[SpringMVC] Quick start with JSR 303 and interceptor interceptor

Table of contents

1. JSR303

1. What is JSR 303?

2. Why use JSR 303?

3. JSR 303 common annotations

3.1. Commonly used JSR 303 annotations

3.2. The difference between @Validated and @Valid

3.2.1、@Validated

3.2.2、@Valid

3.2.3. Differences

4. Use cases

4.1. Import dependencies

4.2. Configure verification rules

4.3. Write verification method

4.4. Front-end code

4.5. Testing

2. interceptor interceptor

1. What is an interceptor?

2. Why use interceptors?

3. Interceptors and filters

 3.1. What is filter?

3.2. The difference between interceptors and filters

3.2.1. Filter

3.2.2. Interceptor

3.2.3. Summary

4. Interceptor application scenarios

5. Use cases

5.1. Create interceptor

5.2. Configure interceptor

5.3. Run the test

5.4. Working principle of interceptor

5.5. Interceptor chain

5.6. Login interception example

5.6.1. Create interceptor

5.6.2. Configure interceptor

5.6.3. Writing the control layer

5.6.4. Front-end page

5.6.5. Testing

login

Sign out


1. JSR303

1. What is JSR 303?

JSR 303 is the abbreviation of Java Specification Request , 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 to Some additional constraints.

It defines a set of standards for Java Bean validation. JSR 303 uses annotations, which are widely used in Spring MVC for data verification and verification.

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

2. Why use JSR 303?

        We performed data verification on the front end, but why do we need to do another article? Because because of a small mistake, our front-end verification was not written well, but some people still bypass the requests sent by the front end (through tests like Postman Tools make extraordinary data requests) and pass some wrong parameters, which will put our back-end code in great danger, so we generally use one set of verifications on the front end and one set of verifications on the back end, so that the security is It can be greatly improved.

So I summed up the benefits of JSR 303 below:

  1. Improve the maintainability of the code: By adding annotations to the entity class, the fields and rules that need to be verified can be clearly identified, making the code easier to understand and maintain.
  2. Enhance data integrity: According to defined rules, the legality of input data can be automatically verified to prevent erroneous data from entering the system and ensure data integrity and accuracy.
  3. Reduce duplicate code: Through annotations, the same verification rules can be reused in different scenarios, reducing the workload of writing duplicate code.

3. JSR 303 common annotations

3.1. Commonly used JSR 303 annotations

Annotation description @Null is used to verify that the object is null @NotNull is used when the object cannot be null , and a string with a length of 0 cannot be checked @NotBlank is only used for String type, it cannot be null and the size after trim() is > 0 @NotEmpty Used for collection classes, String classes cannot be null , and size>0 . But strings with spaces cannot be verified. @Size is used for objects ( Array, Collection, Map, String ) whether the length is within the given range. @Length is used for String objects. The size must be within the specified range. @Pattern Used for whether the String object conforms to the rules of the regular expression @Email Used for whether the String object conforms to the email format @Min Used for whether the Number and String objects are greater than or equal to the specified value @Max Used for whether the Number and String objects are less than or equal to the specified value @ AssertTrue is used to determine whether the Boolean object istrue @AssertFalse for whether the Boolean object is false

3.2. The difference between @Validated and @Valid

@Validated and @Valid are annotations used for data verification, but they have some differences and application scenarios.

3.2.1、@Validated
  • Annotations provided by the Spring framework
  • 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
  • The validator provided by Spring uses Hibernate Validator by default (implements the JSR-303 specification), but it supports richer validation scenarios, such as group validation.
3.2.2、@Valid
  • Annotations of the JSR-303 ( Bean Validation ) specification provided by the JDK
  • 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
  • When using the @Valid annotation, JSR-303 or other supported validation frameworks will be triggered to validate the annotated object.
3.2.3. Differences
  1. Scope of application : @Valid can be applied to method parameters, return values, fields and methods, while @Validated can only be applied to classes, interfaces and methods.
  2. Validation framework : @Validated uses Hibernate Validator (implements JSR-303), Spring Validator or a custom validator by default, while @Valid uses JSR-303 or other supported validation frameworks.
  3. Group verification : @Validated supports group verification, allowing different verification rules to be used in different scenarios, while @Valid does not directly support group verification.

@Validated is an extended annotation provided by the Spring framework and does not belong to the Java standard specification. When using it, you can select appropriate annotations for data verification according to specific needs.

4. Use cases

4.1. Import dependencies

<!-- JSR303 -->
<hibernate.validator.version>6.0.7.Final</hibernate.validator.version>

<!-- JSR303 -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>${hibernate.validator.version}</version>
</dependency>

4.2. Configure verification rules

Add configuration verification in the entity class

package com.tgq.model;

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

import javax.validation.constraints.NotNull;

@ToString
public class MyStudent {

    @NotNull(message = "学生编号不能为空")
    private String sid;

    @NotBlank(message = "学生名不能为空")
    private String sname;

    @NotBlank(message = "学生年龄不能为空")
    private String sage;

    @NotBlank(message = "学生性别不能为空")
    private String ssex;

    public MyStudent(String sid, String sname, String sage, String ssex) {
        this.sid = sid;
        this.sname = sname;
        this.sage = sage;
        this.ssex = ssex;
    }

    public MyStudent() {
        super();
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public String getSage() {
        return sage;
    }

    public void setSage(String sage) {
        this.sage = sage;
    }

    public String getSsex() {
        return ssex;
    }

    public void setSsex(String ssex) {
        this.ssex = ssex;
    }
}

4.3. Write verification method

   Use @Validatedannotations to perform server-side verification on our MyStudent.

    //    给数据添加服务端校验
    @RequestMapping("/valiAdd")
    public String valiAdd(@Validated MyStudent myStudent, 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.myStudentBiz.insertSelective(myStudent);
            return "redirect:stu/list";
        }
        return "stu/edit";
    }

4.4. Front-end code

Submit using form

<%--
  Created by IntelliJ IDEA.
  User: tgq
  Date: 12/9/2023
  Time: 下午8:05
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>edit</title>
</head>
<body>

<form action="${pageContext.request.contextPath }/stu/valiAdd" method="post">
    用户id:<input type="text" name="sid"><span style="color: red">${errorMap.sid}</span><br>
    用户名:<input type="text" name="sname"><span style="color: red">${errorMap.sname}</span><br>
    用户年龄:<input type="text" name="sage"><span
        style="color: red">${errorMap.sage}</span><br>
    用户性别:<input type="text" name="ssex"><span style="color: red">${errorMap.ssex}</span><br>
    <input type="submit" value="提交">
</form>
</body>
</html>

4.5. Testing

Click submit. If it is empty, you will be prompted.

2. interceptor interceptor

1. What is an interceptor?

        Interceptors are components that perform specific logic before or after a request enters a backend handler. They are able to intercept the flow of execution by the handler, allowing additional functionality to be inserted into the request handling process.

        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. Why use interceptors?

  1. Horizontal function expansion : Through interceptors, additional functions can be added without modifying the original business logic, such as logging, permission verification, performance statistics, etc.
  2. Code reuse : Multiple requests may require the same processing logic. This part of the logic can be extracted through interceptors to reduce repeated writing of code.
  3. Decoupling : Through interceptors, concerns can be separated and common logic is processed in the interceptors, allowing the business processor to focus more on the business itself.

3. Interceptors and filters

 3.1. What is filter?

Depends on servlet container . Based on function callbacks in implementation, almost all requests can be filtered , but the disadvantage is that a filter instance can only be called once when the container is initialized . The purpose of using filters is to perform some filtering operations, such as: modifying the character encoding in the filter; modifying some parameters of HttpServletRequest in the filter , including: filtering vulgar text, dangerous characters, etc.

3.2. The difference between interceptors and filters

3.2.1. Filter
  1.   Filter belongs to Servlet technology and can be used in any web project.
  2.   filter is mainly due to filtering all requests
  3.   The execution time of filter is earlier than Interceptor
3.2.2. Interceptor
  1.   Interceptor belongs to SpringMVC technology and must have a SpringMVC environment before it can be used.
  2.   interceptor usually intercepts the processor Controller
  3.   interceptor can only intercept requests processed by dispatcherServlet
3.2.3. Summary
  • Interceptors are executed inside the application handler , while filters are executed before or after the application .
  • Filters are based on the Servlet specification, and interceptors are based on the application framework.
  • Filters can process requests before they reach the Servlet container, while interceptors can only process requests after they reach the application.

4. Interceptor application scenarios

  1. Permission verification : The interceptor can check whether the user has permission to operate. If not, it can intercept the request and return the corresponding error message. If not, return directly to the login page.
  2. Logging : The interceptor can record the detailed information of the request, such as request time, information, request parameters, etc., to facilitate subsequent log analysis and troubleshooting. In order to carry out information monitoring, information statistics, calculation of PV (Page View), etc.
  3. Performance statistics : The interceptor can count the execution time of requests to facilitate analysis and optimization of system performance. (If there is a reverse proxy, such as apache, it can be automatically recorded);
  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.

An interceptor chain is a chain structure composed of multiple interceptors , each of which can perform specific operations before or after the request handler is executed. The interceptors in the interceptor chain are executed in a predefined order, and each interceptor has a chance to process the request and response. The interceptor chain can ensure the orderly execution of each interceptor to achieve the expected processing logic.

5. Use cases

5.1. Create interceptor

Create an interceptor package and create the interceptor under the package

package com.tgq.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


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

        return true;//返回true / false
    }

    @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...");
    }
}

5.2. Configure interceptor

Configure our interceptor in our own configuration spring-mvc.xml

<mvc:interceptors>
        <bean class="com.tgq.interceptor.OneInterceptor"></bean>
    </mvc:interceptors>

5.3. Run the test

Start the project, open the browser to access the request address, and test the interception effect of the interceptor.

Their execution order is: preHandle --> postHandle --> afterCompletion

http://localhost:8080/sc/list

5.4. Working principle of interceptor

  • preHandle : used to preprocess intercepted requests. The method receives a return value of Boolean (true, false) type. Returns true: released, false: not released.

Execution timing: executed before the processor method is executed

method parameters
parameter illustrate
request       request object    
response     response object    
handler       Intercepted handler method  
ModelAndView Model and view objects returned by the handler method, the model and view can be modified in the method
  • afterCompletion : used for final processing after the entire process is completed. If there is an exception in the request process, the object can be obtained in the method

  Execution timing: after the view rendering is completed (after the entire process ends)

method parameters
parameter illustrate
request   Request parameters
response response object  
handler   Intercepted handler method
ex exception object

5.5. Interceptor chain

If multiple interceptors can intercept the same request, multiple interceptors will form an interceptor chain. The main purpose is to understand the execution order of each interceptor in the interceptor chain. The execution order of multiple interceptors in the interceptor chain is related to the configuration order of the root interceptor. The one configured first is executed first.

package com.tgq.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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...");
    }
}

Configure spring-mvc.xml

<mvc:interceptors>
        <!--2) 多拦截器(拦截器链)-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.tgq.interceptor.OneInterceptor"/>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/sc/**"/>
            <bean class="com.tgq.interceptor.TwoInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

Use an interceptor: edit icon-default.png?t=N7T8http://localhost:8080/stu/save

Take two interceptors: list icon-default.png?t=N7T8http://localhost:8080/sc/list

5.6. Login interception example

5.6.1. Create interceptor
package com.tgq.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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 sname = (String) request.getSession().getAttribute("sname");
        if (sname == null || "".equals(sname)) {
            response.sendRedirect("/page/stu/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 {

    }
}
5.6.2. Configure interceptor
    <!--登录拦截器实例-->
    <mvc:interceptors>
        <bean class="com.tgq.interceptor.LoginInterceptor"></bean>
    </mvc:interceptors>

5.6.3. Writing the control layer
package com.tgq.web;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(HttpServletRequest req) {
        String sname = req.getParameter("sname");
        HttpSession session = req.getSession();
        if ("tgq".equals(sname)) {
            session.setAttribute("sname", sname);
        }
        return "redirect:/sc/list";
    }

    @RequestMapping("/logout")
    public String logout(HttpServletRequest req) {
        req.getSession().invalidate();
        return "redirect:/sc/list";
    }
}
5.6.4. Front-end page
<%--
  Created by IntelliJ IDEA.
  User: tgq
  Date: 12/9/2023
  Time: 下午10:03
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户登录</title>
</head>
<body>

<form action="/login" method="post">
    账号:<input name="sname">
    <input type="submit">
</form>
</body>
</html>
5.6.5. Testing
login

http://localhost:8080/logouticon-default.png?t=N7T8http://localhost:8080/login

Sign out

http://localhost:8080/logouticon-default.png?t=N7T8http://localhost:8080/logout

Guess you like

Origin blog.csdn.net/weixin_74383330/article/details/132837017