springboot統(tǒng)一接口返回數(shù)據的實現(xiàn)
一,沒有異常的情況,正常返回數(shù)據
希望接口統(tǒng)一返回的數(shù)據格式如下:
{
"status": 0,
"msg": "成功",
"data": null
}
和接口數(shù)據對應的bean
/**
* 統(tǒng)一返回結果的實體
* @param <T>
*/
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 錯誤碼
*/
private int status;
/**
* 提示消息
*/
private String msg;
/**
* 返回的數(shù)據體
*/
private T data;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
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;
}
}
操作Result實體的工具類
/**
* 生成result的工具類,避免重復代碼
*/
public class ResultUtils {
/**
* 成功時生成result的方法,有返回數(shù)據
*/
public static <T> Result<T> success(T t){
Result<T> result = new Result<>();
result.setStatus(ResultEnum.SUCCESS.getCode());
result.setMsg(ResultEnum.SUCCESS.getMsg());
result.setData(t);
return result;
}
/**
* 成功時生成result的方法,無返回數(shù)據
*/
public static <T> Result<T> success(){
return success(null);
}
/**
* 失敗時生成result的方法
*/
public static <T> Result<T> error(int status, String msg){
Result<T> result = new Result<>();
result.setStatus(status);
result.setMsg(msg);
return result;
}
}
封裝錯誤碼和錯誤消息的枚舉類
/**
* 所有返回結果的枚舉
*/
public enum ResultEnum {
UNKNOWN_ERROR(-1, "未知錯誤"),
SUCCESS(0, "成功"),
BASIC_INFO_ID_IS_EMPTY(600, "基本信息中BasicInfoId為空"),
BASIC_INFO_ADD_TO_DATABASE_FAILURE(601, "向數(shù)據庫添加基本信息失敗"),
DETAILS_DATA_BASIC_INFO_ID_IS_EMPTY(602, "測試數(shù)據中BasicInfoId為空"),
DETAILS_DATA_ADD_TO_DATABASE_FAILURE(603, "向數(shù)據庫添加測試數(shù)據失敗");
ResultEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
private int code;
private String msg;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "ResultEnum{" +
"code=" + code +
", msg='" + msg + '\'' +
'}';
}
}
統(tǒng)一封裝返回結果的切面
之所以需要這個切面,是為了避免每個Controller方法中都要調用ResultUtils.success()。有了這個切面,Controller可以和原來一樣正常返回對象,字符串,void,在切面里面將結果封裝成Result實體,而不需要每個Controller方法都返回Result實體。
/**
* 統(tǒng)一處理返回結果的切面,避免每個controller方法里面都要調用ResultUtils.success()這句話
* 統(tǒng)一在這個切面里面調用
*/
@ControllerAdvice
public class MyResponseAdvice implements ResponseBodyAdvice<Object> {
@Autowired
private ObjectMapper objectMapper;
/**
* Whether this component supports the given controller method return type
* and the selected {@code HttpMessageConverter} type.
*
* @param returnType the return type
* @param converterType the selected converter type
* @return {@code true} if {@link #beforeBodyWrite} should be invoked;
* {@code false} otherwise
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
/**
* Invoked after an {@code HttpMessageConverter} is selected and just before
* its write method is invoked.
*
* @param body the body to be written
* @param returnType the return type of the controller method
* @param selectedContentType the content type selected through content negotiation
* @param selectedConverterType the converter type selected to write to the response
* @param request the current request
* @param response the current response
* @return the body that was passed in or a modified (possibly new) instance
*/
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if(body instanceof Result){ //發(fā)生異常之后,異常處理器里面返回的已經是Result了
return body;
}else if(body instanceof String){ //String屬于特殊情況,需要單獨處理,否則會報錯
try {
return objectMapper.writeValueAsString(ResultUtils.success(body));
} catch (JsonProcessingException e) {
e.printStackTrace();
return ResultUtils.error(ResultEnum.UNKNOWN_ERROR.getCode(), e.getMessage());
}
}
return ResultUtils.success(body);
}
}
二,有異常的情況下
service層為了自動回滾事務,會拋出一些自定義的RuntimeException。默認情況下,只有RuntimeException才會回滾事務。如果Controller里面直接處理service層拋出的異常,則Controller里面到處都是try catch塊,代碼會很難看。將異常集中在一個地方處理會好很多。
springboot中是通過@ControllerAdvice和@ExceptionHandler來完成統(tǒng)一異常處理的。這2個注解只能處理Controller和攔截器中拋出的異常,其他地方拋出的異常(比如Filter中拋出的異常),無法捕獲。其他地方拋出的異常會轉到/error的Controller方法來處理,默認是BasicErrorController來處理,為了能處理其他地方拋出的異常,我們會自定義ErrorController。
統(tǒng)一的異常處理類,處理Controller和攔截器拋出的異常
/**
* 統(tǒng)一的異常處理類
*/
@ControllerAdvice
public class MyExceptionHandler {
/**
* 轉發(fā)到/error,表示由BasicErrorController處理,
* BasicErrorController是由springboot自動裝配到容器中的
*/
/*@ExceptionHandler(BasicInfoException.class)
public String handleException(Exception ex, HttpServletRequest request){
request.setAttribute("javax.servlet.error.status_code", 401);
request.setAttribute("exMsg", ex.getMessage());
return "forward:/error";
}*/
/**
* 處理基本信息相關的異常
*/
@ExceptionHandler(BasicInfoException.class)
@ResponseBody
public Result handleBasicInfoException(BasicInfoException ex){
return ResultUtils.error(ex.getCode(), ex.getMessage());
}
/**
* 處理測試數(shù)據相關的異常
*/
@ExceptionHandler(DetailsDataException.class)
@ResponseBody
public Result handleDetailsDataException(DetailsDataException ex){
return ResultUtils.error(ex.getCode(), ex.getMessage());
}
/**
* 處理未知異常
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Result handleUnKnowException(Exception ex){
return ResultUtils.error(ResultEnum.UNKNOWN_ERROR.getCode(), ex.getMessage());
}
}
自定義的異常類示例
public class BasicInfoException extends RuntimeException {
private int code;
public BasicInfoException(int code, String msg){
super(msg);
this.code = code;
}
public int getCode() {
return code;
}
}
處理其他地方拋出的異常(不是Controller和攔截器拋出的異常),自定義ErrorController
/**
* 自定義ErrorController,處理其他地方拋出的異常(不是Controller和攔截器拋出的異常)
*/
@Controller
public class MyBasicErrorController extends AbstractErrorController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 可以通過@Value獲取到
*/
@Value("${server.error.path}")
private String myPath;
private final ErrorProperties errorProperties;
private ErrorAttributes mErrorAttributes;
public MyBasicErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
super(errorAttributes);
this.errorProperties = serverProperties.getError();
this.mErrorAttributes = errorAttributes;
}
//@RequestMapping(value = "/error")
@RequestMapping("${server.error.path}") //從properties文件中獲取
@ResponseBody
public Result<Object> error(HttpServletRequest request) throws Throwable {
logger.debug("myPath = " + myPath);
//發(fā)生錯誤之后直接將異常拋出去,異常會到統(tǒng)一異常處理器中處理
WebRequest webRequest = new ServletWebRequest(request);
Throwable throwable = this.mErrorAttributes.getError(webRequest).getCause();
throw throwable;
/*UserException ex;
if(throwable instanceof UserException){
ex = (UserException) throwable;
throw ex;
}else{
throw throwable;
}*/
/*HttpStatus status = getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return ResultUtils.error(status.value(), status.name());
}
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
return ResultUtils.error((Integer) body.get("status"), (String)body.get("message"));*/
}
/**
* Determine if the stacktrace attribute should be included.
* @param request the source request
* @param produces the media type produced (or {@code MediaType.ALL})
* @return if the stacktrace attribute should be included
*/
private boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) {
ErrorProperties.IncludeStacktrace include = getErrorProperties().getIncludeStacktrace();
if (include == ErrorProperties.IncludeStacktrace.ALWAYS) {
return true;
}
if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) {
return getTraceParameter(request);
}
return false;
}
/**
* Provide access to the error properties.
* @return the error properties
*/
private ErrorProperties getErrorProperties() {
return this.errorProperties;
}
/**
* Returns the path of the error page.
*
* @return the error path
*/
@Override
public String getErrorPath() {
return this.errorProperties.getPath();
}
}
自定義ErrorController中錯誤處理的方法中,也可以直接將異常拋出,這樣異常就會交給統(tǒng)一異常處理器進行處理。
//@RequestMapping(value = "/error")
@RequestMapping("${server.error.path}") //從properties文件中獲取
@ResponseBody
public Result<Object> error(HttpServletRequest request) throws Throwable {
logger.debug("myPath = " + myPath);
//發(fā)生錯誤之后直接將異常拋出去,異常會到統(tǒng)一異常處理器中處理
WebRequest webRequest = new ServletWebRequest(request);
Throwable throwable = this.mErrorAttributes.getError(webRequest).getCause();
UserException ex;
if(throwable instanceof UserException){
ex = (UserException) throwable;
throw ex;
}else{
throw throwable;
}
/*HttpStatus status = getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return ResultUtils.error(status.value(), status.name());
}
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
return ResultUtils.error((Integer) body.get("status"), (String)body.get("message"));*/
}
到此這篇關于springboot統(tǒng)一接口返回數(shù)據的實現(xiàn)的文章就介紹到這了,更多相關springboot統(tǒng)一接口返回數(shù)據內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
springboot使用CommandLineRunner解決項目啟動時初始化資源的操作
這篇文章主要介紹了springboot使用CommandLineRunner解決項目啟動時初始化資源的操作,幫助大家更好的理解和學習使用springboot框架,感興趣的朋友可以了解下2021-02-02
FileUtils擴展readURLtoString讀取url內容
這篇文章主要介紹了FileUtils擴展readURLtoString使用其支持讀取URL內容為String,支持帶POST傳大量參數(shù),大家參考使用吧2014-01-01
spring AOP實現(xiàn)@Around輸出請求參數(shù)和返回參數(shù)
這篇文章主要介紹了spring AOP實現(xiàn)@Around輸出請求參數(shù)和返回參數(shù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
Java中zip文件壓縮與解壓之ZipInputStream和ZipOutputStream
這篇文章主要給大家介紹了關于Java中zip文件壓縮與解壓之ZipInputStream和ZipOutputStream的相關資料,ZipInputStream 和 ZipOutputStream 可以用于處理 ZIP文件格式,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2023-10-10

