文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-12-02 00:34

关注

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

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

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的组件,我们可以拿来即用。引入这个包即可:

<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-validationartifactId>
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) {

List<FieldError> fieldErrors = 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处理结果,可以想象一下,这些代码有多乱。

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

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

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;
}
}

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


public class BaseResponse<T> {


private String code;


private String message;


private T data;


public static <T> BaseResponse<T> success(T data) {
BaseResponse<T> response= new BaseResponse<>();
response.setCode(CodeEnum.SUCCESS.getCode());
response.setMessage(CodeEnum.SUCCESS.getMessage());
response.setData(data);
return response;
}


public static <T> BaseResponse<T> fail(String code, String message) {
BaseResponse<T> response = 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 BaseResponse<String> getStr(){
return BaseResponse.success("hello,捡田螺的小男孩");
}
//output
{"code":"0000","message":"操作成功","data":"hello,捡田螺的小男孩"}

@RequestMapping("queryUser")
public BaseResponse<UserVo> queryUser(String userId) {
return BaseResponse.success(new UserVo("666", "捡田螺的小男孩"));
}
//output
{"code":"0000","message":"操作成功","data":{"userId":"666","name":"捡田螺的小男孩"}}

3. 统一异常处理

日常开发中,我们一般都是自定义统一的异常类,如下:

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 BaseResponse<UserVo> queryUserInfo(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 BaseResponse<UserVo> queryUserInfo1(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 BaseResponse<Void> handler(BizException e) {
System.out.println("进入业务异常"+e.getRetCode()+e.getRetMessage());
return BaseResponse.fail(CodeEnum.ERROR.getCode(), CodeEnum.ERROR.getMessage());
}
}

唠叨几句

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


来源:捡田螺的小男孩内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯