SpringMVC基础-01

1.MVC的概念

  1. MVC即Model-View-Controller。MVC会将一个应用分成三个层:模型层、视图层、控制层,来降低视图和业务逻辑间的双向耦合。
  2. 对于Controller,在SpringMVC中,DispatcherServlet表示前端控制器,通过HandlerMapping和HandlerAdapter来将URL和类进行匹配,同时HandlerInterceptor也可以理解为是一个前端控制器。后端控制器就是自定义的Controller。
  3. Model就是后端自定义的Controller进行一系列处理后返回的数据,一般会封装在ModelAndView、Model或者ModelMap中。
  4. View表示HTML、JSP页面。

2.SpringMVC入门

  1. 导入依赖。
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>
  1. 配置web.xml文件。使用idea自动生成的web.xml版本低,会导致jsp中无法解析数据,需要改变web.xml的头部信息。
    1. DispatcherServlet如果配置为/,会处理所有的请求,但是不会处理.jsp。
    2. DispatcherServlet如果配置为/* 会处理所有的请求,同时也会处理.jsp。
<web-app version="2.5" 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_2_5.xsd">
  <display-name>Archetype Created Web Application</display-name>

  <!-- 所有的请求先经过DispatcherServlet处理 -->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 管理SpringMVC的配置文件 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath*:springmvc.xml</param-value>
    </init-param>
  </servlet>
    
    <!-- / 匹配所有的请求,不包含.jsp;
  /* 匹配所有的请求,包含.jsp-->
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>
  1. 配置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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 处理器映射器,将url映射为具体处理这个url的类 -->
    <bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <!-- 处理器适配器,用于调用处理这个url的类。 -->
    <bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

    <!-- 视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 后缀 -->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 将Controller注入,id为访问路径 -->
    <bean id="/hello" class="com.my.controller.HelloController"/>
</beans>
  1. controller类。
public class HelloController implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("name", "tom");
        // 配置了视图解析器,会解析为/WEB-INF/jsp/hello.jsp
        modelAndView.setViewName("hello");
        return modelAndView;
    }
}

3.SpringMVC执行原理

  1. 用户发送请求后被前端控制器DispatcherServlet接受。
  2. DispatcherServlet收到请求后调用HandlerMapping处理器映射器。
  3. 处理器映射器找到具体的处理器(根据xml配置、注解查找),并生成处理器对象及处理器拦截器(如果有则生成),然后返回给DispatcherServlet。
  4. DispatcherServlet调用HandlerAdapter处理器适配器。
  5. HandlerAdapter经过适配调用具体的处理器,即自定义的后端控制器。
  6. 自定义的后端控制器,即Controller执行完成返回ModelAndView对象给HandlerAdapter。HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
  7. DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
  8. ViewReslover解析后返回具体View。
  9. DispatcherServlet根据View进行渲染视图,即将模型数据填充至视图中。
  10. DispatcherServlet响应用户。

SpringMVC基础-01_spring

4.SpringMVC简化配置

<?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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.my.controller" />
    
    <!-- 注解驱动,相当将注解的处理器映射器和处理器适配器注入容器。 -->
    <mvc:annotation-driven />
    
    <!-- css js等静态资源放行 -->
    <mvc:default-servlet-handler />

    <!-- 视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 后缀 -->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

5.Restful风格

  1. Restful是一种资源定位和资源操作的风格,这个风格设计的软件可以更简洁,更有层次,更易于实现缓存。如http://localhost:8080/user/find?id=1可以变为http://localhost:8080/user/find/1
  2. Restful风格可以使用通过post、delete、put、get请求,来实现对资源的增删改查操作。
  3. 和Restful相关的注解。@PathVariable,获取URL上的参数;@GetMapping、@PostMapping、@PutMapping、@DeleteMapping,请求的方式。

6.转发和重定向

  1. 转发,forward。服务器内部资源跳转,URL不会改变,是SpringMVC方法返回时的默认配置。

  2. 重定向,redirect。可以重定向到服务器外部资源,URL会改变。

  3. 对于forward。return "hello"; 直接进行转发,会经过视图解析器,拼接完整的路径;return "forward:/WEB-INF/jsp/hello.jsp"; 不会经过视图解析器,所以需要写全路径。

  4. 不能redirect到/WEB-INF下的文件中;如果redirect到外部网站,需要写完整的路径(带http),如return "redirect:http://www.baidu.com";

  5. Java代码。

@Controller
@RequestMapping("/hello")
public class HelloController {

    /**
     * forward,转发,默认,url不会变化。
     * return "hello"; 直接进行转发,会经过视图解析器,拼接完整的路径。
     * return "forward:/WEB-INF/jsp/hello.jsp"; 不会经过视图解析器,所以需要写全路径。
     * @param model
     * @return
     */
    @RequestMapping("/h1")
    public String h1(Model model) {
        model.addAttribute("name", "forward,转发,默认,url不会变化");
        return "forward:/WEB-INF/jsp/hello.jsp";
    }

    @RequestMapping("/h2")
    public String h2(Model model) {
        model.addAttribute("name", "redirect,重定向,url地址会变化。");
        return "redirect:/index.jsp";
    }

    /**
     * 不能重定向到/WEB-INF下的文件中
     * @param model
     * @return
     */
    @RequestMapping("/h3")
    public String h3(Model model) {
        model.addAttribute("name", "redirect");
        return "redirect:/WEB-INF/jsp/hello.jsp";
    }

    /**
     * 重定向到外部网站
     * @param model
     * @return
     */
    @RequestMapping("/h4")
    public String h4(Model model) {
        model.addAttribute("name", "redirect");
        return "redirect:http://www.baidu.com";
    }
}

7.请求数据和响应数据

  1. 请求数据的相关注解。@RequestParam,将URL中?后的参数和方法参数进行匹配;@PathVariable,将URL中?前的参数和方法参数进行匹配;@RequestBody,将请求体中的数据封装到方法参数中,方法参数可以为对象,常用;@RequestHeader,将请求头中的数据封装到方法参数中;@RequestAttribute,主要用于jsp中,获取jsp中request.setAttribute("name", "tom");中的值。
  2. 响应的相关注解。@ResponseBody,响应json数据;@RestController=@Controller+@ResponseBody,常用。
  3. 响应数据的方式。可以通过ModelAndView、Model、ModelMap封装数据;也可以直接返回json数据,主要用于前段后分离的场景,常用。
  4. 请求相关Java代码。
@Controller
@RequestMapping("/hello")
public class HelloController {

    /**
     * http://localhost:8080/hello/h1?name=tom
     * 参数名匹配可以直接获取。
     * @param name
     * @return
     */
    @GetMapping("/h1")
    public String h1(String name, Model model) {
        model.addAttribute("name", name);
        return "hello";
    }

    /**
     * http://localhost:8080/hello/h2?username=tom
     * 参数名不匹配可以直接使用 @RequestParam注解,进行匹配。
     * @param name 姓名
     * @return
     */
    @GetMapping("/h2")
    public String h2(@RequestParam("username") String name, Model model) {
        model.addAttribute("name", name);
        return "hello";
    }

    /**
     * http://localhost:8080/hello/h3?id=1&username=tom&age=10
     * 对象会通过传入的参数名和对象的属性进行对应匹配,不同时该属性就为初始化值null。
     * @param user
     * @return
     */
    @GetMapping("/h3")
    public String h3(User user, Model model) {
        model.addAttribute("user", user);
        return "hello";
    }

    /**
     * @RequestBody 获取请求体中的数据,如果请求体中的数据为json格式,
     * 接收参数必须是一个实体类,不能是String、Integer类型。
     * @param user
     * @param model
     * @return
     */
    @GetMapping("/h4")
    public String h4(@RequestBody User user, Model model) {
        model.addAttribute("name", user.getName());
        return "hello";
    }

    /**
     * http://localhost:8080/hello/h5/tom
     * @PathVariable("name") 用于匹配请求路径中的参数
     * @param name
     * @param model
     * @return
     */
    @GetMapping("/h5/{name}")
    public String h5(@PathVariable("name") String name, Model model) {
        model.addAttribute("name", name);
        return "hello";
    }

    /**
     * @RequestHeader("name") 用于匹配请求头中的参数
     * @param name
     * @param model
     * @return
     */
    @GetMapping("/h6")
    public String h6(@RequestHeader("name") String name, Model model) {
        model.addAttribute("name", name);
        return "hello";
    }
}
  1. 响应数据相关Java代码。
@Controller
@RequestMapping("/hello")
public class HelloController {

    /**
     * 
     * @param name
     * @return
     */
    @GetMapping("/h1")
    public String h1(String name, Model model) {
        model.addAttribute("name", name);
        return "hello";
    }

    /**
     * ModelAndView中使用ModelMap作为属性。
     * @param name
     * @param modelAndView
     * @return
     */
    @GetMapping("h2")
    public String h2(String name, ModelAndView modelAndView) {
        modelAndView.addObject("name", name);
        return "hello";
    }

    /**
     * ModelMap是LinkedHashMap的子类,具有Map的方法。modelMap.addAttribute()调用Map的put()方法
     * @param name
     * @param modelMap
     * @return
     */
    @GetMapping("h3")
    public String h4(String name, ModelMap modelMap) {
        modelMap.addAttribute("name", name);
        return "hello";
    }
}