1.创建基于spring boot+jpa的基本的增删
请参考spring boot+jpa简单实现就不多介绍了。本次主要是统一异常处理的演进过程,还有一个目的是刚看的异常处理视频,记录一下,方便以后查看。
2.最原始的返回(不友好,不利于前端处理)
@RequestMapping("findByIdFirst")
public Student findByIdFirst(@RequestParam String id) {
return studentService.findById(id).orElse(null);
}
@RequestMapping("findAllFirst")
public List<Student> findByIdFirst() {
return studentService.list();
}
-
如果存在Student的id为
d4c-2cfaa59e-27a8-46c1-8578-da715e44b214
则返回。
-
如果查询的id不存在,则什么都不返回
-
如果存在数据,list接口返回
如果不存在数据,则返回。
如果用这种接口返回数据,肯定会被前端捶爆。(还是不要尝试了!哎!说多了都是泪!!!)
3 .怎么改进
我们定义一个ResultInfo对象来统一定义返回结果。
package com.d4c.exception.demo.pojo;
import lombok.Data;
/**
* Created with IntelliJ IDEA.
* User: liangqing.zhao(zlq)
* Date: 2019/10/7 19:41
* Description:
*/
@Data
public class ResultInfo<T> {
/**
*返回码
*/
private Integer code;
/**
*返回提示信息
*/
private String msg;
/**
*返回具体对象
*/
private T data;
}
上面的接口就可以改进为
@RequestMapping("findByIdSecond")
public ResultInfo findByIdSecond(@RequestParam String id) {
Student stu = studentService.findById(id).orElse(null);
ResultInfo resultInfo = new ResultInfo();
resultInfo.setCode(1);
resultInfo.setMsg("成功!");
resultInfo.setData(stu);
return resultInfo;
}
@RequestMapping("findAllSecond")
public ResultInfo findByIdSecond() {
List<Student> listStudent = studentService.list();
ResultInfo resultInfo = new ResultInfo();
resultInfo.setCode(1);
resultInfo.setMsg("成功!");
resultInfo.setData(listStudent);
return resultInfo;
}
-
改造后的数据(1条数据)
-
list
现在不管有没有数据,共同的部分code和msg都会返回,这样更有利于前端的判断处理数据。
但是,每次返回成功都要写一遍
ResultInfo resultInfo = new ResultInfo();
resultInfo.setCode(1);
resultInfo.setMsg("成功!");
这有点太繁琐,一点都不优雅!!!
4. 代码共同的部分提取成一个工具类。
package com.d4c.exception.demo.utils;
import com.d4c.exception.demo.pojo.ResultInfo;
/**
* Created with IntelliJ IDEA.
* User: liangqing.zhao(zlq)
* Date: 2019/10/7 19:42
* Description:
*/
public class ResultInfoOldUtil {
public static ResultInfo success(Object object) {
ResultInfo result = new ResultInfo();
result.setCode(1);
result.setMsg("成功!");
result.setData(object);
return result;
}
}
然后,代码就能改成
@RequestMapping("findByIdThird")
public ResultInfo findByIdThird(@RequestParam String id) {
Student stu = studentService.findById(id).orElse(null);
return ResultInfoOldUtil.success(stu);
}
@RequestMapping("findAllThird")
public ResultInfo findByIdThird() {
List<Student> listStudent = studentService.list();
return ResultInfoOldUtil.success(listStudent);
}
效果与上面一样。
到上面我们就处理了我们成功的代码,但只是成功,前提是代码不出现异常,但是这也许有可能吧!!!
我们来主动测试一个异常看看
@RequestMapping("findByIdFourth")
public ResultInfo findByIdFourth(@RequestParam String id) {
Student stu = studentService.findById(id).orElse(null);
Integer count = 1/0;
return ResultInfoOldUtil.success(stu);
}
直接异常抛到页面上,这怎么可以。
因此又处理了一下,变成了
@RequestMapping("findByIdFourth")
public ResultInfo findByIdFourth(@RequestParam String id) {
try {
Student stu = studentService.findById(id).orElse(null);
Integer count = 1/0;
return ResultInfoOldUtil.success(stu);
} catch (Exception e) {
e.printStackTrace();
return ResultInfoOldUtil.error();
}
}
@RequestMapping("findAllFourth")
public ResultInfo findByIdFourth() throws Exception {
try {
List<Student> listStudent = studentService.list();
throw new Exception("出现异常");
} catch (Exception e) {
e.printStackTrace();
return ResultInfoOldUtil.error();
}
}
此时的结果变成了
异常也变得优雅了!
但是,如果异常多了,我们分别处理,就有变成了。
try {...} catch(...) {...}catch(...).... finally {...}
这样处理如此繁琐。能不能把这些异常统一处理一下,处理一次,下次就不有再处理同样的异常了。
5.统一异常处理@ControllerAdvice+ @ExceptionHandler(...)
package com.d4c.exception.demo.handle;
import com.d4c.exception.demo.enums.ResultInfoEnum;
import com.d4c.exception.demo.exception.StudentException;
import com.d4c.exception.demo.pojo.ResultInfo;
import com.d4c.exception.demo.utils.ResultInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* Created with IntelliJ IDEA.
* User: liangqing.zhao(zlq)
* Date: 2019/10/7 19:40
* Description:
*/
@ControllerAdvice
@Slf4j
public class ExceptionHandle {
@ExceptionHandler(Exception.class)
@ResponseBody
public ResultInfo handleException(Exception e) {
if (e instanceof StudentException) {
StudentException studentException = (StudentException) e;
return ResultInfoUtil.error(studentException.getCode(), studentException.getMessage());
} else if (e instanceof NullPointerException) {
ResultInfoEnum resultInfoEnum = ResultInfoEnum.NULL_POINT_EXCEPTION;
return ResultInfoUtil.error(resultInfoEnum.getCode(), resultInfoEnum.getMsg());
} else if (e instanceof IndexOutOfBoundsException) {
ResultInfoEnum resultInfoEnum = ResultInfoEnum.INDEX_OUT_BOUNDS_EXCEPTION;
return ResultInfoUtil.error(resultInfoEnum.getCode(), resultInfoEnum.getMsg());
} else {
log.error("【系统异常】{}", e);
ResultInfoEnum unknown = ResultInfoEnum.UNKNOWN;
return ResultInfoUtil.error(unknown.getCode(), unknown.getMsg());
}
}
}
package com.d4c.exception.demo.exception;
import com.d4c.exception.demo.enums.ResultInfoEnum;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import net.bytebuddy.implementation.bind.annotation.Super;
/**
* Created with IntelliJ IDEA.
* User: liangqing.zhao(zlq)
* Date: 2019/10/7 19:36
* Description:
*/
@Getter
@Setter
public class StudentException extends RuntimeException {
private Integer code;
public StudentException(ResultInfoEnum resultInfoEnum){
super(resultInfoEnum.getMsg());
this.code = resultInfoEnum.getCode();
}
}
然后我们就不用显示的try catch了。只要在ExceptionHandle处理一遍就好了。就变成了下面:
@RequestMapping("findByIdFifth")
public ResultInfo findByIdFifth(@RequestParam String id) {
Student stu = studentService.findById(id).orElse(null);
Integer count = 1 / 0;
return ResultInfoOldUtil.success(stu);
}
@RequestMapping("findAllFifth")
public ResultInfo findByIdFifth() throws Exception {
List<Student> listStudent = studentService.list();
throw new Exception("出现异常");
}
6.自定义异常类StudentException
package com.d4c.exception.demo.exception;
import com.d4c.exception.demo.enums.ResultInfoEnum;
import lombok.Getter;
import lombok.Setter;
/**
* Created with IntelliJ IDEA.
* User: liangqing.zhao(zlq)
* Date: 2019/10/7 19:36
* Description:
*/
@Getter
@Setter
public class StudentException extends RuntimeException {
private Integer code;
public StudentException(ResultInfoEnum resultInfoEnum) {
super(resultInfoEnum.getMsg());
this.code = resultInfoEnum.getCode();
}
}
7.统一管理异常信息ResultInfoEnum
package com.d4c.exception.demo.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Created with IntelliJ IDEA.
* User: liangqing.zhao(zlq)
* Date: 2019/10/7 19:39
* Description:
* @author
*/
@Getter
@AllArgsConstructor
public enum ResultInfoEnum {
/**
* 成功
*/
SUCCESS(1,"success"),
/**
* 失败
*/
FAILED(2,"failed"),
/**
*未知错误
*/
UNKNOWN(3,"未知错误"),
/**
*id不存在
*/
NOT_EXIST_ID(4,"要查询的id不存在"),
NULL_POINT_EXCEPTION(5,"空指针异常"),
INDEX_OUT_BOUNDS_EXCEPTION(6,"下标超出异常")
;
private Integer code;
private String msg;
}
8.优化后的ResultInfoUtil
package com.d4c.exception.demo.utils;
import com.d4c.exception.demo.enums.ResultInfoEnum;
import com.d4c.exception.demo.pojo.ResultInfo;
/**
* Created with IntelliJ IDEA.
* User: liangqing.zhao(zlq)
* Date: 2019/10/7 19:42
* Description:
*/
public class ResultInfoUtil {
public static ResultInfo success(Object object) {
ResultInfo result = new ResultInfo();
ResultInfoEnum successEnum = ResultInfoEnum.SUCCESS;
result.setCode(successEnum.getCode());
result.setMsg(successEnum.getMsg());
result.setData(object);
return result;
}
public static ResultInfo success() {
return success(null);
}
public static ResultInfo error(Integer code ,String msg) {
ResultInfo result = new ResultInfo();
result.setCode(code);
result.setMsg(msg);
return result;
}
}
最后,代码优化成
json与统一异常处理到这里就告一段落了。
具体的源码请参考exception-demo