Spring MVC

MVC:View(视图)、Controller(控制器)、Model(模型)

Spring MVC的核心Controller控制器(相当于中介),用于处理请求,产生响应。

Spring MVC基于Spring IOC容器运行,所有对象陂IOC管理。

  • Spring MVC环境配置

    1. Maven依赖spring-webmvc

    2. web.xml配置DispatcherServlet

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      <!-- DispatchServlet -->
      <servlet>
      <servlet-name>springmvc</servlet-name>
      <!--
      Dispatcherservlet是spring MVC最核心的对象
      Dispatcherservlet用于拦截Http请求,并根据请求的URL调用与之对应的Controller方法,来完成Http请求的处理
      -->
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <!--applicationContext.xml-->
      <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:applicationContext.xml</param-value>
      </init-param>
      <!-- 在web应用启动时自动创建Spring IOC容器并初始化DispatchServlet -->
      <load-on-startup>0</load-on-startup>
      </servlet>

      <servlet-mapping>
      <servlet-name>springmvc</servlet-name>
      <!--"/”代表拦截所有请求-->
      <url-pattern>/</url-pattern>
      </servlet-mapping>

    3. 配置applicationContext的mvc标记

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      <!--
      context:component-scan 标签作用
      在Spring Ioc初始化过程中,自动创建并管理com.codewhale及子包中拥有以下注解的对象.
      @Repository
      @Service
      @Controller
      @Component
      -->
      <context:component-scan base-package="com.codewhale"></context:component-scan>
      <!--启用Spring Mvc的注解开发模式-->
      <mvc:annotation-driven/>
      <!--将图片/JS/CSS等静态资源排除在外,可提高执行效率-->
      <mvc:default-servlet-handler/>
    4. 开发Controller控制器

      1
      2
      3
      4
      5
      6
      7
      8
      @Controller
      public class TestController{
      @GetMapping("/t") // 通过localhost/t访问
      @ResponseBody //直接向响应输出字符串数据,不跳转页面
      public String Test(){
      return "Yes!";
      }
      }
  • Spring MVC数据绑定

    • URLMapping(URL映射)

      URL Mapping指将URL与Controller方法绑定

      通过将URL与方法绑定,SpringMVC便可通过Tomcat对外暴露服务

      • URL Mapping注解

        1. @RequestMapping - 通用绑定:一般加到类上,作为通用。加到方法上,则不再区分get/post请求
        2. @GetMapping - 绑定Get请求
        3. @PostMapping - 绑定Post请求
    • Controller方法参数接收

      • 接收请求参数的常用做法

        1. 使用Controller方法参数接收

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          <form action="/m1" method="post">
          <input name="username"/>
          <input name="password"/>
          </form>

          -----------------------------------------------------------------

          @PostMapping("/m1")
          @ResponseBody
          public String postMapping(String username , Long password){
          return username + ":" + password;
          }
          @GetMapping("/m2")
          @ResponseBody
          //@RequestParam 参数映射
          public String postMapping(@RequestParam("manager_name") String managerName){
          return managerName;
          }
        2. 使用Java Bean接收数据

          1
          2
          3
          4
          5
          @PostMapping("/p1")
          @ResponseBody
          public String postMapping(User user){
          return user.getUsername() + ":" + user.getPassword;
          }
        3. 可以通过Map或者List集合对复合数据进行接收,但是Map只能接收单一数据,想要接收复合数据(如复选框数据)则需要使用List集合进行接收。

    • 关联对象赋值

      复杂表单

      1
      2
      3
      4
      5
      6
      用户名:<input name="username">
      密码: <input name="password">

      姓名:<input name="idcard.name">
      身份证:<input name="idcard.idno">
      过期时间:<input name="idcard.expire">
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      // IdCard类
      public class IdCard{
      private String name;
      private String dino;
      private String exprire;
      // 以下set/get方法省略....
      }

      // From表单类
      public class From{
      private String username;
      private String password;
      private IdCard idcard = new IdCard();
      // 以下set/get方法省略....
      }
    • 日期类型转换

      使用@DateTimeFormat注解对日期参数进行格式化。

      1
      @DateTimeFormat(pattern = "yyyy-MM-dd")
      • 全局默认日期转换

        创建一个转换器类进行转换。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        public class MyDateConverter implements Converter<String, Date> {
        public Date convert(String s){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
        Date d = sdf.parse(s);
        return d;
        } catch(ParseException e) {
        return null;
        }
        }
        }
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        <!-- applicationContext.xml配置文件中配置转换器类 -->
        <mvc:annotation-driven conversion-service="conversionService">

        <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
        <set>
        <bean class="com.codewhale.converter.MyDateConverter"/>
        </set>
        </property>
        </bean>
    • Web应用中文乱码问题解决

      Tomcat默认使用字符集ISO-8895-1,属于西欧字符集,所以中文会出现乱码问题,只需要将该字符集转换成UTF-8即可解决。

      Controller中请求和响应都需要设置UTF-8字符集。

      • Get请求乱码 - 在Tomcat配置文件(server.xml)中的增加URlEncoding属性,Tomcat 8.0版本之后默认使用UTF-8。

      • Post请求乱码 - web.xml配置CharacterEncodingFilter

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        <!-- web.xml配置文件中配置filter -->
        <filter>
        <filter-name>characterFilter</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>characterFilter</filter-name>
        <url-pattern>/*</url-pattern>
        </filter-mapping>
      • Response响应乱码 - Spring配置StringHttpMessageConverter

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        <!-- applicationContext.xml配置文件中配置 -->
        <mvc:annotation-driven conversion-service="conversionService">
        <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
        <property name="supportedMediaTypes">
        <list>
        <!-- response.setContentType("text/html;charset=utf-8") -->
        <value>text/html;charset=utf-8</value>
        </list>
        </property>
        </bean>
        </mvc:message-converters>
        </mvc:annotation-driven>
    • 响应输出结果

      • @ResponseBody - 产生响应文本

        1. @ResponseBody直接产生响应体的数据,过程不涉及任何视图
        2. @ResponseBody可产生标准字符串/JSON/XML等格式数据
        3. @ResponseBody被StringHttpMessageConverter所影响
      • ModelAndView - 利用模板引擎渲染输出

        1. ModelAndView对象是指”模型(数据)与视图(界面)”对象

        2. 通过ModelAndView可将包含数据对象与模板引擎进行绑定

        3. SpringMVC中默认的View是JSP,也可以配置其他模板引擎

          1
          2
          3
          4
          5
          6
          7
          8
          @GetMapping("/text")
          public ModelAndView showView(Integer id) {
          ModelAndView mav = new ModelAndView("/text.jsp");
          User user = new User();
          user.setId(id);
          mav.addObject("u", user)
          return mav;
          }

          text.jsp代码:

          1
          <h1>${u.id}</h1>
      • ModelAndView核心

        1. mav.addObject()方法设置的属性默认存放在当前请求中

        2. 默认ModelAndView使用请求转发(forward)至页面

        3. 重定向使用 new ModelAndView(“redirect:/index.jsp”)

          重定向和请求转发的区别,数据关联不大时使用重定向(例如注册页面注册成功跳转到首页时)。

          相对路径:text.jsp

          绝对路径(推荐):/text.jsp

        4. String与ModelMap

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          //Controller方法返网string的情况
          //1.方法被@ResponseBody描述,SpringMvc直按响应String字符串本身
          //2.方法不存在@Responsedody,则SpringMVc处理String指代的视图(页面)
          public String showView(Integer id, ModelMap modelMap){
          String view = "/test/test.jsp";
          User user = new User();
          user.setId(id);
          modelMap.addAttribute("u", user);
          return view;
          }
    • SpringMVC整合Freemarker

      1. pom.xml中引入依赖

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        <dependency>
        <groupld>org.freemarker</groupld>
        <artifactld>freemarker</artifactld>
        <version>2.3.28</version>
        </dependency>
        <dependency>
        <groupld>org.springframework</groupld>
        <artifactld>spring-context-support</artifactld>
        <version>5.1.9.RELEASE</version>
        </dependency>
      2. 启用Freemarker模板引擎

        1
        2
        3
        4
        5
        6
        <bean id="ViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
        <!--设置响应输出,并解决中文乱码 -->
        <property name="contentType" value="text/html;charset=utf-8"></property>
        <!--指定Freemarker模板文件扩展名 -->
        <property name="suffix" value=".ftl"/>
        </bean>
      3. 配置Freemarker参数

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <!--设置模板保存的目录-->
        <property name="templateLoaderPath" value="/WEB-INF/ftl"/>
        <!--其他模板引擎设置-->
        <property name="freemarkerSettings">
        <props>
        <!--设置Freemarker脚本与数据渲染时使用的字符集-->
        <prop key="defaultEncoding">UTF-8</prop>
        </props>
        </property>
        </bean>
    • RESTful开发风格

      • 开发规范

        1. 使用URL作为用户交互入口
        2. 明确的语义规范(GET | POST | PUT | DELETE)
        3. 只返回数据(JSON | XML),不包含任何展现
      • RestController注解

        该注解可以代替方法上的@Response注解,简化开发。

      • 路径变量

        1
        2
        3
        4
        5
        // Get /test/1
        @GetMapping("/test/{id}")
        public String doGetRequest(@PathVariable("id") Integer id){
        return id;
        }
      • 简单请求与非简单请求

        简单请求是指标准结构的HTTP请求,对应GET/POST请求
        非简单请求是复杂要求的HTTP请求,指PUT/DELETE、扩展标准请求
        两者最大区别是非简单请求发送前需要发送预检请求

      • JSON序列化

        Jackson用于JSON序列化。引入依赖后自动开启无需配置。

        使用时需同时导入jackson-corejackson-databindjackson-annotations三个依赖。

        对于日期类型的数据,需要对该类型进行格式化。

        1
        2
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private Date birthday;
    • 跨域资源访问问题(CORS)

      CORS是一种机制,使用额外的HTTP头通知浏览器可以访问其他域
      URL响应头包含 Access-Control-*指明请求允许跨域

      • SpringMVC解决跨域访问

        1. @CrossOrigin - Controller跨域注解

          1
          2
          // maxAge参数:预检请求进行缓存,减轻服务器压力,因为每一个非简单请求会发送两个请求(一个预检请求,一个实际请求)
          @CrossOrigin(origins = {"http://XXX:8080"}, maxAge = 1000)
        2. <mvc:cors> - Spring MVC全局跨域配置

          1
          2
          3
          4
          5
          6
          7
          <mvc:cors>
          <mvc:mapping path="/**"
          allowed-origins="http://example.com"
          allowed-methods="GET, POST, PUT, DELETE"
          allowed-headers="*"
          allow-credentials="true"/>
          </mvc:cors>
    • Spring MVC拦截器

      拦截器(lnterceptor)用于对URL请求进行前置/后置过滤
      Interceptor与Filter用途相似,但实现方式不同

      Interceptor底层就是基于Spring AOP面向切面编程实现

      • 拦截器开发流程

        1. Maven依赖servlet-api

          1
          2
          3
          4
          5
          6
          7
          <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <!-- 只在开发编译时引用,不和打包后的冲突 -->
          <scope>provided</scope>
          </dependency>
        2. 实现HandlerInterceptor接口

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          public class MyInterceptor implements HandlerInterceptor {
          @Override
          public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
          System.out.println(request.getRequestURL() + "-准备执行");
          return true;
          }

          @Override
          public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
          System.out.println(request.getRequestURL() + "-目标处理成功");
          }

          @Override
          public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
          System.out.println(request.getRequestURL() + "-相应内容已产生");
          }
          }

          HandlerInterceptor接口:

          • preHandle - 前置执行处理
          • postHandle - 目标资源已被Spring MVC框架处理
          • afterCompletion - 响应文本已经产生
        3. applicationContext.xml中配置过滤地址

          1
          2
          3
          4
          5
          6
          <mvc:interceptors>
          <mvc:interceptor>
          <mvc:mapping path="/**"/>
          <bean class="com.codewhale.interceptor.MyInterceptor"/>
          </mvc:interceptor>
          </mvc:interceptors>
        4. 排除某些资源拦截(如ico、jpg、gif、js等)

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          <mvc:interceptors>
          <mvc:interceptor>
          <mvc:mapping path="/**"/>
          <mvc:exclude-mapping path="/**.ico"/>
          <mvc:exclude-mapping path="/**.jpg"/>
          <mvc:exclude-mapping path="/**.gif"/>
          <mvc:exclude-mapping path="/**.js"/>
          <mvc:exclude-mapping path="/**.css"/>
          <!-- 将该目录下所有资源进行排除 -->
          <mvc:exclude-mapping path="/resources/**"/>
          <bean class="com.codewhale.interceptor.MyInterceptor"/>
          </mvc:interceptor>
          </mvc:interceptors>
      • 应用:”用户流量“拦截器

        电商:可通过拦截器获取到用户信息,针对某个产品的受众进行分析等等。

      • LogBack配置

        • logback.xml配置

          additivity参数:设为false,则只在配置的指定文件中输出,反之则会向控制台中也输出一份。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          <configuration>
          <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
          <encoder>
          <pattern>[%thread] %d %level %logger{10} - %msg%n</pattern>
          </encoder>
          </appender>
          <appender name="accessHistoryLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <fileNamePattern>d:/logs/history.%d.log</fileNamePattern>
          </rollingPolicy>
          <encoder>
          <pattern>[%thread] %d %level %logger{10} - %msg%n</pattern>
          </encoder>
          </appender>
          <root level="debug">
          <appender-ref ref="console"/>
          </root>
          <logger name="com.codewhale.interceptor.MyInterceptor" level="INFO" additivity="false">
          <appender-ref ref="accessHistoryLog"/>
          </logger>
          </configuration>
        • logback使用

          1
          2
          private Logger logger = LoggerFactory.getLogger(此类名称.class);
          logger.info("信息");
      • Spring MVC处理流程

        ![Spring MVC处理流程](/res/Spring MVC处理流程.png)