-
使用注解,进行参数校验
-
统一结果返回
-
统一异常处理
1.使用注解,统一参数校验
spring boot
有个validation
的组件,引入这个包即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
使用注解如下:
public class User {
@NotNull(message = "用户名不能为空")
private String name;
@NotNull(message = "手机号不能为空")
@Max(value = 11)
private String phone;
@NotNull(message = "邮箱不能为空")
private String email;
}
然后在User
参数对象中,加入@Validated
注解,把错误信息接收到BindingResult
对象,代码如下:
@RequestMapping("saveUser")
@ResponseBody
public String saveUser(@Validated User user, BindingResult result) {
List<FieldError> fieldErrors = result.getFieldErrors();
if (!fieldErrors.isEmpty()) {
return fieldErrors.get(0).getDefaultMessage();
}
//todo 保存用户信息表
return "SUCCESS";
}
2. 接口统一响应对象返回
作为后端开发,我们项目的响应结果,需要统一标准的返回格式。
-
code :响应状态码
-
msg:响应结果描述
-
data:返回的数据
响应状态码一般用枚举表示
public enum SystemCode{
/**操作成功**/
SUCCESS("000000","操作成功"),
/**操作失败**/
ERROR("999999","操作失败"),;
/**
* 自定义状态码
**/
private String code;
/**自定义描述**/
private String message;
SystemCode(String code, String message){
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public String getMessage() {
return message;
}
}
返回的数据类型不是确定的,使用泛型,如下:
public class RtnInfo<T> {
// 返回码
private String code;
// 提示信息
private String msg;
// 错误信息描述
private String ext = "";
// 业务对象
private T data;
public RtnInfo() {
}
/**
*
* setMsgIsNUll(当MSG为空的时候才放入信息)
* @param msg 传入的消息
* @since JDK 1.8
*/
public static RtnInfo OK(){
return new RtnInfo(SystemCode.SUCCESS);
}
public static RtnInfo error(String code,String msg){
return new RtnInfo(code,msg);
}
public void setMsgIsNUll(String msg) {
if(StringUtils.isBlank(getMsg())) {
setMsg(msg);
}
}
/**
*
* setMsgIsNUll(当Code为空的时候才放入信息)
* @param
* @since JDK 1.8
*/
public void setCodeIsNUll(String code) {
if(StringUtils.isBlank(getCode())) {
setMsg(code);
}
}
/**
*
* setSysCodeIsNUll(更新信息为空的code或msg)
* @param sysCode
* @since JDK 1.8
*/
public void setSysCodeIsNUll(SystemCode sysCode) {
if(StringUtils.isBlank(getCode())) {
setCode(sysCode.getCode());
}
if(StringUtils.isBlank(getMsg())) {
setMsg(sysCode.getMsg());
}
}
public RtnInfo(SystemCode sysCode) {
this.code = sysCode.getCode();
this.msg = sysCode.getMsg();
}
public RtnInfo(String code, String msg) {
this(code, msg, null);
}
public RtnInfo(String code, String msg, String ext) {
this(code, msg, ext, null);
}
public RtnInfo(String code, String msg, String ext, T data) {
this.code = code;
this.msg = msg;
this.ext = ext;
this.data = data;
}
public void setSystemCode(SystemCode sysCode) {
this.code = sysCode.getCode();
this.msg = sysCode.getMsg();
}
public void setTicketEnums(TicketEnums ticketEnums){
this.code = ticketEnums.getCode();
this.msg = ticketEnums.getMsg();
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getExt() {
return ext;
}
public void setExt(String ext) {
this.ext = ext;
}
public T getData() {
return data;
}
public RtnInfo setData(T data) {
this.data = data;
return this;
}
@Override
public String toString() {
return "RtnInfo [code=" + code + ", msg=" + msg + ", ext=" + ext
+ ", data=" + data + "]";
}
controller 层的代码,如下
@RequestMapping("queryUser")
public RtnInfo<UserVo> queryUser(String userId) {
RtnInfo rtnInfo = new RtnInfo();
//查询数据
rtnInfo.setSystemCode(SystemCode.SUCCESS);
rtnInfo.setData(new User("123", "张三"))
return rtnInfo;
}
//输出
{"code":"000000","message":"操作成功","data":{"userId":"123","name":"张三"}}
//需要传多个对象
@RequestMapping("queryUser")
public RtnInfo<UserVo> queryUser(String userId) {
RtnInfo rtnInfo = new RtnInfo();
//封装返回的对象,多个
Map<String, Object> jObj = new HashMap<String, Object>();
//查询数据
rtnInfo.setSystemCode(SystemCode.SUCCESS);
jObj.put("user", new User("123", "张三"));
jObj.put("user2", new User("456", "李四"));
rtnInfo.setData(jObj);
return rtnInfo;
}
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 RtnInfo<User> queryUserInfo(User user) {
RtnInfo rtnInfo = new RtnInfo();
try {
rtnInfo.setData(userService.queryUserInfo(userParam));
rtnInfo.setSystemCode(SystemCode.SUCCESS);
return rtnInfo;
} catch (BizException e) {
//doSomething
} catch (Exception e) {
//doSomething
}
return BaseResponse.fail(CodeEnum.ERROR.getCode(),CodeEnum.ERROR.getMessage());
}
可以借助注解@RestControllerAdvice
,让代码更优雅。@RestControllerAdvice
是一个应用于Controller
层的切面注解,它一般配合@ExceptionHandler
注解一起使用,作为项目的全局异常处理。我们来看下demo代码
还是原来的UserController
,和一个会抛出异常的userService的方法,如下:
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/query")
public BaseResponse<User> queryUserInfo1(User user) {
RtnInfo rtnInfo = new RtnInfo();
rtnInfo.setData(userService.queryUserInfo(userParam));
rtnInfo.setSystemCode(SystemCode.SUCCESS);
return rtnInfo;
}
@Service
public class UserServiceImpl implements UserService {
//抛出异常
@Override
public User queryUserInfo(User user) 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 RtnInfo<Void> handler(BizException e) {
RtnInfo rtnInfo = new RtnInfo();
System.out.println("进入业务异常"+e.getRetCode()+e.getRetMessage());
rtnInfo.setSystemCode(SystemCode.ERROR);
return rtnInfo);
}
}