期望结果
请求成功时响应
{
"code":200,
"message":"SUCCESS",
"data":{
"info":"测试成功"
}
}
//或
{
"code": 200,
"message": "success",
"data": null
}
请求失败时响应
{
"code": 500,
"message": "系统异常,请联系管理员!",
"data": null
}
创建枚举类型
用于返回状态码
这里只定义了一些通用的、基于的HTTP响应状态码,业务相关的编码可根据业务需求进行定义。
@Getter
@AllArgsConstructor
public enum ResponseCodeEnums {
SUCCESS(200, "success"),
FAIL(500, "failed"),
HTTP_STATUS_200(200, "ok"),
HTTP_STATUS_400(400, "request error"),
HTTP_STATUS_401(401, "no authentication"),
HTTP_STATUS_403(403, "no authorities"),
HTTP_STATUS_500(500, "server error");
private final int code;
private final String message;
}
定义统一返回结果实体类
@Data
public class ResponseInfo<T> {
/**
* 状态码
*/
protected int code;
/**
* 响应信息
*/
protected String message;
/**
* 返回数据
*/
private T data;
public static <T> ResponseInfo<T> success() {
return new ResponseInfo<>();
}
public static <T> ResponseInfo<T> success(T data) {
return new ResponseInfo<>(data);
}
public static <T> ResponseInfo<T> fail(String message) {
return new ResponseInfo<>(ResponseCodeEnums.FAIL.getCode(), message);
}
public ResponseInfo() {
this.code = ResponseCodeEnums.SUCCESS.getCode();
this.message = ResponseCodeEnums.SUCCESS.getMessage();
}
public ResponseInfo(ResponseCodeEnums statusEnums) {
this.code = statusEnums.getCode();
this.message = statusEnums.getMessage();
}
/**
* 若没有数据返回,可以人为指定状态码和提示信息
*/
public ResponseInfo(int code, String msg) {
this.code = code;
this.message = msg;
}
/**
* 有数据返回时,状态码为200,默认提示信息为“操作成功!”
*/
public ResponseInfo(T data) {
this.data = data;
this.code = ResponseCodeEnums.SUCCESS.getCode();
this.message = ResponseCodeEnums.SUCCESS.getMessage();
}
/**
* 有数据返回,状态码为 200,人为指定提示信息
*/
public ResponseInfo(T data, String msg) {
this.data = data;
this.code = ResponseCodeEnums.SUCCESS.getCode();
this.message = msg;
}
/**
* 依据上一步定义的响应码枚举类型的构造器
*/
public ResponseInfo(ResponseCodeEnums respCodeEnums,T data) {
this.data = data;
this.code = respCodeEnums.getCode();
this.message = respCodeEnums.getMessage();
}
}
该类此时是作为响应数据的json模板。
可以在Controller 方法中直接使用。
错误处理的Controller
单独处理异常:
@Slf4j
@RestController
public class TestController {
@RequestMapping("/calc")
public ResponseInfo<String> calc(Integer id) {
try {
// 模拟异常业务代码
int num = 1 / id;
log.info("计算结果num={}", num);
return ResponseInfo.success();
} catch (Exception e) {
return ResponseInfo.fail("系统异常,请联系管理员!");
}
}
}
在上述实例中,我们通过try...catch的形式捕获异常,并进行处理。在SpringBoot中,我们可以通过RestControllerAdvice注解来定义全局异常处理,这样就无需每处都try...catch了。
全局处理异常:(这是一些错误处理的例子)
@Slf4j
@RestControllerAdvice
public class ExceptionHandlerAdvice {
/**
* 参数格式异常处理
*/
@ExceptionHandler({IllegalArgumentException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseInfo<String> badRequestException(IllegalArgumentException ex) {
log.error("参数格式不合法:{}", ex.getMessage());
return new ResponseInfo<>(HttpStatus.BAD_REQUEST.value() + "", "参数格式不符!");
}
/**
* 权限不足异常处理
*/
@ExceptionHandler({AccessDeniedException.class})
@ResponseStatus(HttpStatus.FORBIDDEN)
public ResponseInfo<String> badRequestException(AccessDeniedException ex) {
return new ResponseInfo<>(HttpStatus.FORBIDDEN.value() + "", ex.getMessage());
}
/**
* 参数缺失异常处理
*/
@ExceptionHandler({MissingServletRequestParameterException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseInfo<String> badRequestException(Exception ex) {
return new ResponseInfo<>(HttpStatus.BAD_REQUEST.value() + "", "缺少必填参数!");
}
/**
* 空指针异常
*/
@ExceptionHandler(NullPointerException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseInfo<String> handleTypeMismatchException(NullPointerException ex) {
log.error("空指针异常,{}", ex.getMessage());
return ResponseInfo.fail("空指针异常");
}
@ExceptionHandler(Exception.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseInfo<String> handleUnexpectedServer(Exception ex) {
log.error("系统异常:", ex);
return ResponseInfo.fail("系统发生异常,请联系管理员");
}
/**
* 系统异常处理
*/
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseInfo<String> exception(Throwable throwable) {
log.error("系统异常", throwable);
return new ResponseInfo<>(HttpStatus.INTERNAL_SERVER_ERROR.value() + "系统异常,请联系管理员!");
}
}
关于@RestControllerAdvice 的几点说明:
-
@RestControllerAdvice注解包含了@Component注解,会把被注解的类作为组件交给Spring来管理。 -
@RestControllerAdvice注解包含了@ResponseBody注解,异常处理完之后给调用方输出一个JSON格式的封装数据。 -
@RestControllerAdvice注解有一个basePackages属性,该属性用来拦截哪个包中的异常信息,一般不指定,拦截项目工程中的所有异常。 -
在方法上通过@ExceptionHandler注解来指定具体的异常,在方法中处理该异常信息,最后将结果通过统一的JSON结构体返回给调用者。
扩展内容
有时可以通过自定义异常,对异常进行抛出从而实现对某一请求的控制
例如前后端分离时,登录失败的情况就可以通过抛出错误进行处理(大部分网站都是使用这种方式)
//定义登陆异常
public class LoginException extends Exception{
public LoginException(String message){
super(message);
}
}
//在全局错误处理Controller中处理LoginException
@Slf4j
@RestControllerAdvice
public class MyExceptionHandle {
@ExceptionHandler({LoginException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseInfo loginHandle(LoginException le){
log.info("错误信息:{}",le.getMessage());
new ResponseInfo(ResponseCodeEnums.HTTP_STATUS_200);
return new ResponseInfo(HttpStatus.BAD_REQUEST.value(),le.getMessage());
}
}
//在登陆Controller中的处理
//登陆验证
// post:/login
@PostMapping("/login")
@ResponseBody
public String login(@RequestParam("userName") String userName,
@RequestParam("passWord") String passWord,
HttpServletRequest request) throws LoginException {
log.info("userName---{}", userName);
log.info("passWord---{}", passWord);
if ("asd123".equals(userName) && "123456".equals(passWord)) {
HttpSession session = request.getSession();
session.setAttribute("userName", userName);
return "登陆成功";
}
throw new LoginException("登陆失败");
}
?
?注意:偷了个小懒,响应体中没有添加data字段。
参考:SpringBoot:如何优雅地进行响应数据封装、异常处理?-51CTO.COM
|