Controller层代码就该这么写,简洁又优雅
一个优秀的Controller层逻辑
说到 Controller,相信大家都不陌生,它可以很方便地对外提供数据接口。它的定位,我认为是「不可或缺的配角」,说它不可或缺是因为无论是传统的三层架构还是现在的COLA架构,Controller 层依旧有一席之地,说明他的必要性;说它是配角是因为 Controller 层的代码一般是不负责具体的逻辑业务逻辑实现,但是它负责接收和响应请求 从现状看问题
Controller 主要的工作有以下几项 接收请求并解析参数 调用 Service 执行具体的业务代码(可能包含参数校验) 捕获业务逻辑异常做出反馈 业务逻辑执行成功做出响应 //DTO @Data public class TestDTO { private Integer num; private String type; } //Service @Service public class TestService { public Double service(TestDTO testDTO) throws Exception { if (testDTO.getNum() <= 0) { throw new Exception("输入的数字需要大于0"); } if (testDTO.getType().equals("square")) { return Math.pow(testDTO.getNum(), 2); } if (testDTO.getType().equals("factorial")) { double result = 1; int num = testDTO.getNum(); while (num > 1) { result = result * num; num -= 1; } return result; } throw new Exception("未识别的算法"); } } //Controller @RestController public class TestController { private TestService testService; @PostMapping("/test") public Double test(@RequestBody TestDTO testDTO) { try { Double result = this.testService.service(testDTO); return result; } catch (Exception e) { throw new RuntimeException(e); } } @Autowired public DTOid setTestService(TestService testService) { this.testService = testService; } }
如果真的按照上面所列的工作项来开发 Controller 代码会有几个问题 参数校验过多地耦合了业务代码,违背单一职责原则 可能在多个业务中都抛出同一个异常,导致代码重复 各种异常反馈和成功响应格式不统一,接口对接不友好 改造 Controller 层逻辑统一返回结构
统一返回值类型无论项目前后端是否分离都是非常必要的,方便对接接口的开发人员更加清晰地知道这个接口的调用是否成功(不能仅仅简单地看返回值是否为 null 就判断成功与否,因为有些接口的设计就是如此),使用一个状态码、状态信息就能清楚地了解接口调用情况 //定义返回数据结构 public interface IResult { Integer getCode(); String getMessage(); } //常用结果的枚举 public enum ResultEnum implements IResult { SUCCESS(2001, "接口调用成功"), VALIDATE_FAILED(2002, "参数校验失败"), COMMON_FAILED(2003, "接口调用失败"), FORBIDDEN(2004, "没有权限访问资源"); private Integer code; private String message; //省略get、set方法和构造方法 } //统一返回数据结构 @Data @NoArgsConstructor @AllArgsConstructor public class Result { private Integer code; private String message; private T data; public static Result success(T data) { return new Result<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage(), data); } public static Result success(String message, T data) { return new Result<>(ResultEnum.SUCCESS.getCode(), message, data); } public static Result<?> failed() { return new Result<>(ResultEnum.COMMON_FAILED.getCode(), ResultEnum.COMMON_FAILED.getMessage(), null); } public static Result<?> failed(String message) { return new Result<>(ResultEnum.COMMON_FAILED.getCode(), message, null); } public static Result<?> failed(IResult errorResult) { return new Result<>(errorResult.getCode(), errorResult.getMessage(), null); } public static Result instance(Integer code, String message, T data) { Result result = new Result<>(); result.setCode(code); result.setMessage(message); result.setData(data); return result; } }
统一返回结构后,在 Controller 中就可以使用了,但是每一个 Controller 都写这么一段最终封装的逻辑,这些都是很重复的工作,所以还要继续想办法进一步处理统一返回结构 统一包装处理
Spring 中提供了一个类 ResponseBodyAdvice ,能帮助我们实现上述需求
ResponseBodyAdvice 是对 Controller 返回的内容在 HttpMessageConverter 进行类型转换之前拦截,进行相应的处理操作后,再将结果返回给客户端。那这样就可以把统一包装的工作放到这个类里面。 public interface ResponseBodyAdvice { boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType); @Nullable T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response); } supports:判断是否要交给 beforeBodyWrite 方法执行,ture:需要;false:不需要 beforeBodyWrite:对 response 进行具体的处理 // 如果引入了swagger或knife4j的文档生成组件,这里需要仅扫描自己项目的包,否则文档无法正常生成 @RestControllerAdvice(basePackages = "com.example.demo") public class ResponseAdvice implements ResponseBodyAdvice
出口疲软下如何提振国内经济大家都知道,提振经济的三驾马车是出口贸易内部消费建设投资。在过去改革开放40年中,对我国经济发展起重要作用的,是对外出口贸易。对外出口总值从1995年的1487。7亿美元,上升至截
(两会声音)全国人大代表马忠俊把文山打造成名副其实的世界三七之都中新网北京3月5日电(记者黄钰钦)全国人大代表云南省文山壮族苗族自治州州长马忠俊近日接受记者采访时表示,文山是中国三七之乡,将加快三七与旅游康养融合发展,开发三七大健康产业,做强三
豆校长完成A轮5000万元融资每食宝完成天使轮融资近期消费大事件,新鲜事儿起底大爆料!1星巴克任命ShellyRanus为代理首席道德与合规官3月2日,据彭博社报道,星巴克已聘请其公司律师之一ShellyRanus担任代理首席道德
这就是信心丨促消费稳外贸引外资助力商务高质量发展消费市场基本稳定外贸规模再创新高多双边经贸合作实现新突破3月2日,国新办举行权威部门话开局系列主题新闻发布会,介绍了我国推动商务高质量发展迈出新步伐的有关情况。商务工作是国内大循环
甘肃省临夏市打造青年人的理想之城中国青年报客户端讯(中青报中青网记者王豪马富春)近年来,在宜居宜学宜商宜游城市发展目标下,甘肃省临夏回族自治州临夏市委市政府精准规划多措并举积极打造青年发展型县域,吸引诸多青年来临
江浩然委员改革成果人民共享共享发展关系着人民群众能顺利享受发展成果,保证人民群众成为改革发展最普遍的受益群体,是中国式现代化的重要体现。全国政协委员恒银金融科技股份有限公司董事长江浩然表示,我国坚持全面深化
单季度业绩下滑,经营现金净流入减少,恩捷股份背得动百亿负债吗?3月3日,恩捷股份(002812。SZ)低开低走,当日报收117。31元股,跌幅2。09,这一股价已接近恩捷股份近两年的最低点。前一日晚间,恩捷股份发布了2022年年报,公司营收净
乙二醇短期盈利承压进口依赖改善明显本报记者陈家运北京报道乙二醇行业短期弱势难改,但相关企业的投资热情依旧不减。金联创数据显示,截至2月23日,油制乙二醇利润为190。2美元吨,较1月下跌27。7美元吨煤制乙二醇利润
追寻雷锋丨像春天般温暖今年是毛泽东等老一辈革命家为雷锋同志题词60周年。60年来,学雷锋活动在全国持续深入开展,雷锋的名字家喻户晓,雷锋的事迹深入人心,雷锋精神滋养着一代代中华儿女的心灵。特别策划追寻雷
两会湘声邹彬大力弘扬工匠精神推动质量强国建设视频加载中全国人大代表中国建筑第五工程局总承包公司项目质量总监邹彬。红网时刻新闻记者王嫣任晔摄影杨抒怀陈杰报道当前,推进中国式现代化,进一步服务产业工人转型,弘扬工匠精神,对于推动
售价不过20的牛栏山,明明都知道是酒精酒,为何还能年销量超百亿在白酒界能真正意义上做到百姓的口粮酒,恐怕只有牛栏山了吧。毕竟是唯一一个能将酒精酒卖到上百亿销量,足以证明酒友们对其喜爱之深。而且还有一个特别奇怪的现象,那就是许多人喝着牛栏山的时