项目开发形式为前后端分离,采用Restful接口形式开发,对异常的处理与业务数据统一以json形式返回。接口统一json格式的response返回格式一般定义如下:
{
"code": 0,
"msg": "成功",
"data": {
"name": "阿饭",
"age": 16
}
}
package com.fun.common.tools.result;
import com.fun.common.constants.CommonConstants;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
public class CustomResponse<T> implements Serializable {
private static final long serialVersionUID = 1L;
private int code;
private String msg;
private T data;
public CustomResponse(int code) {
this.code = code;
this.msg = CommonConstants.SUCCESS;
}
public CustomResponse(int code, String msg) {
this.code = code;
this.msg = msg;
}
public CustomResponse(int code, T data) {
this.code = code;
this.data = data;
this.msg = CommonConstants.SUCCESS;
}
}
package com.fun.common.tools.exception.result;
public enum ErrorResultCode {
NAME_NOT_NULL(10001, "姓名不能为空"),
AGE_NOT_NULL(10002, "年龄不能为空")
NULL_POINT_EXCEPTION(10003,"空指针异常"),
CUSTOM_EXCEPTION(10004,"具体的自定义异常");
private int code;
private String msg;
WorkDataResultCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
package com.fun.common.tools.result;
import com.fun.common.tools.exception.result.ErrorResultCode ;
public class Result {
public static CustomResponse success() {
return new CustomResponse(0);
}
public static CustomResponse fail() {
return new CustomResponse(-1);
}
public static CustomResponse success(Object data) {
return new CustomResponse(0, data);
}
public static CustomResponse fail(String msg) {
return new CustomResponse(-1, msg);
}
public static CustomResponse fail(ErrorResultCode resultCode) {
return new CustomResponse(resultCode.getCode(), resultCode.getMsg());
}
public static CustomResponse fail(int code, String msg) {
return new CustomResponse(code, msg);
}
}
package com.fun.test.controller;
import com.fun.common.tools.exception.CustomException;
import com.fun.common.tools.exception.result.ErrorResultCode;
import com.fun.common.tools.result.CustomResponse;
import com.fun.common.tools.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/**
* @ClassName: TestController
* @Author: fun
* @Description: 测试类
* @Date: 2020/4/16 10:24
* @Version: 1.0.0
* 可爱之人必有可胖之处
* ღღ ∧_∧
* ฅ(՞••՞)ฅ
*/
@RestController
@Slf4j
@RequestMapping("/test")
public class TestController {
@PostMapping(value = "/test")
public CustomResponse test(User user) {
if (StringUtil.isEmpty(user.getName())) {
return Result.fail(ErrorResultCode.NAME_NOT_NULL);
}
user.setName("阿饭");
user.setAge(16)
return Result.success(user);
}
}
当传入{"name": "阿饭", "age": 16}
,返回结果为:
{
"code": 0,
"msg": "成功",
"data": {
"name": "阿饭",
"age": 16
}
}
当传入{"name": "", "age": 16}
,返回结果为:
{
"code": -1,
"msg": "姓名不能为空",
"data": null
}
在 spring 4.1 新加入的一个接口,在消息体被HttpMessageConverter写入之前允许Controller 中 @ResponseBody修饰的方法或ResponseEntity调整响应中的内容,比如做一些返回处理。
ResponseBodyAdvice接口里一共包含了两个方法
该组件是否支持给定的控制器方法返回类型和选择的{@code HttpMessageConverter}类型
在选择{@code HttpMessageConverter}之后调用,在调用其写方法之前调用。
@Slf4j
@RestControllerAdvice
public class GlobalDataAdvice implements ResponseBodyAdvice<Object> {
@Override
public Object beforeBodyWrite(Object arg0, MethodParameter arg1, MediaType arg2,
Class<? extends HttpMessageConverter<?>> arg3, ServerHttpRequest arg4, ServerHttpResponse arg5) {
final String returnTypeName = arg1.getParameterType().getName();
// 可判断方法返回类型,做出相应返回处理。例如:测试类中void的返回类型,获取到以后自动装载成全局统一返回格式。此处可做
if ("void".equals(returnTypeName)) {
return ResponseUtils.success();
}
if ("com.fun.common.tools.result.CustomResponse".equals(returnTypeName)) {
return arg0;
}
return ResponseUtils.success(arg0);
}
@Override
public boolean supports(MethodParameter arg0, Class<? extends HttpMessageConverter<?>> arg1) {
final String returnTypeName = arg0.getParameterType().getName();
// 用于判断是否需要做处理
return !"com.fun.common.tools.result.CustomResponse".equals(returnTypeName);
}
package com.fun.common.tools.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* @ClassName: CustomException
* @Author: fun
* @Description:自定义异常,继承RuntimeException ,可根据业务需要添加,此处不做更多扩展
* @Date: 2020/1/6 10:23
* @Version: 1.0.0
* 可爱之人必有可胖之处
* ღღ ∧_∧
* ฅ(՞••՞)ฅ
*/
@Data
public class CustomException extends RuntimeException {
private int code;
private String msg;
}
@RestControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(NullPointerException.class)
public CustomResponse errorHandler(NullPointerException ex) {
return ResponseUtils.fail(ErrorResultCode.CUSTOM_EXCEPTION);
}
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(CustomException.class)
public CustomResponse myErrorHandler(CustomException ex) {
return ResponseUtils.fail(ex.getCode(), ex.getMsg());
}
}
package com.fun.test.controller;
import com.fun.common.tools.exception.CustomException;
import com.fun.common.tools.exception.result.ErrorResultCode;
import com.fun.common.tools.result.CustomResponse;
import com.fun.common.tools.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/**
* @ClassName: TestController
* @Author: fun
* @Description: 测试类
* @Date: 2020/4/16 10:24
* @Version: 1.0.0
* 可爱之人必有可胖之处
* ღღ ∧_∧
* ฅ(՞••՞)ฅ
*/
@RestController
@Slf4j
@RequestMapping("/test")
public class TestController {
@PostMapping(value = "/test")
public CustomResponse test() {
User user = new User();
if (user == null) {
throw new NullPointerException();
}
user.setName("阿饭");
user.setAge(16)
return Result.success(customResponse);
}
}
{
"code": 10003,
"msg": "空指针异常",
"data": null
}
或者上面测试类中,将 throw new NullPointerException();改为抛出自定义异常,那么返回结果为:
{
"code": 10004,
"msg": "具体的自定义异常",
"data": null
}
全局统一异常处理类根据自身需求去定义需要处理的异常即可。
@RestControllerAdvice注解的类,需要让spring扫描到,不然不会生效。