每个程序员都能写出简介优雅的restful接口validation(springboot)

痛定思痛。 2023-07-24 11:36 11阅读 0赞

背景
最近在开发的时候贼烦,本来是想写一个非常简洁而优雅的restful风格的代码的,controller层本来是想超级简单,可是奈何,一个接口包含输入请求参数总是需要我们去效验的。

  1. @PostMapping("/saveIntuitiveLike")
  2. @AdminValidable(validType = 2)
  3. @ApiOperation(value = "直观像模块-新建直观像", notes = "", httpMethod = "POST")
  4. public Response<?> saveIntuitiveLike(HttpServletRequest request, HttpServletResponse response,
  5. @ApiParam(value = "直观像模块-新建直观像") @RequestBody List<SaveIntuitiveLikeNodeReq> reqList) throws Exception {
  6. String adminName = this.getCurrentAdminName(request);
  7. logger.info("直观像模块-新建直观像:saveIntuitiveLike,adminName is {} req is {}", adminName, JsonUtil.tranObjToStr(reqList));
  8. //参数
  9. if (!UtilEmpty.isNullorEmpty(reqList)) {
  10. reqList.forEach(x->{
  11. try {
  12. checkIntuitiveLike(x);
  13. } catch (OkyaException e) {
  14. logger.info("直观像模块-新建直观像:saveIntuitiveLike error msg is ", JsonUtil.tranObjToStr(e));
  15. e.printStackTrace();
  16. }
  17. });
  18. }
  19. intuitiveLikeBusiness.saveIntuitiveLike(reqList);
  20. return Response.ok("创建成功");
  21. }
  22. public void checkIntuitiveLike(SaveIntuitiveLikeNodeReq req) throws OkyaException {
  23. if (UtilEmpty.isNullorEmpty(req)) {
  24. try {
  25. throw new OkyaException("IntuitiveLikeBusiness", "checkPara", API_RESULT.PARA_CAN_NOT_EMPTY);
  26. } catch (OkyaException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. boolean b = paramCheck( req.getAnswerJudgeTime(), req.getAnswerLists(), req.getAnswerShowTime(),
  31. req.getAnswerTime(), req.getIntuitiveShowTime(), req.getIntuitiveType(), req.getLessonUnique());
  32. if (!b) {
  33. throw new OkyaException("IntuitiveLikeBusiness", "checkPara", API_RESULT.PARA_CAN_NOT_EMPTY);
  34. }
  35. }

在这里插入图片描述
然而效验就是归效验,这样写代码是简单了,然并卵,可是前段并不知道具体是哪个参数是空的呀,这就很蛋疼了。所以呢 老是会存在到底哪个参数不能非空呀。所以我们就的在swagger上标明到底哪个参数是否是要非空,可是要是哪天需求改了呢,参数就很有可能忘记修改
在这里插入图片描述
这个痛点一直伴随了我这苦逼的程序员很久,终于曙光到来,发现validation能够非常好的处理这个问题,废话不多说,我们直接来个Demo展现一下风采吧。

pom文件引入依赖包

  1. <dependency>
  2. <groupId>javax.validation</groupId>
  3. <artifactId>validation-api</artifactId>
  4. </dependency>

编写DTO类

  1. @Data
  2. @ApiModel
  3. public class UserSaveReq implements Serializable {
  4. @NotEmpty(message = "用户名字不能为空")
  5. @ApiModelProperty(value = "姓名")
  6. private String user;
  7. @ApiModelProperty(value = "手机号码")
  8. @NotBlank(message = "手机号不能为空")
  9. private String phone;
  10. }

编写controller层

  1. @PostMapping("/saveUser")
  2. public String saveUser(HttpServletRequest request, HttpServletResponse response,
  3. @ApiParam(value = "查询订单列表") @RequestBody @Valid UserSaveReq req){
  4. UserModel userModel = new UserModel();
  5. BeanUtils.copyProperties(req,userModel);
  6. userService.save(userModel);
  7. return "添加成功";
  8. }

记得这里必须要加上@Valid注解

测试一波
在这里插入图片描述
在这里插入图片描述
接口返回400,在defaultMessage上返回了我们刚才在Dto上配置的message内容,这样展示是 好像是有点不太友好,没关系我们使用@ControllerAdvice拦截异常

  • 首先我们封装下Response输出格式

    package com.evan;

    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;

    /**

    • 请求响应结果
    • @author EvanYang
      *
    • @param
      */
      @ApiModel(description = “返回对象”)
      @Data
      public class Response {
      public final static String CODE_OK = “200”;
      public final static String MSG_OK = “ok”;
      public final static String CODE_ERROR = “5000”;
      public final static String MSG_ERROR = “error”;
      @ApiModelProperty(value = “返回码,200为成功,其他为失败”, required = true)
      private String resultCode;
      @ApiModelProperty(value = “返回码描述”, required = true)
      private String resultMsg;
      @ApiModelProperty(value = “结果签名”, required = true)
      private String sign;
      @ApiModelProperty(value = “详细数据”, required = false)
      private T data;

      public Response() {

      1. resultCode = CODE_OK;
      2. resultMsg = MSG_OK;

      }

      public Response(String resultCode, String resultMsg) {

      1. this.resultCode = resultCode;
      2. this.resultMsg = resultMsg;

      }

      /**

      • 成功结果
        *
      • @param data
      • @param
      • @return
        */
        public static Response ok(T data, String sign) {
        Response response = new Response<>();
        response.setData(data);
        response.setSign(sign);
        return response;
        }

        /**

      • 成功结果
        *
      • @param data
      • @param
      • @return
        */
        public static Response ok(T data) {
        Response response = new Response<>();
        response.setData(data);
        return response;
        }
  1. /**
  2. * 失败结果
  3. *
  4. * @param data
  5. * @param <T>
  6. * @return
  7. */
  8. public static <T> Response<T> error(T data) {
  9. Response<T> response = new Response<>();
  10. response.setData(data);
  11. return error(CODE_ERROR, MSG_ERROR, data);
  12. }
  13. /**
  14. * 失败结果
  15. *
  16. * @param code
  17. * @param msg
  18. * @param data
  19. * @param <T>
  20. * @return
  21. */
  22. public static <T> Response<T> error(String code, String msg, T data) {
  23. Response<T> response = new Response<>(code, msg);
  24. response.setData(data);
  25. return response;
  26. }
  27. /**
  28. * 失败结果
  29. *
  30. * @param data
  31. * @param <T>
  32. * @return
  33. */
  34. public static <T> Response<T> error(Exception exception, T data) {
  35. return errorException(exception, data);
  36. }
  37. /**
  38. * 失败结果
  39. * @param data
  40. * @param <T>
  41. * @return
  42. */
  43. public static <T> Response<T> errorException(Exception exception, T data) {
  44. Response<T> response = new Response<>();
  45. response.setData(data);
  46. response.setResultMsg(exception.getMessage());
  47. return response;
  48. }
  49. }
  • 自定义异常类BusinessException

    package com.evan.except;

    /**

    • @author evanYang
    • @version 1.0
    • @date 04/11/2020 10:49
      */
      public class BusinessException extends RuntimeException {
      private String message;
      private Throwable throwable;
      public BusinessException(String message) {

      1. this(message,null);

      }

      public BusinessException(String message,Throwable throwable) {

      1. super(message,throwable);

      }
      }

  • 定义异常拦截类 程序中抛出的所有异常都会被拦截然后统一输出,避免输出不友好的异常提示信息。

    package com.evan.except;

    import com.evan.Response;
    import org.springframework.util.CollectionUtils;
    import org.springframework.validation.ObjectError;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;

    import javax.validation.ConstraintViolation;
    import javax.validation.ConstraintViolationException;
    import java.util.List;
    import java.util.Set;

    /**

    • @author evanYang
    • @version 1.0
    • @date 04/11/2020 10:50
      */
      @ControllerAdvice
      @RestControllerAdvice
      public class GlobalExceptionHandler {
      @ExceptionHandler(Exception.class)
      public Response<?> handleException(Exception e) {

      1. return Response.error( e.getMessage());

      }

      /**

      • 拦截业务异常
        */
        @ExceptionHandler(BusinessException.class)
        public Response<?> handleBusinessException(BusinessException e) {
        return Response.error( e.getMessage());
        }

        /**

      • 拦截参数校验异常
        */
        @ExceptionHandler(MethodArgumentNotValidException.class)
        public Response<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException methodArgumentNotValidException) {
        StringBuilder errorMessage=new StringBuilder();
        List objectErrors=methodArgumentNotValidException.getBindingResult().getAllErrors();
        if (!CollectionUtils.isEmpty(objectErrors)) {

        1. for (int i = 0; i < objectErrors.size(); i++) {
        2. if (i == 0) {
        3. errorMessage.append(objectErrors.get(i).getDefaultMessage());
        4. } else {
        5. errorMessage.append(",");
        6. errorMessage.append(objectErrors.get(i).getDefaultMessage());
        7. }
        8. }

        }else {

        1. errorMessage.append("MethodArgumentNotValidException occured.");

        }
        return Response.error(“400”, errorMessage.toString(),null);
        }

        /**

      • 拦截自定义约束异常
        */
        @ExceptionHandler(ConstraintViolationException.class)
        public Response<?> handle(ConstraintViolationException constraintViolationException) {
        Set> violations = constraintViolationException.getConstraintViolations();
        String errorMessage = “”;
        if (!violations.isEmpty()) {
        1. StringBuilder builder = new StringBuilder();
        2. violations.forEach(violation -> builder.append(" " + violation.getMessage()));
        3. errorMessage = builder.toString();
        } else {
        1. errorMessage = "ConstraintViolationException occured.";
        }
        return Response.error(“400”, errorMessage,null);
        }
  1. }

这会我们再来看看我们的返回信息
在这里插入图片描述
最后文末附上GitHUb上的工程地址:GitHub项目链接

发表评论

表情:
评论列表 (有 0 条评论,11人围观)

还没有评论,来说两句吧...

相关阅读