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中了