Spring MVC

Spring MVC

Spring MVC介绍

  • Spring MVC 是Spring体系的轻量级Web MVC框架
  • Spring MVC的核心Controller控制器, 用于处理请求, 产生响应
  • Spring MVC基于Spring IoC容器运行, 所有对象被IoC管理

Spring 5.x版本变化

  • Spring 5.x最低要求JDK8与J2EE 7(Servlet 3.1/Tomcat 8.5+)
  • Spring 5.x支持JDK8/9, 可以使用新特性
  • Spring 5.x最重要的新特性支持响应式编程

Spring MVC环境配置

  1. Maven依赖spring-webmvc

  2. web.xml配置DispatcherServlet

    <!--  DispatcherServlet是Spring MVC最核心对象, DispatcherServlet用于拦截Http请求, 并根据请求的URL调用
      与之对应的Controller方法, 来完成Http请求的处理-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <!-- 在Web应用启动时自动创建Spring IoC容器, 并初始化DispatcherServlet -->
        <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <!--  "/"代表拦截所有请求      -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
  3. 配置applicationContext的mvc标记

    <context:component-scan base-package="com.zk.springmvc"/>
    <!--  启用Spring MVC的注解开发模式  -->
    <mvc:annotation-driven/>
    <!--  将图片/JS/CSS等静态资源排除在外, 可提高Spring MVC的执行效率  -->
    <mvc:default-servlet-handler/>
    
  4. 开发Controller控制器

Spring MVC数据绑定

URL Mapping

  • URL Mapping指将URL与Controller方法绑定
  • 通过将URL与方法绑定, Spring MVC便可通过Tomcat对外暴露服务

URL Mapping 注解

  • @RequestMapping - 通用绑定
  • @GetMapping - 绑定Get请求
  • @PostMapping - 绑定Post请求

接收请求参数

接收请求参数的常用做法

  • 使用Controller方法参数接受数据
  • 使用Java Bean接收数据

接受复合数据

  1. 直接使用数组
  2. 使用List集合, 要在参数前添加@RequestParam注解
  3. 在实体对象中使用List集合属性
  4. 使用Map时只能接受单个数据, 对于复合数据会出现数据丢失

关联对象赋值

修改表单name属性增加关联对象名作为前缀

日期类型转换

在方法参数前增加@DateTimeFormat(pattern = "yyyy-MM-dd") 或者

增加全局日期类型转换器

  1. 日期转换器类需要实现Converter接口

  2. 配置applicationContext.xml通知Spring MVC有哪些自定义的转换类

    <mvc:annotation-driven conversion-service="conversionService"/>
    
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.zk.springmvc.converter.MyDateConverter"/>
            </set>
        </property>
    </bean>
    

如果既书写了@DateTimeFormat也增加了日期转换器, 在实际运行时以哪个为准呢?

  • Sping MVC的强制要求是一旦增加了对应的日期转换器, 那优先使用转换器类来处理类型转换

解决中文乱码

Web应用的中文乱码由来

  • Tomcat 默认使用字符集ISO-8859-1, 属于西欧字符集
  • 解决乱码的核心思路是将ISO-8859-1转换为UTF-8
  • Controller中请求与响应都需要设置UTF-8字符集

中文乱码的配置

  • Get请求乱码 - 在Tomcat的server.xml增加URIEncoding属性指明UTF-8

    • 在Tomcat 8.0以后版本的URIEncoding属性默认就是UTF-8
  • Post请求乱码 - web.xml配置CharacterEncodingFilter

    <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

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html;charset=utf-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    

响应输出结果

响应中产生结果的两种方式

  • @ResponseBody - 产生响应文本
  • ModelAndView - 利用模板引擎渲染输出
@ResponseBody
  • @ResponseBody注解代表直接产生响应体的数据, 过程不涉及任何视图
  • @ResponseBody可产生标准字符串/JSON/XML等格式数据
  • @ResponseBody所产生的字符串会被StringHttpMessageConverter所影响
ModelAndView对象
  • ModelAndView对象是指"模型(数据)与视图(界面)"对象
  • 通过ModelAndView可将包含数据对象与模板引擎进行绑定
  • Spring MVC中默认的View是JSP, 也可以配置其他模板引擎

ModelAndView对象核心用法

  • mav.addObject()方法设置的属性默认存放在当前请求中
  • 默认ModelAndView使用请求转发(forward)至页面
  • 重定向使用new ModelAndView("redirect:/index.jsp")
// String 与 ModelMap实现类似 ModelAndView 的功能
@GetMapping("/xxx")
public String showView1(Integer userId, ModelMap modelMap) {
    String view = "/um/view.jsp";
    User user = new User();
    if (userId == 1) {
        user.setUsername("lily");
    } else if (userId == 2) {
        user.setUsername("smith");
    }
    modelMap.addAttribute("u", user);
    return view;
}

Spring MVC整合Freemarker

  1. pom.xml引入依赖freemarker spring-context-support

  2. 通知Spring MVC 使用Freemarker模板引擎
    在applicationContext.xml中配置

    <bean id="ViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
        <property name="contentType" value="text/html;charset=utf-8"/>
        <property name="suffix" value=".ftl"/>
    </bean>
    
  3. 配置Freemarker参数

    <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value="/WEB-INF/ftl"/>
        <property name="freemarkerSettings">
            <props>
                <prop key="defaultEncoding">utf-8</prop>
            </props>
        </property>
    </bean>
    

RESTful开发风格

传统Web应用的问题

  • 客户端只能是支持HTML的浏览器
  • 而小程序, app等不支持

REST与RESTful

  • REST - (Representational State Transfer)表现层状态转换, 资源在网络中以某种表现形式进行状态转移
  • RESTful是基于REST理念的一套开发风格, 是具体的开发规则

RESTful传输数据

image-202104251725ss20530

RESTful开发规范

  • 所有的资源都使用URL作为用户交互入口
  • 明确的语义规范(GET | POST | PUT | DELETE)
  • 只返回数据(JSON | XML), 不包含任何展现

RESTful命名要求

URI说明修改建议
GET /articles?au=lily正确用法
GET /a/1URI必须具有语义GET /student/1
POST /createArticle/1URI必须使用名词POST /article/1
GET /articles/author/1URI扁平化, 不超两级GET /articles/author?id=1
DELETE /articles/1URI名词区分单复数GET /articles?au=lily
DELETE /article/1

RestController注解与路径变量

@RestController 代替@Controller注解 说明当前类的所有方法的返回值都是RESTful风格的数据, 而不是页面跳转

路径变量是指存放在URI中可变的那一部分数值

// POST /article/1
// POST /restful/request/100
@PostMapping("/request/{rid}")
public String doPostRequest(@PathVariable("rid") Integer requestId) {
    return "{\"message\":\"数据新建成功\", \"id\":" + requestId + "}";
}

简单请求与非简单请求

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

Spring MVC需要在web.xml中添加以下过滤器, 才支持非简单请求(PUT/DELETE)的请求参数获取

<filter>
    <filter-name>formContentFilter</filter-name>
    <filter-class>org.springframework.web.filter.FormContentFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>formContentFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

JSON序列化

利用Jackson

  1. 引入Maven依赖 jackson-core jackson-databind jackson-annotations

  2. 在方法定义的时候不再返回String, 而是直接返回需要JSON序列化的对象, 在Spring MVC在对外输出响应的时候, 这个对象会被Jackson自动序列化, 然后随着响应一起发送到客户端

  3. 在进行时间输出的时候, 需要在属性上添加@JsonFormat注解, 用于对对象进行格式化输出(日期, 数字, 货币等)

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date birthday;
    

浏览器的跨域访问

浏览器的同源策略
  • 同源策略阻止从一个域加载的脚本去获取另一个域上的资源
  • 只要协议、域名(二级域名)、端口有任何一个不同, 都被当作是不同的域
  • 浏览器Console看到Access-Control-Allow-Origin错误就代表跨域了(触发了浏览器的同源策略), 请求得到的结果并不会被浏览器所处理

HTML中允许跨域的标签

  • <img> - 显示远程图片
  • <script> - 加载远程JS
  • <link> - 加载远程CSS

Spring MVC跨域访问

CORS 跨域资源访问
  • CORS是一种机制, 使用额外的HTTP头通知浏览器可以访问其他域
  • URL响应头包含 Access-Control-* 指明请求允许跨域
Spring MVC解决跨域访问
  • @CrossOrigin - Controller跨域注解(当前Controller所有映射的URL都可以被那些其他域的请求跨域访问)
    @CrossOrigin(origins = {"http://localhost:8080"})
  • <mvc:cors> - Spring MVC全局跨域配置

image-20210426161946391

说明当前的请求需要跨域访问了

image-20210426162131442

当前的响应可以被浏览器所解析

CORS全局配置
<mvc:cors>
    <mvc:mapping path="/restful/**" allowed-origins="http://localhost:8080, https://www.baidu.com"
                 <!-- max-age是预检请求缓存的时间3600为1小时 -->
                 max-age="3600"/>
</mvc:cors>

Spring MVC拦截器

拦截器 - Interceptor

  • 拦截器(Interceptor)用于对URL请求进行前置/后置过滤
  • Interceptor与Filter用途相似, 但实现方式不同
  • Interceptor底层就是基于Spring AOP面向切面编程实现

拦截器开发流程

  • Maven依赖servlet-api

  • 实现HandlerInterceptor接口

  • applicationContext配置过滤地址

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.zk.restful.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    

HandlerInterceptor 接口

  • preHandle - 前置执行处理
  • postHandle - 目标资源已被Spring MVC处理, 但是还没产生响应之前 (后置执行处理)
  • afterCompletion - 产生了响应文本以后
拦截器使用细则

对于资源的过滤和排除

<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/**"/>

或者 通过缩小拦截的范围

<mvc:mapping path="/restful/**"/>
<mvc:mapping path="/restful2/**"/>

多Interceptor执行顺序

image-20210426173128788

开发用户流量拦截器

  • 拦截器产生的用户数据作为日志输出到日志文件上
    配置logback.xml

    <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>/var/log/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.zk.restful.interceptor.AccessHistoryInterceptor" level="INFO" additivity="false">
            <appender-ref ref="accessHistoryLog"/>
        </logger>
    </configuration>
    
  • 开发拦截器

    public class AccessHistoryInterceptor implements HandlerInterceptor {
        private Logger logger = LoggerFactory.getLogger(AccessHistoryInterceptor.class);
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            StringBuilder log = new StringBuilder();
            log.append(request.getRemoteAddr());
            log.append("|");
            log.append(request.getRequestURL());
            log.append("|");
            log.append(request.getHeaders("User-Agent"));
            logger.info(log.toString());
            return true;
        }
    }
    

Spring MVC处理流程

image-2021042619342aa9432

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值