1.1 因为返回的格式比较乱,因此先对返回格式进行统一,返回消息格式参照以下模板:java
{ "code":1, "msg":"年龄不小于10岁", "data":null } { "code":0, "msg":"成功" "data":{ "id":20, "age":18, "name":"hahaha" } }
1.2 按照如上的消息格式,在domain下新建Result类,该类是Http请求返回的最外层对象(code,msg,data):程序员
package com.example.demo.domain; /** * Http请求返回的最外层对象 * Created by xzf on 2017/9/19. */ 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; } }
1.3 把设置返回结果的方法抽象成 ResultUtil 工具类(这样可复用,避免代码冗余),在具体业务场景中,调用 ResultUtil 工具类中的对应方法,以下图:web
当发生错误时,调用ResultUtil中的error方法;当执行“添加一个学生”成功时,则调用 ResultUtil 的success方法。spring
那么,ResultUtil工具类中的success和error具体是怎么定义的的?其代码以下:json
package com.example.demo.utils; import com.example.demo.domain.Result; /** * Created by xzf on 2017/9/19. */ public class ResultUtil { public static Result success(Object object){ Result result=new Result(); result.setCode(0); result.setMsg("成功"); result.setData(object); return result; } //成功的状况下也可能不含object(即成功也可能没有返回数据) public static Result success(){ //此处调用上面定义的success方法,传入null值 return success(null); } public static Result error(Integer code,String msg){ Result result=new Result(); result.setCode(code); result.setMsg(msg); return result; } }
下面这个方法经过传入一个id,得到该id对应的学生的年龄。在该方法中,对得到的学生年龄进行了判断,并根据判断结果抛出异常框架
//studentService中的getAge方法 public void getAge (Integer id)throws Exception{ Student student= studentRepository.findOne(id); Integer age=student.getAge(); if (age<10){ //返回"你可能在上小学" code=100 throw new StudentException(ResultEnum.PRIMARY_SCHOOL); }else if (age>10 && age<16){ //返回"你可能在上初中" code=101 throw new StudentException(ResultEnum.MIDDLE_SCHOOL); } }
不难看出,这里使用了自定义的异常类StudentExceptiondom
由于原生的Exception异常类,其构造方法只能传入一个String 类型的message,而咱们定义的返回json的模板须要传入的除了错误提示消息,还有错误码,所以此处自定义一个异常类——StudentException工具
package com.example.demo.exception; import com.example.demo.enums.ResultEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sun.plugin2.message.Message; /** * Created by xzf on 2017/9/19. */ //Spring框架只对RuntimeException抛出的异常进行回滚,所以此处不用Exception public class StudentException extends RuntimeException{ private Integer code; public StudentException(ResultEnum resultEnum) { super(resultEnum.getMsg());//父类构造方法中自己会传一个message进去 this.code = resultEnum.getCode(); } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } }
在上面的代码中咱们看到,在抛StudentException异常时,该异常的构造方法中传入的参数是“ResultEnum.PRIMARY_SCHOOL ”,他们是什么呢?不是说须要传入“错误码+返回消息”吗?其实,这里的“ResultEnum.PRIMARY_SCHOOL ”就包含了这两个信息。this
原来,为了方便对错误码(状态码)进行统一管理,使得错误码和其相应的返回消息可以一一对应,也方便程序员查看和修改,这里把错误码和返回消息设置成一个枚举类:spa
package com.example.demo.enums; /** * 将code和message对应起来 * Created by xzf on 2017/9/19. */ public enum ResultEnum { UNKNOW_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; } /** * 枚举类中给getter方法就能够了,枚举的使用都是使用构造方法来建立,不会再set它的值 * @return */ public Integer getCode() { return code; } public String getMsg() { return msg; } }
这样一来,错误码和它所对应的返回消息就一目了然了。
在这里拗了半天,下面来捋一捋关系:
简单说来,就是把原来的抛异常,改为了抛一个自定义的异常;把原来要传入的两个参数(code和msg),改为了传入一个枚举类参数(枚举类中包含了这两个信息)
既然是抛出了异常,那么就须要捕获异常,并采起相应的操做。这里咱们在handle下新建一个ExceptionHandle类,用于捕获并处理上面的异常:
package com.example.demo.handle; import com.example.demo.domain.Result; import com.example.demo.exception.StudentException; import com.example.demo.utils.ResultUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; /** * Created by xzf on 2017/9/19. */ @ControllerAdvice public class ExceptionHandle { private static final Logger logger= LoggerFactory.getLogger(ExceptionHandle.class); @ExceptionHandler(value = Exception.class) //声明捕获的异常类 @ResponseBody //返回的是json数据,然而类前使用的不是@RestController注解,所以须要加上@ResponseBody public Result handle(Exception e){ //判断捕获的异常是不是自定义的StudentException if (e instanceof StudentException){ StudentException exception=(StudentException) e; return ResultUtil.error(exception.getCode(),exception.getMessage()); }else { logger.error("【系统异常】",e);//控制台输出异常信息 //前台返回“-1,未知错误”,而且该异常被捕获处理了,控制台不显示,因此这里借助日志来排查错误 return ResultUtil.error(-1,"未知错误!");//返回json信息为"未知错误", } } }
从上面代码能够看到,在处理异常的时候,传过来的 StudentException 类中的值就能够用来设置进Result中了