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

news/2025/3/16 3:19:41/文章来源:https://www.cnblogs.com/javastack/p/18343185

作者:小塵
链接: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);@Autowiredprivate UserService userService;@Autowiredprivate AuthService authService;@PostMappingpublic 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);@Autowiredprivate UserService userService;@Autowiredprivate 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 CommonResultreturn 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最新版)

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/778135.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

delphi 导出到excel的7种方法

delphi 导出到excel的7种方法本文来自 爱好者8888 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/kpc2000/article/details/17066823?utm_source=copy ===================================================================================================第一种方…

codemirror diff-match-match 不同设备、不同设备状态下的对比结果不稳定

今天遇到一个问题,在使用codemirror对两条文本内容进行对比时,有同事反馈在它的电脑上会显示成:前面一半是正常显示差异内容,而后面就变成了全部是新增的。 像这样:预期的对比结果是这样:我们观察用于对比的两个文本,实际上上面的文本都是去掉后面括号中的内容,对比结果…

【YashanDB数据库】ycm托管数据库时报错OM host ip:127.0.0.1 is not support join to YCM

问题现象 托管数据库时检查报错OM的IP是127.0.0.1,不支持托管到YCMOM 问题的风险及影响 导致数据库无法托管监控 问题影响的版本问题发生原因 安装数据库时修改了OM的监听ip为127.0.0.1解决方法及规避方式 后台修改OM的ip为本机的ip或者0.0.0.0 问题分析和处理过程 1、修改env…

图像降噪算法概述

图像降噪是图像预处理中非常重要的一步,旨在去除图像中的噪声,以提高图像质量并为后续的图像分析提供更好的基础。图像降噪算法可以根据其原理和技术进行分类,主要包括以下几个大类: 1. 空域滤波方法 这些方法直接在像素级别上操作,通常涉及邻域内像素值的加权平均。均值…

面向零基础初学者的现代-C---教程-全-

面向零基础初学者的现代 C++ 教程(全)原文:Modern C++ for Absolute Beginners 协议:CC BY-NC-SA 4.0一、介绍 亲爱的读者: 恭喜你选择学习 C++ 编程语言,感谢你拿起这本书。我叫 Slobodan Dmitrovi,是一名软件开发人员和技术作家,我将尽我所能向您介绍一个 C++ 的美丽世…

面向-Windows-程序员的-C---软件互操作教程-全-

面向 Windows 程序员的 C++ 软件互操作教程(全)原文:C++ Software Interoperability for Windows Programmers 协议:CC BY-NC-SA 4.0一、准备 介绍 本章介绍了软件互操作性项目。我们先简要了解一下先决条件。接下来是项目概述。最后,我们描述了项目的主要组成部分以及它们…

Echarts 实现圆角环形图

第一种方式:使用 bar 实现 想要的效果:代码实现:const chartData = {title: {text: 97, // 圆环中间数字textStyle: {color: #222222,fontSize: 20,},subtext: 成功数,subtextStyle: {color: #222222,},itemGap: 10, // 主副标题距离left: center,top: center,},angleAxis: …

PlayCover Mac电脑全屏运行ios应用软件 for Mac免费下载

PlayCover是一款功能强大的软件,主要用于在Mac平台上运行iOS应用程序和Android应用程序(取决于具体版本)。对于iOS应用,PlayCover通过模拟iOS环境,让用户能够在Mac上直接运行iPhone和iPad应用,无需虚拟机或双重启动,支持多点触控、传感器模拟等特性,提供舒适的使用体验…

Android开发_android studio 重写类的方法

按快捷键 Ctrl+O,弹出以下对话框选择相应的方法。作者: CH520 出处: 博客园资源分享中心

《数据资产管理核心技术与应用》读书笔记-第一章:认识数据资产

《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,全书共分10章,第1章主要让读者认识数据资产,了解数据资产相关的基础概念,以及数据资产的发展情况。第2~8章主要介绍大数据时代数据资产管理所涉及的核心技术,内容包括元数据的采集与存储、数据血缘、数据质…