您现在的位置是:亿华云 > IT科技类资讯

后端思维篇:统一参数校验、异常处理、结果返回

亿华云2025-10-03 06:33:31【IT科技类资讯】2人已围观

简介前言大家好,我是捡田螺的小男孩。今天这篇比较简单~。日常工作中,我们开发接口时,一般都会涉及到参数校验、异常处理、封装结果返回等处理。如果每个后端开发在参数校验、异常处理等都是各写各的,没有统一处理的

前言

大家好,后端我是篇统捡田螺的小男孩。

今天这篇比较简单~。参数处理日常工作中,校验我们开发接口时,异常一般都会涉及到参数校验、结果异常处理、后端封装结果返回等处理。篇统

后端思维篇:统一参数校验、异常处理、结果返回

如果每个后端开发在参数校验、参数处理异常处理等都是校验各写各的,没有统一处理的异常话,代码就不优雅,结果也不容易维护。后端所以,篇统作为一名合格的参数处理后端开发工程师,我们需要统一校验参数,统一异常处理、统一结果返回,让代码更加规范、可读性更强、更容易维护。

后端思维篇:统一参数校验、异常处理、结果返回

1. 使用注解,统一参数校验

假设小田螺实现一个注册用户的功能,在controller 层,他会先进行校验参数,如下:

后端思维篇:统一参数校验、异常处理、结果返回

@RestController

@RequestMapping

public class UserController {

@RequestMapping("addUser")

public String addUser(UserParam userParam) {

if (StringUtils.isEmpty(userParam.getUserName())) {

return "用户名不能为空";

}

if (StringUtils.isEmpty(userParam.getPhone())) {

return "手机号不能为空";

}

if (userParam.getPhone().length() > 11) {

return "手机号不能超过11";

}

if (StringUtils.isEmpty(userParam.getEmail())) {

return "邮箱不能为空";

}

//省略其他参数校验

//todo 插入用户信息表

return "SUCCESS";

}

}

以上代码有什么问题嘛?其实没什么问题,就是云服务器提供商校验有点辣眼睛。正常的添加用户业务还没写,参数校验就一大堆啦。假设后来,小田螺又接了一个需求:编辑用户信息。实现编辑用户信息前,也是先校验信息,如下:

@RequestMapping("editUser")

public String editUser(UserParam userParam) {

if (StringUtils.isEmpty(userParam.getUserName())) {

return "用户名不能为空";

}

if (StringUtils.isEmpty(userParam.getPhone())) {

return "手机号不能为空";

}

if (userParam.getPhone().length() > 11) {

return "手机号不能超过11";

}

if (StringUtils.isEmpty(userParam.getEmail())) {

return "邮箱不能为空";

}

//省略其他参数校验

//todo 编辑用户信息表

return "SUCCESS";

}

我们可以使用注解的方式,来进行参数校验,这样代码更加简洁,也方便统一管理。实际上, spring

boot有个validation的组件,我们可以拿来即用。引入这个包即可:

org.springframework.boot

spring-boot-starter-validation

</dependency>

引入包后,参数校验就非常简洁啦,如下:

public class UserParam {

@NotNull(message = "用户名不能为空")

private String userName;

@NotNull(message = "手机号不能为空")

@Max(value = 11)

private String phone;

@NotNull(message = "邮箱不能为空")

private String email;

然后在UserParam参数对象中,加入@Validated注解哈,把错误信息接收到BindingResult对象,代码如下:

@RequestMapping("addUser")

public String addUser(@Validated UserParam userParam, BindingResult result) {

ListfieldErrors = result.getFieldErrors();

if (!fieldErrors.isEmpty()) {

return fieldErrors.get(0).getDefaultMessage();

}

//todo 插入用户信息表

return "SUCCESS";

}2. 接口统一响应对象返回

如果你在你们项目代码中,看到controller 层报文返回结果,有这样的:

@RequestMapping("/hello")

public String getStr(){

return "hello,捡田螺的小男孩";

}

//返回

hello,捡田螺的小男孩

也有这样的:

@RequestMapping("queryUser")

public UserVo queryUser(String userId) {

return new UserVo("666", "捡田螺的小男孩");

}

//返回:

{ "userId":"666","name":"捡田螺的小男孩"}

显然,如果接口返回结果不统一,香港云服务器前端处理就不方便,我们代码也不好维护。再比如小田螺喜欢用Result处理结果,大田螺喜欢用Response处理结果,可以想象一下,这些代码有多乱。

所以作为后端开发,我们项目的响应结果,需要统一标准的返回格式。一般一个标准的响应报文对象,都有哪些属性呢?

code :响应状态码message :响应结果描述data:返回的数据

响应状态码一般用枚举表示哈:

public enum CodeEnum {

/**操作成功**/

SUCCESS("0000","操作成功"),

/**操作失败**/

ERROR("9999","操作失败"),;

/

**

* 自定义状态码

**/

private String code;

/**自定义描述**/

private String message;

CodeEnum(String code, String message){

this.code = code;

this.message = message;

}

public String getCode() {

return code;

}

public String getMessage() {

return message;

}

}

因为返回的数据类型不是确定的,我们可以使用泛型,如下:

/

**

* @author 捡田螺的小男孩

* @param

*/

public class BaseResponse{

/

**

* 响应状态码(0000表示成功,9999表示失败

*/

private String code;

/

**

* 响应结果描述

*/

private String message;

/

**

* 返回的数据

*/

private T data;

/

**

* 成功返回

* @param data

* @param

* @return

*/

public static BaseResponsesuccess(T data) {

BaseResponseresponse= new BaseResponse<>();

response.setCode(CodeEnum.SUCCESS.getCode());

response.setMessage(CodeEnum.SUCCESS.getMessage());

response.setData(data);

return response;

}

/

**

* 失败返回

* @param code

* @param message

* @param

* @return

*/

public static BaseResponsefail(String code, String message) {

BaseResponseresponse = new BaseResponse<>();

response.setCode(code);

response.setMessage(message);

return response;

}

public void setCode(String code) {

this.code = code;

}

public void setMessage(String message) {

this.message = message;

}

public void setData(T data) {

this.data = data;

}

}

有了统一的响应体,我们就可以优化一下controller 层的代码啦:

@RequestMapping("/hello")

public BaseResponsegetStr(){

return BaseResponse.success("hello,捡田螺的小男孩");

}

//output

{ "code":"0000","message":"操作成功","data":"hello,捡田螺的小男孩"}

@RequestMapping("queryUser")

public BaseResponsequeryUser(String userId) {

return BaseResponse.success(new UserVo("666", "捡田螺的小男孩"));

}

//output

{ "code":"0000","message":"操作成功","data":{ "userId":"666","name":"捡田螺的小男孩"}}3. 统一异常处理

日常开发中,我们一般都是自定义统一的异常类,云南idc服务商如下:

public class BizException extends RuntimeException {

private String retCode;

private String retMessage;

public BizException() {

super();

}

public BizException(String retCode, String retMessage) {

this.retCode = retCode;

this.retMessage = retMessage;

}

public String getRetCode() {

return retCode;

}

public String getRetMessage() {

return retMessage;

}

}

在controller 层,很可能会有类似代码:

@RequestMapping("/query")

public BaseResponsequeryUserInfo(UserParam userParam) {

try {

return BaseResponse.success(userService.queryUserInfo(userParam));

} catch (BizException e) {

//doSomething

} catch (Exception e) {

//doSomething

}

return BaseResponse.fail(CodeEnum.ERROR.getCode(),CodeEnum.ERROR.getMessage());

}

这块代码,没什么问题哈,但是如果try...catch太多,不是很优雅。

可以借助注解@RestControllerAdvice,让代码更优雅。@RestControllerAdvice是一个应用于Controller层的切面注解,它一般配合@ExceptionHandler注解一起使用,作为项目的全局异常处理。我们来看下demo代码哈。

还是原来的UserController,和一个会抛出异常的userService的方法,如下:

@RestController

public class UserController {

@Autowired

private UserService userService;

@RequestMapping("/query")

public BaseResponsequeryUserInfo1(UserParam userParam) {

return BaseResponse.success(userService.queryUserInfo(userParam));

}

}

@Service

public class UserServiceImpl implements UserService {

//抛出异常

@Override

public UserVo queryUserInfo(UserParam userParam) throws BizException {

throw new BizException("6666", "测试异常类");

}

}

我们再定义一个全局异常处理器,用@RestControllerAdvice注解,如下:

@RestControllerAdvice(annotations = RestController.class)

public class ControllerExceptionHandler {

}

我们有想要拦截的异常类型,比如想拦截BizException类型,就新增一个方法,使用@ExceptionHandler注解修饰,如下:

@RestControllerAdvice(annotations = RestController.class)

public class ControllerExceptionHandler {

@ExceptionHandler(BizException.class)

@ResponseBody

public BaseResponsehandler(BizException e) {

System.out.println("进入业务异常"+e.getRetCode()+e.getRetMessage());

return BaseResponse.fail(CodeEnum.ERROR.getCode(), CodeEnum.ERROR.getMessage());

}

}唠叨几句

本文大家学到了哪些知识呢?

为了写出更优雅、更简洁、更容易维护的代码,我们需要统一参数校验、统一响应对象返回、统一异常处理。参数校验更简洁,可以使用注解实现。如何统一响应对象返回,一般要包括状态码、描述信息、返回数据。Controller层如何统一全局异常处理?@RestControllerAdvice+@ExceptionHandler。进阶篇?大家可以自己实现自定义注解哈,也建议去看看@RestControllerAdvice实现原理,它其实就是一个切面注解,看下它的源码即可。

很赞哦!(58635)