SpringBoot 에서 사용자 정의 주 해 를 사용 하여 매개 변수 비 공 검 사 를 실현 하 는 예제 입 니 다.

머리말
프로젝트 를 작성 한 지 얼마 되 지 않 아 웹 배경 인 터 페 이 스 를 쓸 때 전단 에 들 어 오 는 매개 변 수 를 규칙 적 으로 검사 합 니 다.만약 에 가입 이 적 으 면 검사 해 야 할 매개 변수 가 비교적 많 으 면 if 검 사 를 사용 하면 대량의 중복 작업 을 가 져 올 수 있 고 코드 를 보면 매우 지루 할 수 있 습 니 다.그래서 저 는 먼저 몇 가지 수단 을 통 해 이 점 을 개선 할 수 있 는 지 생각 합 니 다.컨트롤 러 층 으로 하여 금 파라미터 검사 의 불필요 한 코드 를 줄 이 고 코드 의 읽 을 수 있 도록 합 니 다.
다른 사람의 코드 를 읽 어 보 니 annotation 주 해 를 사용 하 는 것 이 비교적 편리 한 수단 임 을 알 수 있 습 니 다.SpringBoot 가 자체 적 으로 가지 고 있 는@RequestParam 주 해 는 요청 에 있 는 이 매개 변수 가 존재 하 는 지 확인 할 수 있 습 니 다.그러나 이 매개 변 수 는 null 이 아니 라 비어 있 지 않 으 면 판단 할 수 없 기 때문에 요청 매개 변수 에 있 는 주 해 를 강화 해 볼 수 있 습 니 다.
준비 작업
앞의 생각 이 있 으 면 우 리 는 먼저 틀 을 세 워 나 가자.
  • SpringBoot 2.3.5.REALEASE
  • JDK 1.8
  • 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.3.5.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
     </parent>
     <groupId>cn.bestzuo</groupId>
     <artifactId>springboot-annotation</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <name>springboot-annotation</name>
     <description>Demo project for Spring Boot</description>
    
     <properties>
      <java.version>1.8</java.version>
     </properties>
    
     <dependencies>
      <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
      <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
    
      <dependency>
       <groupId>org.projectlombok</groupId>
       <artifactId>lombok</artifactId>
       <optional>true</optional>
      </dependency>
      <!--  AOP     -->
      <dependency>
       <groupId>org.aspectj</groupId>
       <artifactId>aspectjweaver</artifactId>
       <version>1.8.5</version>
      </dependency>
      <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
       <scope>test</scope>
       <exclusions>
        <exclusion>
         <groupId>org.junit.vintage</groupId>
         <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
       </exclusions>
      </dependency>
     </dependencies>
    
     <build>
      <plugins>
       <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
       </plugin>
      </plugins>
     </build>
    
    </project>
    
    그 중에서 aspectjweaver 는 AOP 와 관련 된 주 해 를 도입 하 는 데 사 용 됩 니 다.예 를 들 어@Aspect,@Pointcut 등 입 니 다.
    사용자 정의 주 해 를 사용 하여 비 어 있 는 검 사 를 통일 합 니 다.
    전체적인 사고:주 해 를 사용자 정의 하고 필요 한 매개 변수 에 이 주 해 를 추가 한 다음 절단면 을 정의 하여 이 매개 변수 가 비어 있 는 지 확인 합 니 다.비어 있 으 면 사용자 정의 이상 을 던 집 니 다.이 이상 은 사용자 정의 이상 프로세서 에 의 해 캡 처 된 다음 에 해당 하 는 오류 정 보 를 되 돌려 줍 니 다.
    1.사용자 정의 주석
    Param Check 이라는 주 해 를 만 듭 니 다.코드 는 다음 과 같 습 니 다.
    
    package cn.bestzuo.springbootannotation.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     *         ,        
     *
     * @author zuoxiang
     * @since 2020-11-11
     */
    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ParamCheck {
     /**
      *     ,      
      */
     boolean notNull() default true;
    }
    
    그 중에서@Target주해 중의ElementType.PARAMETER는 이 주해 의 작용 범 위 를 나타 낸다.우 리 는 소스 코드 를 보면 주해 의 작용 범위 정의 가 비교적 광범 위 하고 방법,파라미터,구조 방법,현지 변수,매 거 등에 작용 할 수 있다.
    
    public enum ElementType {
     /** Class, interface (including annotation type), or enum declaration */
     TYPE,
    
     /** Field declaration (includes enum constants) */
     FIELD,
    
     /** Method declaration */
     METHOD,
    
     /** Formal parameter declaration */
     PARAMETER,
    
     /** Constructor declaration */
     CONSTRUCTOR,
    
     /** Local variable declaration */
     LOCAL_VARIABLE,
    
     /** Annotation type declaration */
     ANNOTATION_TYPE,
    
     /** Package declaration */
     PACKAGE,
    
     /**
      * Type parameter declaration
      *
      * @since 1.8
      */
     TYPE_PARAMETER,
    
     /**
      * Use of a type
      *
      * @since 1.8
      */
     TYPE_USE
    }
    
    물론,우리 가 정의 한 주 해 는 확장 할 수 있 습 니 다.매개 변수 가 비어 있 는 지 확인 하 는 것 뿐만 아니 라,예 를 들 어 문자열 의 길 이 를 늘 릴 수 있 습 니 다.
    2.사용자 정의 이상 클래스
    사용자 정의 주석 에 맞 춰 사용 하기 위해 서 입 니 다.사용자 정의 주석 규격 에 맞지 않 는 인 자 를 검사 하면 사용자 정의 이상 을 던 져 서 되 돌 릴 수 있 습 니 다.코드 는 다음 과 같 습 니 다:
    
    package cn.bestzuo.springbootannotation.exception;
    
    public class ParamIsNullException extends RuntimeException {
     private final String parameterName;
     private final String parameterType;
    
     public ParamIsNullException(String parameterName, String parameterType) {
      super("");
      this.parameterName = parameterName;
      this.parameterType = parameterType;
     }
    
     /**
      *       
      *
      * @return       
      */
     @Override
     public String getMessage() {
      return "Required " + this.parameterType + " parameter \'" + this.parameterName + "\' must be not null !";
     }
    
     public final String getParameterName() {
      return this.parameterName;
     }
    
     public final String getParameterType() {
      return this.parameterType;
     }
    }
    
    이 이상 계승RuntimeException은 두 멤버 의 속성,재 작성getMessage() 방법 을 정의 했다.
    기 존org.springframework.web.bind.MissingServletRequestParameterException 클래스 대신 이 이상 을 사용자 정의 하 는 이 유 는 MissingServletRequestParameterException Checked 이상 으로 동적 에이전트 과정 에서java.lang.reflect.UndeclaredThrowableException이상 을 일 으 키 기 쉽 기 때문이다.
    3.사용자 정의 AOP
    코드 는 다음 과 같 습 니 다:
    
    package cn.bestzuo.springbootannotation.aop;
    
    import cn.bestzuo.springbootannotation.annotation.ParamCheck;
    import cn.bestzuo.springbootannotation.exception.ParamIsNullException;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Method;
    
    @Component
    @Aspect
    public class ParamCheckAop {
     private static final Logger LOGGER = LoggerFactory.getLogger(ParamCheckAop.class);
    
     /**
      *         ,    controller     
      */
     @Pointcut("execution(public * cn.bestzuo.controller..*.*(..))")
     public void checkParam() {
    
     }
    
     @Before("checkParam()")
     public void doBefore(JoinPoint joinPoint) {
     }
    
     /**
      *         
      *
      * @param pjp    
      * @return   
      * @throws Throwable   
      */
     @Around("checkParam()")
     public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
      MethodSignature signature = ((MethodSignature) pjp.getSignature());
      //       
      Method method = signature.getMethod();
      //        ,                     
      Annotation[][] parameterAnnotations = method.getParameterAnnotations();
      if (parameterAnnotations.length == 0) {
       return pjp.proceed();
      }
      //       
      String[] paramNames = signature.getParameterNames();
      //     
      Object[] paramValues = pjp.getArgs();
      //        
      Class<?>[] parameterTypes = method.getParameterTypes();
      for (int i = 0; i < parameterAnnotations.length; i++) {
       for (int j = 0; j < parameterAnnotations[i].length; j++) {
        //           ParamCheck   ,  notNull()=true,       
        if (parameterAnnotations[i][j] != null && parameterAnnotations[i][j] instanceof ParamCheck && ((ParamCheck) parameterAnnotations[i][j]).notNull()) {
         paramIsNull(paramNames[i], paramValues[i], parameterTypes[i] == null ? null : parameterTypes[i].getName());
         break;
        }
       }
      }
      return pjp.proceed();
     }
    
     /**
      *     return        (                 )
      *
      * @param joinPoint    
      */
     @AfterReturning("checkParam()")
     public void doAfterReturning(JoinPoint joinPoint) {
     }
    
     /**
      *       ,      ,   ParamIsNullException  
      *
      * @param paramName      
      * @param value      
      * @param parameterType     
      */
     private void paramIsNull(String paramName, Object value, String parameterType) {
      if (value == null || "".equals(value.toString().trim())) {
       throw new ParamIsNullException(paramName, parameterType);
      }
     }
    }
    
    4.전역 이상 프로세서
    이 이상 처리 장 치 는 ParamCheckAop 클래스 에서 던 진 ParamIsNullException 이상 을 포착 하여 처리 합 니 다.코드 는 다음 과 같 습 니 다.
    
    import cn.bestzuo.springbootannotation.common.Result;
    import cn.bestzuo.springbootannotation.enums.EnumResultCode;
    import cn.bestzuo.springbootannotation.utils.ResponseMsgUtil;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.MissingServletRequestParameterException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    
    import javax.servlet.http.HttpServletRequest;
    
    public class GlobalExceptionHandler {
     private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
    
     /**
      *         
      *
      * @param ex   
      * @return      
      */
     @ExceptionHandler({MissingServletRequestParameterException.class, ParamIsNullException.class})
     public Result<String> requestMissingServletRequest(Exception ex) {
      LOGGER.error("request Exception:", ex);
      return ResponseMsgUtil.builderResponse(EnumResultCode.FAIL.getCode(), ex.getMessage(), null);
     }
    
     /**
      *     :            ,      
      *
      * @param request   
      * @param e     
      * @return      
      */
     @ExceptionHandler(value = Exception.class)
     public Result<String> errorHandler(HttpServletRequest request, Exception e) {
      LOGGER.error("request Exception:", e);
      return ResponseMsgUtil.exception();
     }
    }
    
    5.테스트
    먼저 컨트롤 러 를 정의 하여 테스트 를 진행 합 니 다:
    
    @RestController
    public class HelloController {
     /**
      *   @RequestParam  
      *
      * @param name     
      * @return     
      */
     @GetMapping("/hello1")
     public Result<String> hello1(@RequestParam String name) {
      return ResponseMsgUtil.builderResponse(EnumResultCode.SUCCESS.getCode(), "    ", "Hello," + name);
     }
    
     /**
      *   @ParamCheck  
      *
      * @param name     
      * @return     
      */
     @GetMapping("/hello2")
     public Result<String> hello2(@ParamCheck String name) {
      return ResponseMsgUtil.builderResponse(EnumResultCode.SUCCESS.getCode(), "    ", "Hello," + name);
     }
    
     /**
      *   @ParamCheck @RequestParam   
      *
      * @param name     
      * @return     
      */
     @GetMapping("/hello3")
     public Result<String> hello3(@ParamCheck @RequestParam String name) {
      return ResponseMsgUtil.builderResponse(EnumResultCode.SUCCESS.getCode(), "    ", "Hello," + name);
     }
    }
    
    테스트 액세스http://localhost:8080/hello1이 때@RequestParam 주석 만 있 습 니 다.name 인 자 를 추가 하지 않 으 면 이상 을 요청 합 니 다.

    또한 콘 솔 에 서 는 MissingServletRequestParameter 예외:Required String parameter'name'is not present]이상 을 알 립 니 다.
    하면,만약,만약...http://localhost:8080/hello2?name=,이 때 는 사용자 정의@Param Check 주 해 를 사용 합 니 다.이 때 는 인자 입력 이 없 으 면 입력 의 이상 도 캡 처 합 니 다.

    하면,만약,만약...http://localhost:8080/hello3?name=,이 때 는 매개 변수 가 검증 되 어 있 고 사용자 정의 Param Check 가 비어 있 지 않 기 때문에 이 때 는 매개 변 수 를 추가 하지 않 으 면 이상 을 던 집 니 다.

    콘 솔 에서 사용자 정의 이상 던 지기:
    테스트 요약:
    매개 변수 이름 이 비어 있 을 때 두 개의 주 해 를 추가 하 는 인 터 페 이 스 는 모두 매개 변수 가 비어 있 으 면 안 된다 는 것 을 알려 줍 니 다.
    매개 변수 이름 이 비어 있 지 않 고 값 이 비어 있 을 때@RequestParam 주 해 는 잘못 되 지 않 지만@Param Check 주 해 는 매개 변수'name'의 값 이 비어 있 습 니 다.
    6.총화
  • 이상 의 테스트 를 통 해@RequestParam 은 해당 하 는 매개 변수 만 존재 하 는 지 검증 할 뿐 값 이 비어 있 는 지 검증 하지 않 습 니 다
  • Param Check 은 매개 변수 값 의 길이,불법 문자 가 포함 되 어 있 는 지 등 검사 도 할 수 있다
  • .
    7.코드 부록
    위 에서 사용 한 코드:
    
    package cn.bestzuo.springbootannotation.common;
    
    import lombok.Getter;
    import lombok.Setter;
    
    @Getter
    @Setter
    public class Result<T> {
     private Integer resCode;
     private String resMsg;
     private T data;
    }
    
    
    package cn.bestzuo.springbootannotation.enums;
    
    /**
     *       
     *
     * @author zuoxiang
     * @since 2020-11-11
     */
    public enum EnumResultCode {
     SUCCESS(200),
    
     FAIL(400),
    
     UNAUTHORIZED(401),
    
     NOT_FOUND(404),
    
     INTERNAL_SERVER_ERROR(500);
    
     private final int code;
    
     EnumResultCode(int code) {
      this.code = code;
     }
    
     public int getCode() {
      return code;
     }
    }
    
    
    package cn.bestzuo.springbootannotation.utils;
    
    import cn.bestzuo.springbootannotation.common.Result;
    import cn.bestzuo.springbootannotation.enums.EnumResultCode;
    
    public class ResponseMsgUtil {
     /**
      *               
      *
      * @param code      
      * @param msg       
      * @param data     
      * @param <T>   
      * @return     
      */
     public static <T> Result<T> builderResponse(int code, String msg, T data) {
      Result<T> res = new Result<>();
      res.setResCode(code);
      res.setResMsg(msg);
      res.setData(data);
      return res;
     }
    
     /**
      *         
      *
      * @param <T>   
      * @return     
      */
     public static <T> Result<T> exception() {
      return builderResponse(EnumResultCode.INTERNAL_SERVER_ERROR.getCode(), "    ", null);
     }
    }
    
    
    이상 은 SpringBoot 에서 매개 변수 비 공 검 사 를 실현 하 는 예제 에 대한 상세 한 내용 입 니 다.SpringBoot 매개 변수 비 공 검 사 를 위 한 자 료 는 다른 관련 글 을 주목 하 십시오!

    좋은 웹페이지 즐겨찾기