SpringMVC JSR303 usage and interceptor usage (taking you to explore new areas of SpringMVC)

Table of contents

Preface

1. Explore the world of JSR303

1. Introduction to JSR303

1.1 What is JSR303

 1.2 The importance of JSR303 and reasons for its use

importance:

reason:

1.3 Common annotations of JSR303

Expand

2. JSR303 Quick Start (Basic Use) 

2.1 Import dependencies

 2.2 Configure validation rules

 Entity class attribute settings

Corresponding controller methods

 Corresponding to JSP page writing

2.3 Test results

2. Study the secrets of interceptors (use of interceptors) 

2.1 What is an interceptor?

2.2 The difference between interceptors and filters

2.3. Application scenarios

2.4 Quick Start of Interceptor

2.4.1 Create an interceptor

2.4.2 Configure interceptor (configured in spring-mvc.xml)

 2.4.3 Test results of changing the return value of preHandle in the interceptor class to false

2.5 Interceptor running meridians (working principle)

Schematic diagram

 Detailed description of working principle

2.6 The secret of the interceptor chain (explaining the interceptor chain)

2.6.1 Create another interceptor

2.6.2 Configure two interceptors (configured in spring-mvc.xml)

2.6.3 Test results

Scenario 1: Testing requests under clz

Situation 2: The test is not a request under clz 

2.6.4 Note

3. The ultimate secret of the interceptor (case simulation use)

1. Create the interceptor required for the case

2. Configure the interceptors required for the case

3. Create the controller required for the case

4. Create a simulation case jsp page

Test Results

Simulation test login

sign out

Edit 


Preface

         Today I will continue to share knowledge about SpringMVC with you. Today I will take you to explore the new areas of SpringMVC. Let us learn and understand it together.

1. Explore the world of JSR303

1. Introduction to JSR303

1.1 What is JSR303

        JSR is the abbreviation of Java Specification Requests , which means Java specification proposal . It is a formal request to JCP (Java Community Process) to add a standardized technical specification. Anyone can submit a JSR to add new APIs and services to the Java platform. JSR has become an important standard in the Java world. JSR-303 is a sub-specification in JAVA EE 6 called Bean Validation . Hibernate Validator is the reference implementation of Bean Validation. Hibernate Validator provides implementation of all built-in constraints in the JSR 303 specification. In addition, there are Some additional constraints.

        It defines a set of standard annotations and APIs for validating Java Bean objects. By using JSR 303 annotations, you can perform various verifications on Java Bean properties, such as checking whether a field is empty, whether it meets a specific format, whether it is within a specified range, etc. This can provide a convenient and unified verification mechanism during data binding and validity verification.

        Note:

Validating data is a common task that occurs in all application layers from the presentation layer to the persistence layer. Often the same validation logic is implemented at every layer, which is time-consuming and error-prone. To avoid duplicating these validations, developers often bundle validation logic directly into the domain model, mixing domain classes with validation code that is actually metadata about the classes themselves.

 1.2 The importance of JSR303 and reasons for its use

Importance :
  • Data validity verification : JSR 303 allows developers to verify the value of Java Bean properties to ensure the validity of the data. By using predefined validation annotations, properties can be easily verified, such as checking whether they are empty, whether they meet the specified format, whether they are within a reasonable range, etc.

  • Unified verification specifications : Using JSR 303, you can define a unified set of verification specifications, such as the annotation list of the validator, so that the entire team can follow the same verification rules and improve the consistency and readability of the code.

  • Reduce duplicate code : Using JSR 303 can reduce manually written and maintained validation logic code, because the validation logic has been defined by annotations and integrated into the validation framework. This can reduce the writing of repeated code and improve development efficiency.

  • Powerful validation : JSR 303 provides a variety of predefined validation annotations, such as @NotNull, @Size, @Email, etc., which can meet most common validation needs. In addition, it also supports custom validation annotations and can create specific validation rules based on specific business needs.

  • Compatibility and portability : JSR 303 is part of Java EE and is widely supported and used in various Java frameworks and platforms, such as Spring, Hibernate, etc. Therefore, using JSR 303 can achieve good compatibility and portability, and validation rules can be reused in different projects and environments.

Reason :
  1. If the front-end code verification is not written well, or for people who know a little programming, they directly bypass the front-end and send requests (make extraordinary data requests through testing tools like Postman) and pass some wrong parameters. You Isn’t the back-end code dangerous? Therefore, we generally perform one set of verifications on the front end and one set of verifications on the back end, so that security can be greatly improved.

  2. JSR 303 provides a simple, consistent and extensible way to verify the data validity of Java Bean objects, improving development efficiency and code quality. By using JSR 303, you can reduce the workload of manually writing verification logic and improve the readability and maintainability of your code.

1.3 Common annotations of JSR303

annotation illustrate
@Null Used to verify that the object is null
@NotNull Used for objects that cannot be null and cannot check strings with a length of 0
@NotBlank Only used for String type, cannot be null and size after trim()>0
@NotEmpty Used for collection classes, String classes cannot be null, and size>0. But strings with spaces cannot be verified.
@Size Used to check whether the length of the object (Array, Collection, Map, String) is within the given range
@Length The size used for String objects must be within the specified range
@Pattern Rules for whether a String object conforms to a regular expression
@Email Used to determine whether the String object conforms to the mailbox format
@Min Used to determine whether Number and String objects are greater than or equal to the specified value.
@Max Used to determine whether Number and String objects are less than or equal to the specified value
@AssertTrue Whether the Boolean object is true
@AssertFalse Whether the Boolean object is false
Expand

The difference between @Validated and @Valid  :

 @Validated:

  • Provided by Spring

  • Support group verification

  • Can be used on types, methods and method parameters. But it cannot be used on member attributes (fields)

  • Since it cannot be added to member attributes (fields), cascade verification cannot be completed alone and needs to be coordinated with @Valid

@Valid:

  • Provided by JDK (standard JSR-303 specification)

  • Group verification is not supported

  • Can be used on methods, constructors, method parameters and member properties (fields)

  • Can be added to member attributes (fields) to complete cascade verification independently

2. JSR303 Quick Start (Basic Use) 

2.1 Import dependencies

 2.2 Configure validation rules

 Entity class attribute settings
package com.yx.model;

import lombok.ToString;
import org.hibernate.validator.constraints.NotBlank;

import javax.validation.constraints.NotNull;

@ToString
public class Clazz {
    @NotNull(message = "班级编号不能为空")
//    @Size(max = 100,min = 10,message = "大小必须在10至100之间"),不注解测会影响代码运行
    protected Integer cid;

    @NotBlank(message = "班级名不能为空")
    protected String cname;

    @NotBlank(message = "班级教员老师不能为空")
    protected String cteacher;


    private String pic;

    public Clazz(Integer cid, String cname, String cteacher, String pic) {
        this.cid = cid;
        this.cname = cname;
        this.cteacher = cteacher;
        this.pic = pic;
    }

    public Clazz() {
        super();
    }

    public Integer getCid() {
        return cid;
    }

    public void setCid(Integer cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    public String getCteacher() {
        return cteacher;
    }

    public void setCteacher(String cteacher) {
        this.cteacher = cteacher;
    }

    public String getPic() {
        return pic;
    }

    public void setPic(String pic) {
        this.pic = pic;
    }
}
Corresponding controller methods
//    给数据添加服务端校验
    @RequestMapping("/valiAdd")
    public String valiAdd(@Validated Clazz clazz, BindingResult result, HttpServletRequest req){
//        如果服务端验证不通过,有错误
        if(result.hasErrors()){
//            服务端验证了实体类的多个属性,多个属性都没有验证通过
            List<FieldError> fieldErrors = result.getFieldErrors();
            Map<String,Object> map = new HashMap<>();
            for (FieldError fieldError : fieldErrors) {
//                将多个属性的验证失败信息输送到控制台
                System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage());
                map.put(fieldError.getField(),fieldError.getDefaultMessage());
            }
            req.setAttribute("errorMap",map);
        }else {
            this.clazzBiz.insertSelective(clazz);
            return "redirect:list";
        }
        return "clz/edit";
    }

 Corresponding to JSP page writing
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>电影编辑界面</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/${empty c ? 'clz/valiAdd' : 'clz/edit'}" method="post">
    班级编号:<input type="text" name="cid" value="${c.cid }"><span style="color: red;">${errorMap.cid}</span><br>
    班级名称:<input type="text" name="cname" value="${c.cname }"><span style="color: red;">${errorMap.cname}</span><br>
    教员:<input type="text" name="cteacher" value="${c.cteacher }"><span style="color: red;">${errorMap.cteachcer}</span><br>
    图片:<input type="text" name="pic" value="${c.pic }"><br>
    <input type="submit">
</form>
</body>
</html>

2.3 Test results

2. Study the secrets of interceptors (use of interceptors) 

2.1 What is an interceptor?

        Interceptor is a common design pattern used in software development for components that intercept and process requests, responses, or method calls. Interceptors allow developers to pre-process, post-process, or perform additional operations on requests at specific points in time.

        In web development, interceptors are often used to intercept HTTP requests and responses to perform some action before or after processing the request. For example, you can use interceptors for authentication, logging, performance monitoring, exception handling, etc. Interceptors are widely used in frameworks and platforms, such as Java's Servlet filter, Spring framework's interceptor, Android framework's interceptor, etc. They provide a pluggable, reusable, and extensible way to handle various requests and operations.

         SpringMVC's processor interceptor is similar to the filter in Servlet development and is used to pre-process and post-process the processor. It relies on the web framework and is based on Java's reflection mechanism in implementation, which is an application of aspect-oriented programming (AOP). Since the interceptor is based on the call of the web framework, Spring's dependency injection (DI) can be used to perform some business operations. At the same time, an interceptor instance can be called multiple times within a controller life cycle.

2.2 The difference between interceptors and filters

  • The scope of scope is different: interceptors are usually used in a certain layer within the application, and are used to intercept requests and processes in the MVC framework ; filters are used at the Servlet container level to intercept HTTP requests and responses.
  • The processing location is different: interceptors are located around a specific handler ; filters are located before and after the request chain .
  • The functions are different: interceptors are more used to pre-process and post-process requests , and perform additional operations during request processing ; filters are more used to modify or convert data between requests and responses .
  • Implementation interfaces are different: Interceptors usually need to implement specific interfaces , such as the HandlerInterceptor interface in the Spring framework; filters need to implement the javax.servlet.Filter interface .
  • Import dependencies are different: Interceptors are usually used in conjunction with MVC frameworks or specific request processing frameworks (such as Spring MVC), and therefore may depend on the context and functionality of these frameworks ; filters are executed at the Servlet container level , with specific Frame independent.

2.3. Application scenarios

  1. Logging : Record logs of request information for information monitoring, information statistics, calculation of PV (Page View), etc.

  2. Permission check : such as login detection, enter the processor to detect whether you are logged in, and if not, return directly to the login page;

  3. Performance monitoring : Sometimes the system is inexplicably slow for a certain period of time. You can use the interceptor to record the start time before entering the processor and record the end time after processing to get the processing time of the request (if there is a reverse proxy, such as apache can automatically record);

  4. General behavior : read the cookie to obtain user information and put the user object into the request, so as to facilitate subsequent use of the process, as well as extracting Locale and Theme information, etc., as long as the processing methods in multiple Controllers require it, we can use interception implement.

2.4 Quick Start of Interceptor

2.4.1 Create an interceptor

public class OneInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("【OneInterceptor】:preHandle...");

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("【OneInterceptor】:postHandle...");

    }

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

2.4.2 Configure interceptor (configured in spring-mvc.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
      http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--1) 扫描com.zking.zf及子子孙孙包下的控制器(扫描范围过大,耗时)-->
    <context:component-scan base-package="com.yx"/>

    <!--2) 此标签默认注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter -->
    <mvc:annotation-driven />

    <!--3) 创建ViewResolver视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- viewClass需要在pom中引入两个包:standard.jar and jstl.jar -->
        <property name="viewClass"
                  value="org.springframework.web.servlet.view.JstlView"></property>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--4) 单独处理图片、样式、js等资源 -->
     <mvc:resources location="/static/" mapping="/static/**"/>

<!--    处理文件的上传下载的问题-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 必须和用户JSP 的pageEncoding属性一致,以便正确解析表单的内容 -->
        <property name="defaultEncoding" value="UTF-8"></property>
        <!-- 文件最大大小(字节) 1024*1024*50=50M-->
        <property name="maxUploadSize" value="52428800"></property>
        <!--resolveLazily属性启用是为了推迟文件解析,以便捕获文件大小异常-->
        <property name="resolveLazily" value="true"/>
    </bean>

<!--    配置拦截器-->
    <mvc:interceptors>
        <bean class="com.yx.interceptor.OneInterceptor"></bean>
    </mvc:interceptors>

     <aop:aspectj-autoproxy/>
</beans>

 Configuration results

 As shown in the figure above, if no further configuration is performed, the interceptor will intercept all requests and will be tested next.

 When we send a request, as shown below

Then the interceptor will intercept (because if no further configuration is made before, all will be intercepted), the console output is as follows

It will first pass through the interceptor for preprocessing, and then make output; then call the specified method through the controller; then pass through the interceptor for console output; then echo to the page, and the interceptor will perform final processing.

 2.4.3 Test results of changing the return value of preHandle in the interceptor class to false

 When sending a request, the request will be intercepted and the method request method will be blocked, resulting in the inability to access the database, so the data cannot be displayed on the page, and subsequent code operations will not be executed. The effect is as follows

Page effect

console output 

2.5 Interceptor running meridians (working principle)

Schematic diagram

 Detailed description of working principle
  1. Define interceptors: First, you need to define one or more interceptors and implement the corresponding interceptor interface or class. These interceptors will contain the logic of the actions to be performed.

  2. Set up an interceptor chain: Where interceptors need to be used, such as the controller layer of the MVC framework, there will be an interceptor chain (Interceptor Chain) used to store all interceptor instances. The interceptor chain is organized in a certain order, which determines the execution order of interceptors.

  3. Execute interceptor logic: When the request reaches the location of the interceptor chain, each interceptor will be executed in sequence. Interceptors will be called at different stages of request processing, such as before request, after request, before view rendering, after view rendering, etc.

  4. Interceptor pre-processing: Each interceptor can perform some pre-processing operations before execution, such as authentication, parameter verification, logging, etc. These operations can be performed before the request reaches the target handler to ensure the validity and security of the request.

  5. Handler execution: After the last interceptor of the interceptor chain executes, the request is passed to the target handler, such as a controller method in the MVC framework. Handlers perform specific business logic and return a result.

  6. Interceptor post-processing: After the handler is executed, the interceptor chain will execute the interceptor post-processing operations in reverse order. These operations can handle handler return results, log, clean up resources, and more.

Note:

        Interceptors can perform predefined operations at different stages of the request and intervene and process the request. How interceptors work and the specific interceptor interfaces and methods may vary depending on the framework and application architecture used.

2.6 The secret of the interceptor chain (explaining the interceptor chain)

2.6.1 Create another interceptor
public class TwoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("【TwoInterceptor】:preHandle...");

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("【TwoInterceptor】:postHandle...");

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("【TwoInterceptor】:afterCompletion...");
    }
}
2.6.2 Configure two interceptors (configured in spring-mvc.xml)
 <mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.yx.interceptor.OneInterceptor"/>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/clz/**"/>
        <bean class="com.yx.interceptor.TwoInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

Add the above code to the spring-mvc.xml file and comment out the original ones.

2.6.3 Test results
Scenario 1: Testing requests under clz

page

Because the return value of preHandle has not been changed to false, the interface can be accessed.

console

Situation 2: The test is not a request under clz 

2.6.4 Note

 When we access images or static resource mappings, we do not go through the interceptor.

3. The ultimate secret of the interceptor (case simulation use)

1. Create the interceptor required for the case

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("【implements】:preHandle...");
        StringBuffer url = request.getRequestURL();
        if (url.indexOf("/login") > 0 || url.indexOf("/logout") > 0){
            //        如果是 登录、退出 中的一种
            return true;
        }
//            代表不是登录,也不是退出
//            除了登录、退出,其他操作都需要判断是否 session 登录成功过
        String uname = (String) request.getSession().getAttribute("uname");
        if (uname == null || "".equals(uname)){
            response.sendRedirect("/page/login");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

2. Configure the interceptors required for the case

<mvc:interceptors>
        <bean class="com.yx.interceptor.LoginInterceptor"></bean>
    </mvc:interceptors>

3. Create the controller required for the case

package com.yx.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
 * @author 君易--鑨
 * @site www.yangxin.com
 * @company 木易
 * @create  2023-09-09 15:25
 */
@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(HttpServletRequest req){
        String uname = req.getParameter("uname");
        HttpSession session = req.getSession();
        if ("zs".equals(uname)){
            session.setAttribute("uname",uname);
        }
        return "redirect:/clz/list";
    }

    @RequestMapping("/logout")
    public String logout(HttpServletRequest req){
        req.getSession().invalidate();
        return "redirect:/clz/list";
    }
}

4. Create a simulation case jsp page

<%--
  Created by IntelliJ IDEA.
  User: 86158
  Date: 2023/9/13
  Time: 0:15
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>登陆界面</h1>
<form action="/login" method="post">
    用户名:<input name="uname">
    <input type="submit">

</form>
</body>
</html>

Test Results

Simulation test login

sign out

That’s it for today’s exploration of new knowledge. I hope I can pay attention and support. 

Guess you like

Origin blog.csdn.net/weixin_74352229/article/details/132838440