当前位置: 首页 > news >正文

Controller 层优化四步曲

Controller 层优化四步曲

前言

在开发过程中,Controller 层作为系统与外界交互的桥梁,承担着接收请求、解析参数、调用业务逻辑、处理异常等职责。

然而,随着业务复杂度的增加,Controller 层的代码往往会变得臃肿且难以维护。

为了提升代码的可读性、可维护性以及系统的健壮性,我们可以通过以下四个步骤对 Controller 层进行改造:

  1. 统一返回结构
  2. 统一包装处理
  3. 参数校验
  4. 自定义异常与统一拦截异常

1.统一返回结构

在前后端分离的架构中,统一的返回结构能够显著提升接口的可读性和可维护性。

通过定义统一的返回格式,前端开发人员可以更清晰地判断接口调用是否成功,而不需要依赖返回值的具体内容。

定义返回数据结构

首先,我们可以定义一个通用的返回结构,包含状态码、状态信息以及返回的数据。

以下是一个示例:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {private Integer code;private String message;private T data;public static <T> Result<T> success(T data) {return new Result<>(200, "操作成功", data);}public static <T> Result<T> error(String message) {return new Result<>(500, message, null);}
}

在这个结构中,code 表示状态码,message 表示状态信息,data 则是具体的返回数据。

通过这种方式,所有的接口都可以返回统一的格式,便于前端处理。

2.统一包装处理

为了进一步简化 Controller 层的代码,我们可以使用 Spring 提供的 ResponseBodyAdvice 来统一处理返回值的包装。

这样,Controller 层只需要返回业务数据,而不需要手动封装返回结构。

使用 ResponseBodyAdvice 进行统一包装

@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,Class<? extends HttpMessageConverter<?>> selectedConverterType,ServerHttpRequest request, ServerHttpResponse response) {if (body instanceof Result) {return body;}return Result.success(body);}
}

通过这种方式,所有的 Controller 返回值都会被自动包装成 Result 对象,减少了重复代码。

3. 参数校验

参数校验是保证系统健壮性的重要手段。通过将参数校验逻辑从业务代码中剥离出来,不仅可以减少代码的耦合度,还能提升代码的可读性。

使用 @Validated 进行参数校验

Spring 提供了 @Validated 注解,可以方便地对请求参数进行校验。

我们可以在 DTO 对象中定义校验规则,并在 Controller 方法中使用 @Validated 注解进行校验。

@Data
public class UserDTO {@NotBlank(message = "用户名不能为空")private String username;@NotBlank(message = "密码不能为空")@Length(min = 6, max = 20, message = "密码长度必须在6到20之间")private String password;@Email(message = "邮箱格式不正确")private String email;
}@RestController
@RequestMapping("/user")
public class UserController {@PostMapping("/register")public Result<String> register(@RequestBody @Validated UserDTO userDTO) {// 业务逻辑return Result.success("注册成功");}
}

通过这种方式,参数校验的逻辑与业务逻辑完全解耦,代码更加清晰。

自定义异常与统一拦截异常

在实际开发中,系统可能会抛出各种异常。

为了提升系统的健壮性,我们可以自定义异常,并通过统一的异常拦截器来处理这些异常。

自定义异常

我们可以根据业务需求定义不同的异常类,例如 BusinessExceptionForbiddenException

public class BusinessException extends RuntimeException {public BusinessException(String message) {super(message);}
}public class ForbiddenException extends RuntimeException {public ForbiddenException(String message) {super(message);}
}

统一异常拦截

通过 @RestControllerAdvice@ExceptionHandler,我们可以统一处理系统中的异常,并返回统一的错误信息。

@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(BusinessException.class)public Result<String> handleBusinessException(BusinessException ex) {return Result.error(ex.getMessage());}@ExceptionHandler(ForbiddenException.class)public Result<String> handleForbiddenException(ForbiddenException ex) {return Result.error("无权访问");}@ExceptionHandler(Exception.class)public Result<String> handleException(Exception ex) {return Result.error("系统异常,请稍后重试");}
}

通过这种方式,所有的异常都会被统一处理,并返回给前端统一的错误格式。

总结

通过对 Controller 层的改造,我们可以显著提升代码的可读性、可维护性以及系统的健壮性。

统一的返回结构、自动化的参数校验、自定义异常与统一拦截异常,这些措施不仅减少了重复代码,还使得代码更加清晰和易于维护。

在实际开发中,我们可以根据具体的业务需求,进一步优化和扩展这些策略。

– 欢迎点赞、关注、转发、收藏【我码玄黄】,各大平台同名。

相关文章:

Controller 层优化四步曲

Controller 层优化四步曲 前言 在开发过程中&#xff0c;Controller 层作为系统与外界交互的桥梁&#xff0c;承担着接收请求、解析参数、调用业务逻辑、处理异常等职责。 然而&#xff0c;随着业务复杂度的增加&#xff0c;Controller 层的代码往往会变得臃肿且难以维护。 …...

Python数据分析-Python语法基础,IPython和Jupyter-Notebooks(二)

title: ‘Python数据分析:Python语法基础&#xff0c;IPython和Jupyter Notebooks&#xff08;二&#xff09;’ tags: python数据分析 categories:python数据分析 keywords:python数据分析 cover: …/img/404_icecream_whale.png description: 本文介绍python的基础语法和jup…...

Nginx 开发总结

文章目录 1. Nginx 基础概念1-1、什么是 Nginx1-2、Nginx 的工作原理1-3、Nginx 的核心特点1-4、Nginx 的常见应用场景1-5、Nginx 与 Apache 的区别1-6、 Nginx 配置的基本结构1-7、Nginx 常见指令 2. Nginx 配置基础2-1、Nginx 配置文件结构2-2、全局配置 (Global Block)2-3、…...

centos7安装SVN

[rootVM-16-3-centos ~]# yum install subversion -y [rootVM-16-3-centos ~]# svnserve --version // 创建目录 [rootVM-16-3-centos ~]# mkdir -p /opt/svn/repos // 创建新的空版本库&#xff0c;执行后会在repos文件夹下建立多个文件&#xff0c;待修改 [rootVM-16-3-cento…...

LTV预估 | 多视角对比学习框架CMLTV

&#x1f604; cmltv的loss好多哟&#xff0c;花样好多哟&#xff5e; 文章目录 1 精简总结2 背景&挑战3 方法4 实验 ✅【arxiv-2023 华为 CMLTV】《Contrastive Multi-view Framework for Customer Lifetime Value Prediction》 论文链接&#xff1a; https://arxiv.or…...

llama.cpp LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK2

llama.cpp LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK2 1. LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK22. LLM_ARCH_DEEPSEEK and LLM_ARCH_DEEPSEEK23. struct ggml_cgraph * build_deepseek() and struct ggml_cgraph * build_deepseek2()References 不宜吹捧中国大语言模型的同…...

C语言自定义数据类型详解(二)——结构体类型(下)

书接上回&#xff0c;前面我们已经给大家介绍了如何去声明和创建一个结构体&#xff0c;如何初始化结构体变量等这些关于结构体的基础知识。下面我们将继续给大家介绍和结构体有关的知识&#xff1a; 今天的主题是&#xff1a;结构体大小的计算并简单了解一下位段的相关知识。…...

DeepSeek学术写作测评第二弹:数据分析、图表解读,效果怎么样?

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 针对最近全球热议的DeepSeek开源大模型&#xff0c;娜姐昨天分析了关于论文润色、中译英的详细效果测评&#xff1a; DeepSeek学术写作测评第一弹&#xff1a;论文润色&#…...

深入理解 Python 中的 `__all__`:控制模块的公共接口

在 Python 编程中&#xff0c;模块化设计是构建可维护和可扩展代码的关键。模块不仅帮助我们组织代码&#xff0c;还能通过隐藏实现细节来提高代码的可读性和安全性。Python 提供了多种机制来控制模块的可见性&#xff0c;其中 __all__ 是一个非常重要但常被忽视的特性。本文将…...

虚幻基础07:蓝图接口

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录 作用原理事件函数 作用 实现对象间的通知。 A 通知 B 做什么。 原理 将接口抽象为蓝图&#xff0c;使得任意蓝图都能直接访问。 只需要再传入对象地址&#xff0c;就能执行对象的功能。 事件 黄色&#xff1a;…...

数据结构---哈希表

基本概念 哈希函数&#xff08;Hash Function&#xff09;是一种将输入的数据&#xff08;通常是任意大小的&#xff09;映射到固定大小的输出&#xff08;通常是一个固定长度的值&#xff09;的函数。这个输出值通常称为“哈希值”&#xff08;Hash Value&#xff09;或“哈希…...

DataWhale组队学习 leetCode task4

1. 滑动窗口算法介绍 想象你正在用一台望远镜观察一片星空。望远镜的镜头大小是固定的&#xff0c;你可以通过滑动镜头来观察不同的星区。滑动窗口算法就像这台望远镜&#xff0c;它通过一个固定或可变大小的“窗口”来观察数组或字符串中的连续区间。 滑动操作&#xff1a;就像…...

【ESP32】ESP-IDF开发 | WiFi开发 | UDP用户数据报协议 + UDP客户端和服务器例程

1. 简介 UDP协议&#xff08;User Datagram Protocol&#xff09;&#xff0c;全称用户数据报协议&#xff0c;它是一种面向非连接的协议&#xff0c;面向非连接指的是在正式通信前不必与对方先建立连接&#xff0c; 不管对方状态就直接发送。至于对方是否可以接收到这些数据内…...

【PyQt5】数据库连接失败: Driver not loaded Driver not loaded

报错内容如下&#xff1a; 可以看到目前所支持的数据库驱动仅有[‘QSQLITE’, ‘QMARIADB’, ‘QODBC’, ‘QODBC3’, ‘QPSQL’, ‘QPSQL7’] 我在网上查找半天解决方法未果&#xff0c;其中有一篇看评论反馈是可以使用的&#xff0c;但是PyQt5的版本有点低&#xff0c;5.12…...

Unity游戏(Assault空对地打击)开发(1) 创建项目和选择插件

目录 前言 创建项目 插件导入 地形插件 前言 这是游戏开发第一篇&#xff0c;进行开发准备。 创作不易&#xff0c;欢迎支持。 我的编辑器布局是【Tall】&#xff0c;建议调整为该布局&#xff0c;如下。 创建项目 首先创建一个项目&#xff0c;过程略&#xff0c;名字请勿…...

Rust:如何动态调用字符串定义的 Rhai 函数?

在 Rust 中使用 Rhai 脚本引擎时&#xff0c;你可以动态地调用传入的字符串表示的 Rhai 函数。Rhai 是一个嵌入式脚本语言&#xff0c;专为嵌入到 Rust 应用中而设计。以下是一个基本示例&#xff0c;展示了如何在 Rust 中调用用字符串传入的 Rhai 函数。 首先&#xff0c;确保…...

A星算法两元障碍物矩阵转化为rrt算法四元障碍物矩阵

对于a星算法obstacle所表示的障碍物障碍物信息&#xff0c;每行表示一个障碍物的坐标&#xff0c;例如2 , 3; % 第一个障碍物在第二行第三列&#xff0c;也就是边长为1的正方形障碍物右上角横坐标是2&#xff0c;纵坐标为3&#xff0c;障碍物的宽度和高度始终为1.在rrt路径规划…...

【C++】设计模式详解:单例模式

文章目录 Ⅰ. 设计一个类&#xff0c;不允许被拷贝Ⅱ. 请设计一个类&#xff0c;只能在堆上创建对象Ⅲ. 请设计一个类&#xff0c;只能在栈上创建对象Ⅳ. 请设计一个类&#xff0c;不能被继承Ⅴ. 请设计一个类&#xff0c;只能创建一个对象&#xff08;单例模式&#xff09;&am…...

单细胞分析基础-第一节 数据质控、降维聚类

scRNA_pipeline\1.Seurat 生物技能树 可进官网查询 添加链接描述 分析流程 准备:R包安装 options("repos"="https://mirrors.ustc.edu.cn/CRAN/") if(!require("BiocManager")) install.packages("BiocManager",update = F,ask =…...

多项日常使用测试,带你了解如何选择AI工具 Deepseek VS ChatGpt VS Claude

多项日常使用测试&#xff0c;带你了解如何选择AI工具 Deepseek VS ChatGpt VS Claude 注&#xff1a;因为考虑到绝大部分人的使用&#xff0c;我这里所用的模型均为免费模型。官方可访问的。ChatGPT这里用的是4o Ai对话&#xff0c;编程一直以来都是人们所讨论的话题。Ai的出现…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

DAY 26 函数专题1

函数定义与参数知识点回顾&#xff1a;1. 函数的定义2. 变量作用域&#xff1a;局部变量和全局变量3. 函数的参数类型&#xff1a;位置参数、默认参数、不定参数4. 传递参数的手段&#xff1a;关键词参数5 题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一…...