github源码 https://github.com/zehuawong/SpringBoot-JPA-Thymeleaf-Demo
慕课网课程廖师兄Web进阶:https://www.imooc.com/video/14342
统一json格式的response,如添加一条数据失败的时候的响应码是1而不是500,
{
"code": 1,
"msg": "年龄需要大于6岁",
"data": null
}
{
"code": 0,
"msg": "成功",
"data": {
"id": 10,
"name": "李",
"age": 7
}
}
/**
* http请求返回的最外层对象
* Created by wzh-zhua on 2018/10/1.
*/
public class Result<T> {
/** 错误码. */
private Integer code;
/** 提示信息. */
private String msg;
/** 具体的内容. */
private T data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
为了避免上面出现的代码冗余情况,应该增加工具类,封装请求失败和成功时候的方法,这里可使用静态方法
public class ResultUtil {
public static Result success(Object object) {
Result result = new Result();
result.setCode(0);
result.setMsg("成功");
result.setData(object);
return result;
}
public static Result success() {
return success(null);
}
public static Result error(Integer code, String msg) {
Result result = new Result();
result.setCode(code);
result.setMsg(msg);
return result;
}
}
/**
* 添加一个女生
* @return
*/
@PostMapping(value = "/addgirl")
public Result<Girl> girlAdd(@Valid Girl girl, BindingResult bindingResult) {
//假如表单参数很多,用@RequestParam方式就不合适了
//这里需要做表单验证
if (bindingResult.hasErrors()) {
return ResultUtil.error(1, bindingResult.getFieldError().getDefaultMessage());
}
return ResultUtil.success(girlRepository.save(girl));
}
可以参考
@ControllerAdvice + @ExceptionHandler 全局处理 Controller 层异常
https://blog.csdn.net/kinginblue/article/details/70186586
Spring Boot @ControllerAdvice 处理全局异常,返回固定格式Json
https://blog.csdn.net/u014044812/article/details/78219692
场景一
上面的这个异常的status的响应码的格式是500,而且json的字段不是我们自定义的字段
为了得到异常情况统一的返回数据,我们可以对异常捕获,取到我们想要的内容,再给它封装,最后返回给浏览器。
场景二
还有一种情况是,对于与数据库相关的 Spring MVC 项目,我们通常会把 事务 配置在 Service层,当数据库操作失败时让 Service 层抛出运行时异常,Spring 事物管理器就会进行回滚。
如此一来,我们的 Controller 层就不得不进行 try-catch Service 层的异常,否则会返回一些不友好的错误信息到客户端。但是,Controller 层每个方法体都写一些模板化的 try-catch 的代码,很难看也难维护,特别是还需要对 Service 层的不同异常进行不同处理的时候。
新建一个handle包,新建ExceptionHandle.java类
/**
* 捕获异常的类,返回信息给浏览器,可以自定义返回的code,msg等信息
*/
@ControllerAdvice
public class ExceptionHandle {
private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
if (e instanceof GirlException) { //判断异常是否是我们定义的异常
GirlException girlException = (GirlException) e;
return ResultUtil.error(girlException.getCode(), girlException.getMessage());
}else {
logger.error("【系统异常】{}", e);
return ResultUtil.error(-1, "未知错误");
}
}
}
需要注意:
优点和缺点
注意完善ExceptionHandle类
可以参考文章 https://blog.csdn.net/kinginblue/article/details/70186586
@ExceptionHandler(BusinessException.class) 声明了对 BusinessException 业务异常的处理,并获取该业务异常中的错误提示,构造后返回给客户端。
@ExceptionHandler(Exception.class) 声明了对 Exception 异常的处理,起到兜底作用,不管 Controller 层执行的代码出现了什么未能考虑到的异常,都返回统一的错误提示给客户端。
@ExceptionHandler(MethodArgumentNotValidException.class) 处理所有接口数据验证异常
注意:spring中,只有继承RuntimeException才会进行事务回滚,Exception不会进行事务回滚
public class GirlException extends RuntimeException{ //注意:spring中,只有RuntimeException才会进行事务回滚,Exception不会进行事务回滚
private Integer code;
public GirlException(ResultEnum resultEnum) {
super(resultEnum.getMsg());
this.code = resultEnum.getCode();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
public void getAge(Long id) throws Exception{ //逻辑判断
Girl girl = findOne(id);
Integer age = girl.getAge();
if (age < 10) {
//返回"你还在上小学吧" code=100
throw new GirlException(ResultEnum.PRIMARY_SCHOOL);
}else if (age > 10 && age < 16) {
//返回"你可能在上初中" code=101
throw new GirlException(ResultEnum.MIDDLE_SCHOOL);
}
//如果>16岁,加钱
//...
}
修改:上图中的code=100不应该到处出现,不利于代码维护
public enum ResultEnum {
UNKONW_ERROR(-1, "未知错误"),
SUCCESS(0, "成功"),
PRIMARY_SCHOOL(100, "我猜你可能还在上小学"),
MIDDLE_SCHOOL(101, "你可能在上初中"),
;
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}