首页 > 其他分享 >SpringMVC03_校验和拦截器

SpringMVC03_校验和拦截器

时间:2023-05-04 10:55:48浏览次数:56  
标签:SpringMVC03 拦截器 return 校验 注释 message 异常 public

以下代码全过程在上篇

一、SpringMVC 校验

​ 举一个简单的例子,在登陆时我们要检验用户名是否输入、密码是否合法。

(一)引入依赖框架

​ 在 Spring-MVC 中我们需要添加 Hibernate 的 Validator 检验框架,注意下面的版本号,615Final 对应的应该是 import javax.validation.constraints.NotNull 这个类,之前使用了 8.0.0 Final 结果找不到类。

Error creating bean with name 'bookController': Unsatisfied dependency expressed through field 'bookService'; nested exception is org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.validation.beanvalidation.LocalValidatorFactoryBean] for bean with name 'validator' defined in class path resource [spring-mvc.xml]: problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: javax/validation/ValidatorFactory
<!-- 引入 hibernate-validator 的校验-->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.5.Final</version>
</dependency>

(二)配置开启校验器

​ 此外还需要配置检验器和对应的消息资源,并在 mvc:annotation-driven 中启动校验器。

	<!-- 配置注解方式的映射器、适配器 -->
    <mvc:annotation-driven validator="validator"/>

	<!-- 配置服务端校验器 -->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
        <!-- 配置校验使用的资源文件 -->
        <property name="validationMessageSource" ref="messageSource"/>
    </bean>
    <!-- 配置消息资源类 -->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basenames">
            <!-- 配置 list 集合,用于指定要加载的 properties 属性文件 -->
            <list>
                <value>classpath:errorMessage</value>
            </list>
        </property>
        <property name="fileEncodings" value="UTF-8" />
        <property name="cacheSeconds" value="120"/>
    </bean>

​ 所对应的 errMessage 写成配置文件

user.userName.isNull = userName = null
user.password.isNull = password = null

(三)添加校验规则

​ 对于需要验证的 model 加上验证规则,在这里使用的是 NotNull

package com.ls.bookmanager.model;
@Data
@Accessors(chain = true)
public class User {
    @NotNull(message = "{user.userName.isNull}")
    private String userName;
    @NotNull(message = "{user.passwor.isNull}")
    private String password;
}

(四)获取校验信息

​ 如果想获取校验器抛出的错误信息,需要在 Controller 层的处理方法中加入@Validated 注解,注解定义要进行 校验的 pojo 前面,同时需要在 pojo 后面定义 BindingResult 参数。错误消息就是通过 BindingResult 参数进行获取。校验注解@Validated 和 BindingResult bindingResult 是配对出现,并且形参顺序是固定的,一前一后。

package com.ls.bookmanager.controller;
@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/logIn.action")
    @ResponseBody
    public Map logIn(@Validated User user, BindingResult errResult) {
        System.out.println(user);
        Map<String, Object> result = new HashMap<>();
        if (errResult.hasErrors()) {
            List<ObjectError> allErrors = errResult.getAllErrors();
            List<String> mesgList = new ArrayList<>();
            for (ObjectError error : allErrors) {
                mesgList.add(error.getDefaultMessage());
            }
            result.put("error", mesgList);
            return result;
        }
        result.put("message", "success");
        result.put("code", 200);
        return result;
    }
}

(五)模拟传参

​ 还是使用 Postman 模拟传给 username 和 password

image-20230503162141615

(六)检验规则

​ @Null 被注释的元素必须为 null

​ @NotNull 被注释的元素必须不为 null

​ @AssertTrue 被注释的元素必须为 true

​ @AssertFalse 被注释的元素必须为 false

​ @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值

​ @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值

​ @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值

​ @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@Size(max=, min=) 被注释的元素的大小必须在指定的范围内 

​ @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内

​ @Past 被注释的元素必须是一个过去的日期

​ @Future 被注释的元素必须是一个将来的日期

​ @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式

​ @NotBlank(message =) 验证字符串非 null,且长度必须大于

​ @Email 被注释的元素必须是电子邮箱地址

​ @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内

​ @NotEmpty 被注释的字符串的不能为非空

​ @Range(min=,max=,message=) 被注释的元素必须在合适的范围内

二、MVC 异常处理

​ SpringMVC 在处理请求过程中,如果出现异常信息则应该交由异常处理器进行处理。自定义异常处理器可以实现一个统一的异常处理逻辑。

​ 在 Java 应用中异常包括两类:预期异常和运行时异常 RuntimeException。前者主要通过捕获异常 try..catch 从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。

​ 尽管在项目开发完成后,需要进行大量的测试,但仍会存在一些不可预知的错误异常。即使这种错误异常非常少 了,但仍不能保证异常一点也不存在,所以针对这种情况,我们就需要由一个统一异常处理机制,来针这种情况(突 发异常)进行处理,这就是自定义异常处理机制存在意义。 系统的 dao、service、controller 出现的异常都通过 throws Exception 这种方式向上抛出,最后由 SpringMVC 前端控制器交由异常处理器进行异常处理,如下图:

image-20230503191315345

​ 我们通过自定义异常和异常处理类进行实践:

package com.ls.bookmanager.exception;

public class CustomException extends Exception {
    private static final long serialVersionUID = 1L;
    private String message;

    public CustomException(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
//——————————————————————————————————————————————————————————————————————————————————————————————
package com.ls.bookmanager.exception;
public class CustomExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView mav = new ModelAndView();
        CustomException exception = null;
        if (ex instanceof CustomException) {
            exception = (CustomException) ex;
        } else {
            exception = new CustomException("未知异常:" + ex.getMessage());
        }
        String message = exception.getMessage();
        mav.addObject("errorMesg", message);
        mav.setViewName("/error/error");
        return mav;
    }
}

​ 使用上文的 logIn.action 来主动触发一个 By Zero 的异常,在 jsp 下面新建 /error/error.jsp 接收错误信息。

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    异常信息:${errorMesg}
</body>
</html>

image-20230503210741398

image-20230503210806908

三、RESTFUL 支持

​ RESTful 架构,是目前比较流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。 RESTful(即 Representational State Transfer 的缩写)其实是一个开发理念,是对 http 的很好的诠释。 Representational State Transfer 的含义就是“表现层的状态转化”。

(一)资源

​ 要让一个资源可以被识别,需要有个唯一标识,在Web中这个唯一标识就是URI(Uniform Resource Identifier)。URI既可以看成是资源的地址,也可以看成是资源的名称。如果某些信息没有使用URI来表示,那它就不能算是一个资源, 只能算是资源的一些信息而已。URI的设计应该遵循可寻址性原则,具有自描述性,需要在形式上给人以直觉上的关联。

(二)统一资源接口和状态转化

​ RESTful架构应该遵循统一接口原则,统一接口包含了一组受限的预定义的操作,不论什么样的资源,都是通过使用相同的接口进行资源的访问。接口应该使用标准的HTTP方法如GET,PUT和POST,并遵循这些方法的语义。 HTTP 协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端 要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer),而这种转化是建立表现层之上的,所以就是“表现层状态转化”。 客户端能用到的手段就是 HTTP 协议里面,四个表示操作方式的动词:GET(用来获取资源)、 POST( 用来新建资源)、PUT(用来更新资源)、DELETE(用来删除资源)。

(三)RESTful 规范

​ 使用 RESTful 这种架构理念就需要对 http 请求进行一系列的规范。

​ 1.对 url 规范,写成 RESTful 的格式的 url

​ 非 REST 的 url:http://..../queryitem.action?id=001&itemType=01

​ REST 风格的 url:http://..../queryitem/001/01

​ 特点:url 简洁,将参数通过 url 传到服务端

​ 2.http 的方法规范 不管是删除、添加、更新、使用 url 是一致的,如果进行删除,需要设置 http 的方法为 delete,同理添加 后台 controller 方法:判断 http 方法,如果是 delete 执行删除,如果是 post 执行添加。

​ 3.对 http 的 contentType 规范 请求时指定 contentType,如果是 json 数据,设置成 json 格式的 type。

(四)RESTful 实例

​ 在 UserController 中添加,可见下面所对应的 URL 地址是一样的,但是允许的访问方式不同,我们通过 Posmman 模拟不同的访问方式访问同一个页面。

@PostMapping("/do.action")
@ResponseBody
public Map doSomeThing1(int id){
    System.out.println("添加");
    return getResult();
}

@DeleteMapping("/do.action")
@ResponseBody
public Map doSomeThing2(int id){
    System.out.println("删除");
    return getResult();
}

@PutMapping("/do.action")
@ResponseBody
public Map doSomeThing3(int id){
    System.out.println("修改");
    return getResult();
}

@GetMapping("/do.action")
@ResponseBody
public Map doSomeThing4(int id){
    System.out.println("查询");
    return getResult();
}

private Map getResult() {
    Map<String,Object> result = new HashMap<>();
    result.put("message","success");
    result.put("code",200);
    return result;
}

image-20230503213143089

image-20230503213231040

四、MVC 拦截器

(一)拦截器配置

​ SpringMVC 的拦截器 Interceptor 类似于 JSP/Servlet 中的 Filter 过滤器,可以对处理器进行预处理和后处理操作。Filter 过滤器可以过滤所有的请求,而 MVC 拦截器智能拦截处理器请求。

​ 在 SpringMVC 中提供了一个 HandlerInterceptor 接口,实现了该接口的实现类即为 SpringMVC 的拦截器。

调用顺序和是否执行:

1.preHandle 方法按拦截器的配置顺序调用

2.postHandler 方法按拦截器的配置顺序逆向调用

3.afterCompletion 方法按拦截器的配置顺序逆向调用

4.postHandler 方法在拦截器链内的所有拦截器返回为 true 才调用。

5.afterCompletion 方法在拦截器的 preHandle 方法返回为 true 才调用。

package com.ls.bookmanager.interceptor;
public class MyInterceptor implements HandlerInterceptor {
/**
     * Handler 执行前调用此方法,返回 true 表示放行,返回 false 表示拦截
     * 可以在此方法中进行登录验证,权限拦截等操作
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle.....");
        return true;
    }

    /**
     * Handler 执行后,返回 ModelAndView 前执行此方法,可以对返回的逻辑视图
     * 进行加工处理,将公共信息加入到模型中,方便页面展示数据
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle.....");
    }

    /**
     * Handler 执行后,视图返回后调用此方法,在此方法中可以获取 Handler 执行
     * 时抛出的异常信息,因此可以执行日志操作,资源清理等
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion.....");
    }
}

​ 下面是基于 MVC 处理过程中对拦截器执行位置的标注

image-20230504103533255

​ 写好之后必然要在 spring-mvc.xml 中配置拦截器,一般是针对所有 mapping 映射配置拦截器,即下面这种方式。

    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- path 属性中/**表示所有的 url 拦截,/*表示只拦截根路径的 url 拦截,子层不拦截 -->
            <mvc:mapping path="/**"/>
            <bean class="com.ls.bookmanager.interceptor.MyInterceptor"/>
        </mvc:interceptor>
<!--        <mvc:interceptor>-->
<!--            <mvc:mapping path="/**"/>-->
<!--            <bean class="com.ls.bookmanager.interceptor.MyInterceptor2"/>-->
<!--        </mvc:interceptor>-->
    </mvc:interceptors>

image-20230504102838904

拦截器的实现细节

(二)再谈 MVC 处理过程

image-20230504101453092

1、发起请求到前端控制器 DispatcherServlet,处理请求,但不执行具体操作(model 层)

2、前端控制 DispatcherServlet 请求 HandlerMapping 查找 Handler,(XML 配置或注解)

3、处理器映射器 HandlerMapping 向前端控制器返回 handler 执行链

4、前端控制器调用处理器适配器去执行 handler

5、处理器适配器执行 handle

6、handler 执行完成后返回给处理器适配器 ModelAndView(SpringMVC 框架的一个底层对象,包括 model、 view)

7、处理器适配器向前端控制器返回 ModelAndView

8、前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图(jsp)

9、视图解析器向前端控制器返回 view

10、前端控制器进行视图渲染,将模型数据(在 ModelAndView)填充到 request 域中。

11、前端控制器向用户响应结果。

五、Spring、SpringMVC所有代码

百度网盘

标签:SpringMVC03,拦截器,return,校验,注释,message,异常,public
From: https://www.cnblogs.com/purearc/p/17370414.html

相关文章

  • m基于整数序列的QC-LDPC的稀疏校验矩阵构造算法性能对比matlab仿真,对比差分序列,PEG,
    1.算法仿真效果matlab2013b仿真结果如下:  2.算法涉及理论知识概要       QC-LDPC(Quasi-CyslicLow-DensityParity-CheckCodes)即准循环LDPC码。之前介绍的LDPC码基本属于随机构造法,构造出的码性能很好,但校验矩阵具有不规律性,存在校验矩阵存储于读取困难、编码复......
  • m基于大衍数无高阶环稀疏校验矩阵H构造算法和RMP消息传递的QC-LDPC性能matlab仿真
    1.算法仿真效果matlab2017b仿真结果如下:   2.算法涉及理论知识概要LDPC码早于1962年由Gallager提出,可以看成是一个具有稀疏校验矩阵的线性分组码。自从Mackay和Neal发现LDPC码的性能非常接近香农限以后,LDPC码越来越受到人们的重视。基于准循环LDPC(QC-LDPC)码结......
  • security中登录失败后没有走登录失败拦截器
    在进行security做用户登录时,会创建一系列的拦截器和过滤器,在进行用户校验时,我这边采用的是继承UsernamePasswordAuthenticationFilter,然后重写其中的attemptAuthentication和successfulAuthentication方法,但是在校验失败后,没有走校验失败拦截器。publicclassJwtAuthentication......
  • 拦截器Interceptor
    1、前言SpringMVC中的Interceptor拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306那样子判断当前时间是否是购票时间。 Java里的拦截器是动态拦截action调用的对象。它提......
  • SpringBoot项目使用 validation进行数据校验
    validation进行数据校验@Validated注解和@Valid注解都是SpringFramework中用于数据校验的注解,但它们有以下几点区别:所在包路径不同:@Valid注解位于javax.validation.constraints包下,而@Validated注解位于org.springframework.validation.annotation包下。支持......
  • springmvc 拦截器
    自定义一个拦截器LoginInterceptor这个拦截器的作用就是用户首次要去访问网站,直接点击首页会被拦截并跳转到登录页面,登录成功后(session有记录)方可直接来到首页不被拦截测试1:题目:用户在首次访问前提下,需设置拦截器,使得用户只要登录了才能到达用户主页思路:首先要优化一下首页inde......
  • sap ui5 结束日期校验
    <DatePickerplaceholder=""value="{path:'OtherModel>endDate'}"......
  • 校验日期格式2008-01-01
    校验日期格式2008-01-01functionIsValidDate(dateStr){vardatePat=/^(\d{4})(\-)(\d{1,2})(\-)(\d{1,2})$/;varmatchArray=dateStr.match(datePat);if(matchArray==null){returnfalse;}year=matchArray[1];month=match......
  • 正则校验手机号
    //校验手机号functioncheckPhone(phone){varflag=true;//手机号varreg=/^1[3|4|5|7|8][0-9]\d{8}$/;//电话varreg0=/^(0[1-9]\d{1,2}-)\d{6,7}$/;if(reg.test(phone)==false&&reg0.test(phone)==false){console.lo......
  • J-link自带的串口发不出校验位
    买了个j-link,外观如下图: 安装驱动之后它的5号引脚和17号引脚可以当做串口的TXD和RXD,在设备管理器中显示如下图: 用起来非常的方便。但是最近参与的项目中要用到校验位,发现了问题。用逻辑分析仪测试发现即便串口调试助手中设置了校验位,但是发送出去的数据中依然不......