教你拥有一个优雅的 Controller

前言

很多开发都是把业务代码写在 controller 的,全是字段校验的 controller ,全是 try catch 的 controller,全是if-else的controller。看得蛋疼

蛋疼的controller

@RestController
@RequestMapping("/user/test")
@Slf4j(topic = "UserController ")
public class UserController {


    @Lazy
    @Resource
    UserService userService;

    @Lazy
    @Resource
    AuthService authService;

    @PostMapping("/userRegistration")
    public Result userRegistration(@RequestBody UserVo userVo) {
        if (StringUtils.isBlank(userVo.getUsername())){
            return Result.error("用户名不能为空");
        }
        if (StringUtils.isBlank(userVo.getPassword())){
            return Result.error("密码不能为空");
        }
        log.info("注册用户:{}" , userVo.getUsername());
        try {
            userService.registerUser(userVo.getUsername());
            return Result.ok();
        } catch (Exception e){
            log.error("注册失败:{}", userVo.getUsername(), e);
            return Result.error("注册失败");
        }
    }

    @PermitAll
    @ApiOperation("账号密码登录")
    @PostMapping("/login")
    public Result<AuthRespVO> login(@RequestBody AuthReqVO reqVO) {
        if (StringUtils.isBlank(reqVO.getUsername())){
            return Result.error("用户名不能为空");
        }
        if (StringUtils.isBlank(reqVO.getPassword())){
            return Result.error("密码不能为空");
        }
        try {
            return success(authService.login(reqVO));
        } catch (Exception e){
            log.error("注册失败:{}", reqVO.getUsername(), e);
            return CommonResult.error("注册失败");
        }
    }

}

优雅的controller

改进后

@RestController
@RequestMapping("/user/test")
@Slf4j(topic = "UserController")
public class UserController {


    @Autowired
    private UserService userService;

    @Autowired
    private AuthService authService;

    @PostMapping("/userRegistration")
    public Result userRegistration(@RequestBody @Valid UserVo userVo) {
        userService.registerUser(userVo.getUsername());
        return Result .ok();
    }

    
    @PermitAll
    @ApiOperation("使用账号密码登录")
    @PostMapping("/login")
    public Result<AuthRespVO> login(@RequestBody @Valid AuthReqVO reqVO) {
        return success(authService.login(reqVO));
    }

}

校验咋办?这个不能少呀!

也有使用这样的

Assert.notNull(userVo.getUsername(), "用户名不能为空");

实体类中

@ApiModel(value = "Request VO")
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserVo  {

    @ApiModelProperty(value = "账号", required = true, example = "username")
    @NotEmpty(message = "用户号不能为空")
    @Length(min = 4, max = 16, message = "用户号长度为 4-16 位")
    @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
    private String username;

    @ApiModelProperty(value = "密码", required = true, example = "password")
    @NotEmpty(message = "密码不能为空")
    @Length(min = 4, max = 16, message = "密码长度为 4-16 位")
    private String password;

}

@Valid

在SpringBoot中,@Valid是一个非常有用的注解,主要用于数据校验。以下是关于@Valid的一些详细信息:

  • 为什么使用 @Valid 来验证参数: 在编写接口时,我们经常需要验证请求参数。通常,我们可能会写大量的 if 和 if else 代码来进行判断。但这样的代码不仅不优雅,而且如果存在大量的验证逻辑,这会使代码看起来混乱,大大降低代码可读性。为了简化这个过程,我们可以使用 @Valid 注解来帮助我们简化验证逻辑。

  • @Validated与@Valid的区别: @Validated 是 @Valid 的变体。通过声明实体中属性的 groups ,再搭配使用 @Validated ,就能决定哪些属性需要校验,哪些不需要校验。

  • @Valid 注解的作用: @Valid 的主要作用是用于数据效验,可以在定义的实体中的属性上,添加不同的注解来完成不同的校验规则,而在接口类中的接收数据参数中添加 @valid 注解,这时你的实体将会开启一个校验的功能。

  • @Valid 的相关注解: 在实体类中不同的属性上添加不同的注解,就能实现不同数据的效验功能。

  • 使用 @Valid 进行参数效验步骤: 整个过程如下,用户访问接口,然后进行参数效验,因为 @Valid 不支持平面的参数效验(直接写在参数中字段的效验)所以基于 GET 请求的参数还是按照原先方式进行效验,而 POST 则可以以实体对象为参数,可以使用 @Valid 方式进行效验。如果效验通过,则进入业务逻辑,否则抛出异常,交由全局异常处理器进行处理。

添加全局异常

@ResponseBody
@RestControllerAdvice
@Slf4j(topic = "HandlerAdviceException")
public class HandlerAdviceException {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Object> handleValidationExceptions(MethodArgumentNotValidException ex) {
        log.error("[handleValidationExceptions]", ex);
        StringBuilder sb = new StringBuilder();
        ex.getBindingResult().getAllErrors().forEach(error -> {
            String fieldName = ((org.springframework.validation.FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            sb.append(fieldName).append(":").append(errorMessage).append(";");
        });
        return Result.error(sb.toString());
    }

    /**
     * @Description: 处理系统异常,兜底处理所有的一切
     * @param Throwable 入参
     * @return: Result
     * @Author: fan
     * @Date: 2024/5/16 09:51
     */
    @ExceptionHandler(value = Exception.class)
    public Result<?> defaultExceptionHandler(Throwable ex) {
        logger.error("[defaultExceptionHandler]", ex);
        // 返回 ERROR Result
        return Result.error(ErrorCode.getCode(), ErrorMsg.getMsg());
    }

}

相关推荐

  1. 拥有一个优雅 Controller

    2024-05-16 10:48:14       13 阅读
  2. 如何制作一个简单HTML个人网页】

    2024-05-16 10:48:14       21 阅读
  3. 如何制作一个简单HTML个人网页】

    2024-05-16 10:48:14       21 阅读
  4. Windows10中用Docker优雅拥有一个自己Linux环境

    2024-05-16 10:48:14       30 阅读
  5. 如何在 WebView 中实现优雅后退键处理

    2024-05-16 10:48:14       15 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-16 10:48:14       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-16 10:48:14       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-16 10:48:14       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-16 10:48:14       20 阅读

热门阅读

  1. 【分布式】zookeeper遇到问题与解决

    2024-05-16 10:48:14       13 阅读
  2. Kotlin高阶函数用法之一

    2024-05-16 10:48:14       11 阅读
  3. 谈谈 HTTP 的方法

    2024-05-16 10:48:14       11 阅读
  4. 面试 JVM 八股文十问十答第七期

    2024-05-16 10:48:14       14 阅读
  5. 12、24年--信息系统治理——IT治理

    2024-05-16 10:48:14       11 阅读
  6. verilog testbench-产生时钟复位

    2024-05-16 10:48:14       12 阅读