(三)SpringMVC_3

一、什么是拦截器

SpringMVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
常见使用场景
1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间 ;
4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。
5、OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。
在这里插入图片描述
preHandle:
预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器
返回值
true表示继续流程(如调用下一个拦截器或处理器);
false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;

postHandle:
后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。

afterCompletion:
整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。

二、入门案例

2.1注册组件

@Component //注册Interceptor组件
public class CustomInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("hello preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
       modelAndView.setViewName("WEB-INF/jsp/post.jsp");
       System.out.println("hello postHhandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

2.2配置interceptor

<mvc:interceptors>
        <!--使用的是ref或bean标签,全局作用范围-->
        <!--<ref bean="customInterceptor"/>-->
        <!--<bean class="com.qyt.interceptor.CustomInterceptor"/>-->
        <mvc:interceptor>
        <!--interceptor标签内的是局部作用范围-->
            <!--path中填的是url-->
            <!--/hello 只针对hello请求-->
            <!--/hello* 针对helloXXX请求-->
            <!--/hello/ * 针对hello/XXX一级任意目录的请求-->
            <!--/hello/ ** 针对hello/多级任意目录的请求-->
            <mvc:mapping path="/hello/**"/>
            <ref bean="customInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

2.3prehandle返回值为false

执行到prehandle则停止向下执行,执行不到handler和postHandle和afterCompletion

2.4postHandle可以做后处理

可以处理视图,也可以处理json
在这里插入图片描述
如果handler方法上有@RequestBody注解,说明是以json进行相应,那么ModelAndView的值为null。

二、interceptor的作用范围

默认如果使用的是<bean或<ref子标签,作用范围是DispacherServlet的全局
在这里插入图片描述
如果是写在interceptor标签里面的,那么作用范围只针对部分请求。
在这里插入图片描述

三、多个interceptor执行顺序

3.1均为true

执行顺序:先进后出,后进先出

套娃模型、登山模型
123…n
n…321
n…321

3.2出现false

如果为true,向下执行,并且可以执行到对应的afterCompletion
如果为false,则中断流程。

在这里插入图片描述如果preHandle1为true,preHandle2为false,依次执行preHandle1,preHandle2,afterCompletion1。
在这里插入图片描述
如果preHandle1为false,只执行preHandle1。
在这里插入图片描述
如果preHandle1,preHandle2为true,preHandle3为false,依次执行preHandle1,preHandle2,preHandle3,afterCompletio2,afterCompletio3。

执行顺序练习:
5个interceptor:
1245 为true 3为false:123 21
1为false 2345为true :1
1235为true 4为false:1234 321

四、Lcale

地区,语言信息
在SpringMVC中管理Locale,Locale可以作为handler方法中的形参传入,Locale一般放到cookie或者session中管理。
pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.qyt</groupId>
    <artifactId>demo1-locale</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>3.0-alpha-1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.11.1</version>
        </dependency>
    </dependencies>

</project>

application.xml配置文件

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
        <!--通过cookie中的language字段管理Locale-->
        <property name="cookieName" value="language"/>
        <!--默认Locale为en_US,语言使用美式英文-->
        <property name="defaultLocale" value="en_US"/>
    </bean>

HelloController.java

package com.qyt.controller;

import com.qyt.bean.BaseRespVo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Locale;

@RestController
public class HelloController {
    @RequestMapping("hello")
    public BaseRespVo hello(Locale locale){
        return BaseRespVo.ok(locale);
    }
}

BaseRespVo.java

package com.qyt.bean;
import lombok.Data;
/**
 * Vo viewObject
 * @param <T>
 * 这是前后端分离,json数据一个常用的格式
 */
@Data
public class BaseRespVo<T> {
    T data;
    String msg;//告诉前端请求的消息
    long errno;//自己的前后端应用 : 自定义的状态码 → 通常前端根据该状态码做不同的处理

    public static BaseRespVo ok(){
        BaseRespVo<Object> baseRespVo = new BaseRespVo<>();
        baseRespVo.setErrno(0);
        baseRespVo.setMsg("成功");
        return baseRespVo;
    }
    public static BaseRespVo ok(Object data){
        BaseRespVo<Object> baseRespVo = new BaseRespVo<>();
        baseRespVo.setData(data);
        baseRespVo.setErrno(0);
        baseRespVo.setMsg("成功");
        return baseRespVo;
    }
    public static BaseRespVo ok(Object data, String msg){
        BaseRespVo<Object> baseRespVo = new BaseRespVo<>();
        baseRespVo.setData(data);
        baseRespVo.setErrno(0);
        baseRespVo.setMsg(msg);
        return baseRespVo;
    }
    public static BaseRespVo fail(){
        BaseRespVo<Object> baseRespVo = new BaseRespVo<>();
        baseRespVo.setErrno(500);
        baseRespVo.setMsg("失败");
        return baseRespVo;
    }
    public static BaseRespVo fail(String msg){
        BaseRespVo<Object> baseRespVo = new BaseRespVo<>();
        baseRespVo.setErrno(500);
        baseRespVo.setMsg(msg);
        return baseRespVo;
    }
}

在这里插入图片描述
默认是en_US
在这里插入图片描述
在这里插入图片描述
在cookie中将language字段的值修改为zh_CN。

五、MessageSource

5.1注册组件

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <!--加载的配置文件的名字,注意加上classpath-->
        <property name="basename" value="classpath:message"/>
        <!--properties配置文件的编码-->
        <property name="defaultEncoding" value="utf-8"/>
    </bean>

5.2使用messageSource

@Autowired
    @Qualifier("messageSource")
    MessageSource messageSource;

    @RequestMapping("hello/{key}")
    public BaseRespVo hello(@PathVariable("key") String key){
        //第一个参数 → String → 就是配置文件中的key
        String message = messageSource.getMessage(key, null, Locale.getDefault());
        return BaseRespVo.ok(message);
    }

配置文件
在这里插入图片描述
输入key,返回对应的值。
在这里插入图片描述

5.3locale和messageSource结合

同一个key在不同的locale下,value值不同

分别新建四个配置文件,表示不同语言(Locale)的厉害的意思:
en_US(美式英文):awesome → message_en_US.properties
zh_CN(简体中文):牛皮 → message_zh_CN.properties
th_Th(泰文):เก่ง → message_th_TH.properties
ja_JP(日文):すごい → message_ja_JP.properties
→ 这上面4个配置文件的basename就为message

5.3.1组件注册
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <!--加载的配置文件的名字,注意加上classpath-->
        <property name="basename" value="classpath:message"/>
        <!--properties配置文件的编码-->
        <property name="defaultEncoding" value="utf-8"/>
    </bean>

    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
        <property name="defaultLocale" value="zh_CN"/>
        <property name="cookieName" value="language"/>
    </bean>

在这里插入图片描述

5.3.2使用

配置文件信息
tip:复制进来的properties的文件原来是什么编码就还是什么编码。
在这里插入图片描述
HelloController中的代码

@RequestMapping("i18n/{key}")
    public BaseRespVo i18n(@PathVariable("key") String key,Locale locale){
        String message = messageSource.getMessage(key, null, locale);
        return BaseRespVo.ok(message);
    }

在这里插入图片描述
在这里插入图片描述

5.4第二个参数object[ ]

为从配置文件中取出的值做占位符的赋值

在这里插入图片描述
Locale使用默认的zh_CN,运行结果为:
在这里插入图片描述

六、validator

请求参数校验:将校验和模型绑定起来 → 请求参数和javabean中的成员变量绑定起来 → 校验逻辑和javabean中的成员变量绑定起来。

6.1引入依赖

在之前的基础上引入validator的依赖

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.0.Final</version> 
    <!--注意这里validator的版本要比springmvc的版本高一个版本,
    这里的springmvc的版本是5.2.8,所以validator的版本选择6.1.0-->
</dependency>

6.2application.xml配置

<mvc:annotation-driven validator="localValidatorFactoryBean"/>
    <!--规范-->
    <bean id="localValidatorFactoryBean" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <!--具体的实现方式-->
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
    </bean>

在这里插入图片描述
注册完validator组件要让springmvc知道。

6.3代码

使用validator的注解对javabean的成员变量进行验证。

@Data
public class User {
    @NotNull//限定用户名不为空
    @Size(min = 6)//限定用户名最小长度是6
    String username;
    @Size(min = 6,max = 10)//限定密码长度为6-10之间
    String password;
}
@RestController
public class UserController {
    @RequestMapping("login")
    public BaseRespVo login(@Valid User user){
        return BaseRespVo.ok();
    }
}

以输入长度不合法的密码为例,产生如下报错信息:
在这里插入图片描述
tomcat的报错:
Field error in object ‘user’ on field ‘password’: rejected value [1234]; codes [Size.user.password,Size.password,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.password,password]; arguments []; default message [password],10,6]; default message [个数必须在6和10之间]]

说明密码长度必须在6和10之间,这是对字段的验证。

6.4常见注解

常见的注解 (Bean Validation 中内置的 constraint)
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期 Date
@Future 被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
Hibernate Validator 附加的 constraint
@NotBlank(message =) 验证字符串非null,且长度必须大于0
@Email 被注释的元素必须是电子邮箱地址
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内

6.5message

6.5.1自定义错误消息
@Data
public class User {
    @NotNull
    @Size(min = 6, message = "username length min 6")//自定义的错误信息
    String username;
    @Size(min = 6,max = 10, message = "password length between 6 and 10")//自定义的错误信息
    String password;
}
/**
     *
     * @param user
     * @param bindingResult 👉参数校验的结果 → 哪一个参数发生错误了,发生的错误是什么
     * @return
     */
    @RequestMapping("login")
    public BaseRespVo login(@Valid User user, BindingResult bindingResult){
        if (bindingResult.hasFieldErrors()){
            FieldError fieldError = bindingResult.getFieldError();
            String field = fieldError.getField();
            Object rejectedValue = fieldError.getRejectedValue();
            //获取错误信息,如果未自定义输出系统默认的错误信息,如果有自定义,输出自定义错误信息
            String defaultMessage = fieldError.getDefaultMessage();
            String message = "参数" + field + "携带了" + rejectedValue + "没有完成校验:" + defaultMessage;
            return BaseRespVo.fail(message);
        }
        return BaseRespVo.ok();
    }

携带的参数密码长度不合法,收到返回的错误信息。
在这里插入图片描述

6.5.2和messageSource、Locale结合实现国际化的错误消息返回
  • 配置文件注册messageSource、Locale相关组件
<mvc:annotation-driven validator="localValidatorFactoryBean"/>
    <!--规范-->
    <bean id="localValidatorFactoryBean" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <!--具体的实现方式-->
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
        <property name="validationMessageSource" ref="messageSource"/>//注意这里不要忘了配置messageSource
    </bean>

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:message"/>
        <property name="defaultEncoding" value="utf-8"/>
    </bean>

    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
        <property name="cookieName" value="language"/>
        <property name="defaultLocale" value="zh_CN"/>
    </bean>
  • 配置文件(这里以两种语言为例)
    在这里插入图片描述
@Data
public class User {
    @NotNull
    //@Size(min = 6,message = "username length min 6")
    @Size(min = 6,message = "{error.username}")
    String username;
    //@Size(min = 6,max = 10,message = "password length between 6 and 10")
    @Size(min = 6,max = 10,message = "{error.password}")
    String password;
}
 /**
     *
     * @param bindingResult 👉参数校验的结果 → 哪一个参数发生错误了,发生的错误是什么
     */
    @RequestMapping("login")
    public BaseRespVo login(@Valid User user, BindingResult bindingResult){
        if (bindingResult.hasFieldErrors()){
            FieldError fieldError = bindingResult.getFieldError();
            String field = fieldError.getField();
            Object rejectedValue = fieldError.getRejectedValue();
            String defaultMessage = fieldError.getDefaultMessage();
            String message = "参数" + field + "携带了" + rejectedValue + "没有完成校验:" + defaultMessage;
            return BaseRespVo.fail(message);
        }
        return BaseRespVo.ok();
    }

默认的Locale为zh_CN
在这里插入图片描述
修改浏览器cookie中的language字段为en_US,报错信息以英文显示。
在这里插入图片描述

七、Spring和SpringMVC的整合

7.1Spring容器和SpringMVC容器分家

在这里插入图片描述

7.1.1ContextLoaderListener
7.1.2DispatcherServlet加载的是SpringMVC容器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
<!--ContextLoaderListener-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:application.xml</param-value>
    </context-param>
    <!--DispatcherServlet-->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:application-mvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
7.1.3context:component-scan

在这里插入图片描述
application-mvc.xml

<context:component-scan base-package="com.qyt.controller"/>
    <mvc:annotation-driven/>

application.xml

<context:component-scan base-package="com.qyt">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

7.2SpringMVC JavaConfig

在配置类中注册组件,使用JavaConfig替代原来的xml文件:
Spring配置类 → application.xml
SpringMVC配置类 → application-mvc.xml
web.xml → 替代它需要满足加载spring和springmvc的配置类

7.2.1AACDSI

在这里插入图片描述
在这里插入图片描述

7.2.2Spring配置类

在这里插入图片描述
在这里插入图片描述

7.2.3MVC配置类

在这里插入图片描述

7.2.4其他组件注册
  1. CharactrerEncodingFilter
    web.xml → AACDSI
    在这里插入图片描述
  2. 静态资源映射
    <mvc:resources mapping location/>
    在这里插入图片描述
  3. interceptors
<mvc:interceptors>
	<bean或ref标签
	<mvc:interceptor>
		<mvc:mapping path/>
		<ref或bean标签

在这里插入图片描述

  1. multipartResolver
    commons-fileupload(io)
    在这里插入图片描述在这里插入图片描述
  2. localeResolver
    在这里插入图片描述
    在这里插入图片描述
  3. viewResolver
    在这里插入图片描述
  4. validator
    在这里插入图片描述
    在这里插入图片描述
  5. converter
    conversionService
    1、取出
    2、增加上converter
    3、放回容器
    在这里插入图片描述
  6. handlerExceptionResolver
    在这里插入图片描述

八、spring阶段的组件

8.1jdbcTemplate

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.2TransactionManager

在这里插入图片描述

8.3aspectj

导包
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值