首页 > 其他分享 >【禁止血压飙升】阿里大佬写的 Controller 太优雅了!

【禁止血压飙升】阿里大佬写的 Controller 太优雅了!

时间:2024-08-05 14:38:28浏览次数:9  
标签:校验 CommonResult controller 优雅 Controller Valid error return 大佬

作者:小塵
链接:https://juejin.cn/post/7357172505961578511

前言

见过几千行代码的 controller吗?我见过。

见过全是 try catch 的 controller 吗,我见过。

见过全是字段校验的 controller 吗,我见过。

见过全是业务代码的 controller 吗?不好意思,我们公司很多业务写在 controller 的。

看见这些我真的血压高。

正文

不优雅的 controller

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

    private static Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserService userService;

    @Autowired
    private AuthService authService;

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

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

}

Spring Boot 基础就不介绍了,推荐看这个实战项目:

https://github.com/javastacks/spring-boot-best-practice

优雅的controller

@RestController
@RequestMapping("/user/test")
public class UserController1 {

    private static Logger logger = LoggerFactory.getLogger(UserController1.class);

    @Autowired
    private UserService userService;

    @Autowired
    private AuthService authService;

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

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

}

代码量直接减一半呀,这还不算上有些直接把业务逻辑写在 controller 的,看到这些我真的直接吐血

改造流程

校验方式

这个 if 校验看得我哪哪都不爽。好歹给我写一个断言吧。Assert.notNull(userVo.getUsername(), "用户名不能为空");

这不香吗?确实不香。

使用 spring 提供的@Valid

在入参时使用@Valid注解,并且在 vo 中使用校验注解,如AuthLoginReqVO

@ApiModel(value = "管理后台 - 账号密码登录 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthLoginReqVO {

    @ApiModelProperty(value = "账号", required = true, example = "user")
    @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的一些详细信息:

  1. 为什么使用 @Valid 来验证参数:在编写接口时,我们经常需要验证请求参数。通常,我们可能会写大量的 if 和 if else 代码来进行判断。但这样的代码不仅不优雅,而且如果存在大量的验证逻辑,这会使代码看起来混乱,大大降低代码可读性。为了简化这个过程,我们可以使用 @Valid 注解来帮助我们简化验证逻辑。
  2. @Valid 注解的作用:@Valid 的主要作用是用于数据效验,可以在定义的实体中的属性上,添加不同的注解来完成不同的校验规则,而在接口类中的接收数据参数中添加 @valid 注解,这时你的实体将会开启一个校验的功能。
  3. @Valid 的相关注解:在实体类中不同的属性上添加不同的注解,就能实现不同数据的效验功能。
  4. 使用 @Valid 进行参数效验步骤:整个过程如下,用户访问接口,然后进行参数效验,因为 @Valid 不支持平面的参数效验(直接写在参数中字段的效验)所以基于 GET 请求的参数还是按照原先方式进行效验,而 POST 则可以以实体对象为参数,可以使用 @Valid 方式进行效验。如果效验通过,则进入业务逻辑,否则抛出异常,交由全局异常处理器进行处理。
  5. @Validated与@Valid的区别@Validated@Valid 的���体。通过声明实体中属性的 groups ,再搭配使用 @Validated ,就能决定哪些属性需要校验,哪些不需要校验。

全局异常处理

这个全局异常处理,可以根据自己的异常,自定义异常处理,并设置一个兜底的异常处理

@ResponseBody
@RestControllerAdvice
public class ExceptionHandlerAdvice {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public CommonResult<Object> handleValidationExceptions(MethodArgumentNotValidException ex) {
        logger.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 CommonResult.error(sb.toString());
    }

    /**
     * 处理系统异常,兜底处理所有的一切
     */
    @ExceptionHandler(value = Exception.class)
    public CommonResult<?> defaultExceptionHandler(Throwable ex) {
        logger.error("[defaultExceptionHandler]", ex);
        // 返回 ERROR CommonResult
        return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg());
    }

}

就这么多,搞定,这样就拥有了漂流优雅的 controller 了

在日常开发中,还有那些血压飙升瞬间

我拿出下图阁下如何面对

这个阁下又如何面对,我不说,你能知道这个什么吗【狗头】

总结

  • 不是很明白为什么有些喜欢在 controller 写业务逻辑的,曾经有个同事问我(就是喜欢在 controller 写业务的),你这个接口写在那里,我需要调一下你这个接口。我满脸问号??不是隔壁的模块吗,为什么要调我的接口?直接引用的我的 service 去调方法就好了。
  • 这个就是痛点,各写各的,冗余代码一堆。
  • 曾经看到一个同事写一个保存的方法,虽然逻辑挺多,我滑动了好久都还没有方法还没有结束。一个方法整整几百行……
  • 看过 spring 源码都知道,spring 源码难啃,就是因为 spring 无限往下套娃,基本每个方法干每个方法的事情。比如我保存用户时,就只是保存用户,至于什么校验丢给校验的方法处理,什么发送消息丢给发送消息处理,这些就不能耦合在一起。
  • 对于看到一些 if 下面一丢逻辑,然后 if 再一丢逻辑,看代码时很多情况不需要知道这个逻辑怎么实现的,知道入参出参就大概这里做什么了。即使想知道详细情况点进去就知道了。突出这个当前方法要做的事情就好了。
  • 阿里的开发手册就推荐一个方法不能超过 80 行,超过可以根据业务具体调整一下。在公众号Java核心技术回复手册可以获取最新完整高清版。

更多文章推荐:

1.Spring Boot 3.x 教程,太全了!

2.2,000+ 道 Java面试题及答案整理(2024最新版)

3.免费获取 IDEA 激活码的 7 种方式(2024最新版)

觉得不错,别忘了随手点赞+转发哦!

标签:校验,CommonResult,controller,优雅,Controller,Valid,error,return,大佬
From: https://www.cnblogs.com/javastack/p/18343185

相关文章

  • 推荐一款界面优雅、功能强大的 .NET + Vue 权限管理系统
    前言今天推荐一款用.NET和Vue3实现的开源权限管理系统。它的界面清爽干净,功能强大,还具备灵活的角色权限分配功能,能够满足不同规模企业的管理需求。无论你是开发新手还是大神,都能轻松上手,快速搭建起自己的权限管理体系。别再犹豫了,赶快来试试吧!项目简介Malus是海棠的意思,顾......
  • 分享一个大佬写的界面跳转
    这是Prism框架开发者写的一个demo,我觉得有趣,就发出来让大家看看<StackPanel><StackPanelOrientation="Horizontal"><Buttonx:Name="AnimationButton"Click="AnimationButton_Click"Content="Animation"Background=&qu......
  • 到底什么是@RestController
    @RestController是Spring框架的一个注解,通常用于标识一个类是RESTful服务的Controller。@RestController经常用来处理HTTP请求,是SpringMVC中用于构建RESTfulWeb服务的注解,是@Controller注解的变体通过@RestController注解,SpringMVC可以识别出这个类是一个控制器这个类里面的方......
  • 使用Aspire优雅的进行全栈开发——WinUI使用Semantic Kernel调用智普清言LLM总结Asp.N
    前言这算是一篇学习记录博客了,主要是学习语义内核(SemanticKernel)的实践,以及Aspire进行全栈开发的上手体验,我是采用Aspire同时启动API服务,Blazor前端服务以及WinUI的桌面端项目,同时进行三个项目的代码修改,整体感觉很方便,如果代码都修改了只需要启动Aspire项目,不用每个项目单独起......
  • 【今日曝光】员工恶意删除文件怎么办?企业大佬这样解决
    面对突如其来的挑战总是需要智慧与决断。近日,一起员工恶意删除公司重要文件的事件引发了广泛关注,这不仅考验着企业的应急响应能力,更促使我们深思如何构建更加稳固的数据防护体系。今天,就让我们跟随企业大佬的步伐,一探他们是如何高效解决这一棘手问题的。迅速评估,冷静应对......
  • 如何优雅地重装系统:使用Ventoy实现系统安装All In One
    在日常工作和学习中,我们偶尔会面临需要在一台电脑上测试或使用多个操作系统的场景。传统的解决方案是制作多个启动盘或者使用PE,不仅耗时而且管理不便。那么如何高效地在同一USB盘上实现多个系统镜像引导的统一集成呢?Ventoy提供了一个创新的解决方案。它允许用户在一个USB......
  • 编程技巧:如何优雅地合并两个有序数组?
    目录题目引用描述1.直接合并排序2.指针3.后逆向双指针进阶:你可以设计实现一个时间复杂度为O(m+n)的算法解决此问题吗?总结题目来自力扣引用合并两个有序数组给你两个按**非递减顺序**排列的整数数组nums1和nums2,另有两个整数m和n,分别表示nums1......
  • 如何优雅的应对线上故障?
    知识星球有同学遇到了这样一个问题:背景:线上抽奖活动,奖品价格与需求不符,产生了资损;根因:团队惯例全链路人员都负责,新来的产品认为事故与其无关;问题:内部为这个故障担责问题争论较大,作为测试负责人该如何应对?这是很典型的一个职场案例,基本上每个技术同学在工作中或多或少都会遇......
  • 哪位大佬知道为啥最后计数是0吗? 实际是有数据的
    大家好,我是Python进阶者。一、前言前几天在Python白银交流群【JethroShen】问了一个Python数据处理的问题,问题如下:哪位大佬知道为啥最后计数是0吗?实际是有数据的二、实现过程这里【瑜亮老师】给了一个指导,如下所示:这不是发生错误了么?你设置的发生错误return0,它肯定变成0了......
  • 在 Python 中创建和/或检查编号变量的优雅方法
    我是一个试图学习Python的老家伙,所以我最后的编码经验是使用BASIC-不,不是VisualBasic。我理解一些与Python相关的概念,但我处于初级编码阶段,所以我使用“强力”逻辑编写了这个项目-基本上,将字符串分解为单个字母,然后用经典的“”测试每个字母猜单词类型的游戏。......