JavaSE

SpringMVC

2021-05-19  本文已影响0人  AIGame孑小白

什么是MVC?

Model View Controller

SpringMVC

简而言之:SpringMVC是用来处理http请求的。

重要组件:

  • DispatcherServlet:前端控制器,接受所有请求(@WebServlet配置为’/‘时不包含jsp)
  • HandlerMapping:解析请求格式(判断希望执行那个具体的方法)
  • HandlerAdapter:负责调用具体的方法
  • ViewResovler:视图解析器,跳转到具体的视图文件

第一个SpringMVC项目

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <servlet>
        <servlet-name>springmvc123</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
        <!-- 修改配置文件路径和名称 -->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc123</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <bean id="demo123" class="mvc01.DemoController"></bean>
    <!-- 用来解析请求 -->
    <bean  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <!-- 需要对urlMap设值注入 -->
        <property name="urlMap">
            <map>
                <!-- key指的是解析出来控制器逻辑名 
                value:往哪个控制器走...<bean>
                -->
                <entry key="demo" value-ref="demo123"></entry>
            </map>
        </property>
    </bean>
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
    <!-- 配置一个视图解析器,自动补充前缀和后缀 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

编写控制器

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class DemoController implements Controller{
    @Override
    public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
        System.out.println("执行了SpringMVC的控制器");
        ModelAndView modelAndView = new ModelAndView("index");
        return modelAndView;
    }
}

看到这一行代码:返回一个ModelAndView可以直接跳转转发到对应的界面,参数就是页面路径。

ModelAndView modelAndView = new ModelAndView("index");
return modelAndView;

由于我们做了如下配置:

<!-- 配置一个视图解析器,自动补充前缀和后缀 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>

所以在 new ModelAndView 的时候填写“index”即可。

注解方式环境搭建

配置mvc

<mvc:annotation-driven></mvc:annotation-driven>

这个注解实际上就包含了HandlerMapping的实现类:DefaultAnnotationHandlerMapping,不仅如此还配置了一个AnnotationMethodHandlerAdapter,也就是说:配置这一个标签,就相当于配置了这两个类。(包:org.springframe.web.servlet.mvc.annotation)

编写Controller

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class DemoController {
    @RequestMapping("demo")
    public String demo(){
        System.out.println("执行demo");
        return "main.jsp";
    }
}

取消静态资源的拦截

但是静态资源也会被拦截,我们可以告诉mvc哪些资源是静态资源,不需要拦截:

<!-- 告诉mvc哪些资源是静态的,不要拦截 -->
<mvc:resources location="" mapping="/js/**"></mvc:resources>

表示:WebContent下面js文件夹下的所有文件

mapping="/js/*"

表示:WebConten下面js文件夹下的所有子文件以及子目录

mapping="/js/**"

所以一般配置都是两个"*"号

location="/WEB-INF/"

指的是在WEB-INF目录下面。

基本类型或对象参数

还是先配置web.xml

<servlet>
    <servlet-name>springmvc123</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
    <!-- 修改配置文件路径和名称 -->
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc123</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!-- 字符编码过滤器 -->
<filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
       <param-name>encoding</param-name>
       <param-value>utf-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

上面已经配置了字符集的过滤器。

springmvc.xml

<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        ">
    <!-- 扫描包 -->
    <context:component-scan base-package="cn.jxb"></context:component-scan>
    <!-- 注解驱动 -->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

创建一个People的类,写好getXXX()setXXX()方法。

public class People {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

编写Controller

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class DemoController {
    @RequestMapping("demo")
    public String demo(People p){
        System.out.println("执行demo,名称:"+p.getName()+",年龄:"+p.getAge());
        return "main.jsp";
    }
}

我们在demo方法中的参数由Spring自动帮我们传递,除了这些我们需要的参数以外,Servlet原生的所有相关类,基本都可以拿来使用,例如:

public String demo(ServletRequest request,HttpSession session){
    System.out.println("Request:"+request+",Session:"+session);
    return "main.jsp";
}

假如前端页面传过来的参数名称为"name1,age1",我们如果不想使用前端的名称,此时我们可以自己配置注解:

<form action="demo" method="post">
名称:<input type="text" name="name1"/>
年龄:<input type="text" name="age1"/>
<input type="submit" value="点击提交"/>
</form>

这样编写Controller:

public String demo(@RequestParam("name1") String name,@RequestParam("age1") int age){
    System.out.println("执行demo,名称:"+name+",年龄:"+age);
    return "main.jsp";
}

该注解还有个功能就是增加默认值:

@RequestParam(defaultValue="name1")

比如我们在做分页的时候,就可以直接这样写入默认值,避免了大量的if判断。

@RequestParam(required=true)

假如这里设置为treu则表示必须要传入该参数!假如我们需要一个sql的条件语句,则可以使用这个强制要求必须传入参数,否则就报错(页面505)。

复杂参数

假如我们需要接收一个这样的复杂对象:

<form action="demo" method="post">
名称:<input type="text" name="name"/>
年龄:<input type="text" name="age"/>
<input type="checkbox" name="hover" value="吃饭" />
<input type="checkbox" name="hover" value="睡觉" />
<input type="checkbox" name="hover" value="打游戏" />
<input type="submit" value="点击提交"/>
</form>

那么我们必须要这样配置:

@Controller
public class DemoController {
    @RequestMapping("demo")
    public String demo(String name,int age,@RequestParam("hover")List<String> ho){
        System.out.println("执行demo,名称:"+name+",年龄:"+age+"集合:"+ho);
        return "main.jsp";
    }
}

那么假如我们请求的参数是这样的:

<form action="demo" method="post">
名称:<input type="text" name="peo.name"/>
年龄:<input type="text" name="peo.age"/>
<input type="submit" value="点击提交"/>
</form>

现在我们的参数名称改变为了"peo.name"这样的参数,那么我们如何接收呢?

首先我们已经拥有了People类:

public class People {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

然后我们可以创建一个Demo类,来装载peo对象:

public class Demo {
    private People peo;

    public People getPeo() {
        return peo;
    }
    public void setPeo(People peo) {
        this.peo = peo;
    }
}

然后我们这样配置Cotroller:

@Controller
public class DemoController {
    @RequestMapping("demo")
    public String demo(Demo demo){
        System.out.println(demo);
        return "main.jsp";
    }
}

基于上面的拓展,假如我们的参数变成这样:

<form action="demo" method="post">
名称:<input type="text" name="peo[0].name"/>
年龄:<input type="text" name="peo[0].age"/>
<br>
名称:<input type="text" name="peo[1].name"/>
年龄:<input type="text" name="peo[1].age"/>
<br>
<input type="submit" value="点击提交"/>
</form>

那么我们只需要对Demo类进行修改即可:

public class Demo {
    private List<People> peo;
    @Override
    public String toString() {
        return "Demo [peo=" + peo + "]";
    }
    public List<People> getPeo() {
        return peo;
    }
    public void setPeo(List<People> peo) {
        this.peo = peo;
    }
}

restful风格参数

<a href="demo/张三/13">点击我啊</a>
@RequestMapping("demo/{peopleName}/{peopleAge}")
public String demo(@PathVariable("peopleName")String name,@PathVariable("peopleAge")int age){
    System.out.println(name+":"+age);
    return "/main.jsp";
}

跳转方式

我们默认的请求方式是请求转发,如果想使用重定向可以在return的参数中添加"redirect:"例如:

return "redirect:/main.jsp";

如果需要使用转发(默认的,不用配置)添加"forward:资源路径"

自定义视图解析器

SpringMVC为我们配置了默认的视图解析器。不过我们可以自己在springmvc.xml中配置:

<!-- 自定义视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>

然后我们就可以在Controller中简单的转发到main.jsp:

@RequestMapping("demo/{peopleName}/{peopleAge}")
public String demo(@PathVariable("peopleName")String name,@PathVariable("peopleAge")int age){
    System.out.println(name+":"+age);
    return "main";
}

转发到第二个控制器

@RequestMapping("demo")
public String demo(){
    System.out.println("转发到ok控制器");
    return "forward:ok";
}
@RequestMapping("ok")
public String ok(){
    System.out.println("转发到我这里啦");
    return "main";
}

当我们在浏览器中输入"demo"回车后,会自动转发到"ok"控制器上,然后"ok"控制器会访问"/main.jsp"这段参数是在springmvc.xml中< bean>中配置的前后缀名称。

@ResponseBody

我们之前使用Servlet实现向页面打印数据:

@Controller
public class DemoController {
    @RequestMapping("demo")
    public void demo(HttpServletResponse response) throws IOException{
        PrintWriter writer =  response.getWriter();
        writer.append("OKKKKK");
        writer.flush();
        writer.close();
    }
}

现在我们要是想输出数据:

@Controller
public class DemoController {
    @RequestMapping("demo")
    @ResponseBody
    public People demo(){
        People people = new People();
        people.setName("张三");
        people.setAge(13);
        return people;
    }
}

注意:@ResponseBody这个注解底层使用了jackson解析对象,将对象解析成json字符串打印到网页上面,所以需要导入相关jar包。

{"name":"张三","age":13}

通过@RequestMapping参数,produces="text/html;charset=utf-8":可以配置响应头(Content-Type)信息,进而解决中文乱码的问题:

@RequestMapping(value="demo",produces="text/html;charset=utf-8")
@ResponseBody
public String demo(){
    return "我是中文";
}

SpringMVC基本运行原理

如果在web.xml 中设置DispatcherServlet 的< url-pattern>为/时,当用户发起请求, 请求一个控制器, 首先会执行 DispatcherServlet. 由DispatcherServlet调用HandlerMapping的DefaultAnnotationHandlerMapping 解 析 URL, 解 析 后 调 用HandlerAdatper 组 件 的AnnotationMethodHandlerAdapter 调 用Controller 中的 HandlerMethod.当 HandlerMethod 执行完成后会返回View,会被 ViewResovler 进行视图解析,解析后调用 jsp 对应的.class 文件并运行,最终把运行.class 文件的结果响应给客户端

上一篇下一篇

猜你喜欢

热点阅读