目录
为什么使用
项目中我们会将响应封装成JSON返回,一般我们会将所有接口的数据格式统一, 使前端对数据的操作更一致、轻松。 一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数 据就可以。但是一般会包含状态码、返回消息、数据这几部分内容
整体结构
统一返回数据结构
package com.kuang.common.response;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
/**
* @author HaiGee
* @Description 公共结果返回
*/
@Data
public class Result {
@ApiModelProperty(value = "是否成功")
private Boolean success;
@ApiModelProperty(value = "返回码")
private Integer code;
@ApiModelProperty(value = "返回消息")
private String message;
@ApiModelProperty(value = "返回数据")
private Map<String,Object> data = new HashMap<>();
/**
* 构造方法私有化,里面的方法都是静态方法
* 达到保护属性的作用
*/
private Result(){
}
/**
* 这里是使用链式编程
*/
public static Result ok(){
Result result = new Result();
result.setSuccess(true);
result.setCode(ResultCode.SUCCESS.getCode());
result.setMessage(ResultCode.SUCCESS.getMessage());
return result;
}
public static Result error(){
Result result = new Result();
result.setSuccess(false);
result.setCode(ResultCode.COMMON_FAIL.getCode());
result.setMessage(ResultCode.COMMON_FAIL.getMessage());
return result;
}
public static Result error(ResultCode resultCode){
Result result = new Result();
result.setSuccess(false);
result.setCode(resultCode.getCode());
result.setMessage(resultCode.getMessage());
return result;
}
/**
* 自定义返回成功与否
* @param success
* @return
*/
public Result success(Boolean success){
this.setSuccess(success);
return this;
}
public Result message(String message){
this.setMessage(message);
return this;
}
public Result code(Integer code){
this.setCode(code);
return this;
}
public Result data(String key,Object value){
this.data.put(key,value);
return this;
}
public Result data(Map<String,Object> map){
this.setData(map);
return this;
}
}
创建枚举类定义返回码
package com.kuang.common.response;
/**
* @Author: HaiGee
* @Description: 返回码定义
* 规定:
* #200表示成功
* #1001~1999 区间表示参数错误
* #2001~2999 区间表示用户错误
* #3001~3999 区间表示接口异常
* #后面对什么的操作自己在这里注明就行了
*/
public enum ResultCode implements CustomizeResultCode{
/* 成功 */
SUCCESS(200, "成功"),
/* 默认失败 */
COMMON_FAIL(999, "失败"),
/* 参数错误:1000~1999 */
PARAM_NOT_VALID(1001, "参数无效"),
PARAM_IS_BLANK(1002, "参数为空"),
PARAM_TYPE_ERROR(1003, "参数类型错误"),
PARAM_NOT_COMPLETE(1004, "参数缺失"),
/* 用户错误 */
USER_NOT_LOGIN(2001, "用户未登录"),
USER_ACCOUNT_EXPIRED(2002, "账号已过期"),
USER_CREDENTIALS_ERROR(2003, "密码错误"),
USER_CREDENTIALS_EXPIRED(2004, "密码过期"),
USER_ACCOUNT_DISABLE(2005, "账号不可用"),
USER_ACCOUNT_LOCKED(2006, "账号被锁定"),
USER_ACCOUNT_NOT_EXIST(2007, "账号不存在"),
USER_ACCOUNT_ALREADY_EXIST(2008, "账号已存在"),
USER_ACCOUNT_USE_BY_OTHERS(2009, "账号下线"),
/*部门错误*/
DEPARTMENT_NOT_EXIST(3007, "部门不存在"),
DEPARTMENT_ALREADY_EXIST(3008, "部门已存在"),
/* 业务错误 */
NO_PERMISSION(3001, "没有权限"),
/*运行时异常*/
ARITHMETIC_EXCEPTION(9001,"算数异常"),
NULL_PONINTER_EXCEPTION(9002,"空指针异常"),
/*数据操作错误定义*/
BODY_NOT_MATCH(400,"请求的数据格式不符!"),
SIGNATURE_NOT_MATCH(401,"请求的数字签名不匹配!"),
NOT_FOUND(404, "未找到该资源!"),
INTERNAL_SERVER_ERROR(500, "服务器内部错误!"),
SERVER_BUSY(503,"服务器正忙,请稍后再试!"),
/*用户相关:10000***/
USER_ACCOUNT_NOT_FOUND(10001, "账号不存在!"),
DoNotAllowToDisableTheCurrentUser(10002,"不允许禁用当前用户"),
/*业务异常*/
PRODUCT_IS_REMOVE(30001,"物资已移入回收站"),
PRODUCT_NOT_FOUND(30002,"物资找不到"),
PRODUCT_WAIT_PASS(30003,"物资等待审核"),
PRODUCT_STATUS_ERROR(30004,"物资状态错误"),
PRODUCT_IN_STOCK_NUMBER_ERROR(30005,"物资入库数量非法"),
PRODUCT_OUT_STOCK_NUMBER_ERROR(30008,"物资发放数量非法"),
PRODUCT_IN_STOCK_EMPTY(30006,"物资入库不能为空"),
PRODUCT_OUT_STOCK_EMPTY(30007,"物资发放不能为空"),
PRODUCT_STOCK_ERROR(30009,"物资库存不足");
private Integer code;
private String message;
ResultCode(Integer code,String message){
this.code = code;
this.message = message;
}
@Override
public Integer getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
package com.kuang.common.response;
public interface CustomizeResultCode {
/**
* 获取错误状态码
* @return 错误状态码
*/
Integer getCode();
/**
* 获取错误信息
* @return 错误信息
*/
String getMessage();
}
全局异常处理器
package com.kuang.common.exception;
import com.google.protobuf.ServiceException;
import com.kuang.common.response.Result;
import com.kuang.common.response.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.util.stream.Collectors;
/*
* 功能描述: <br>
* 全局异常处理器 它只会处理controller层的异常
* RestControllerAdvice 捕获异常
* ExceptionHandler 处理异常
* @Param:
* @Return:
* @Author: HaiGee
* @Date: ${Date} ${Time}*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(value = ArithmeticException.class)
public Result exception(ArithmeticException e){
e.printStackTrace();
log.error("出现了异常:"+e.getMessage()+"---------------------");
return Result.error(ResultCode.ARITHMETIC_EXCEPTION);
}
@ResponseBody
@ExceptionHandler(value = NullPointerException.class)
public Result exception(NullPointerException e){
e.printStackTrace();
log.error("出现了异常:"+e.getMessage()+"---------------------");
return Result.error(ResultCode.NULL_PONINTER_EXCEPTION);
}
@ResponseBody
@ExceptionHandler(value = Exception.class)
public Result exception(Exception e){
e.printStackTrace();
log.error("出现了异常:"+e.getMessage()+"---------------------");
return Result.error();
}
@ResponseBody
@ExceptionHandler(value = BusinessException.class)
public Result exception(BusinessException e){
e.printStackTrace();
log.error("出现了异常:"+e.getMessage()+"---------------------");
return Result.error().code(e.getCode()).message(e.getErrMsg());
}
//处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常
@ExceptionHandler(BindException.class)
@ResponseBody
public Result BindExceptionHandler(BindException e) {
String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
log.error("出现了异常:"+e.getMessage()+"---------------------");
return Result.error().message(message);
}
//处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是javax.validation.ConstraintViolationException
/*@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public Result ConstraintViolationExceptionHandler(ConstraintViolationException e) {
String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
return Result.error().message(message);
}*/
//处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public Result MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
return Result.error().message(message);
}
/**
* 处理servlet异常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value = ServletException.class)
@ResponseBody
public Result servletExceptionHandler(HttpServletRequest req, BusinessException e){
log.error("web服务器异常 {}",e.getMessage());
return Result.error().message(e.getMessage());
}
/**
* 处理自定义的业务异常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value = ServiceException.class)
@ResponseBody
public Result bizExceptionHandler(HttpServletRequest req, BusinessException e){
log.error("业务异常=>{}",e.getMessage());
return Result.error().code(e.getCode()).message(e.getErrMsg());
}
/**
* shiro的异常
* @param
* @return
*/
/*@ExceptionHandler(ShiroException.class)
public Result handle401(ShiroException e) {
log.error("shiro异常=>{}",e.getMessage());
return new Result(401, e.getMessage(), null);
}
/**
* 获取状态码
* @param request
* @return
*/
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}
}
自定义异常类
package com.kuang.common.exception;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BusinessException extends RuntimeException{
@ApiModelProperty(value = "状态码")
private Integer code;
@ApiModelProperty(value = "错误信息")
private String errMsg;
}
使用方式
@ApiOperation(value = "查询单个用户")
@GetMapping("/getUserById")
public Result getUserById(){
User user = userService.getById(5);
if(user==null){
//如果为空抛出异常
throw new BusinessException(ResultCode.USER_ACCOUNT_NOT_EXIST.getCode(),
ResultCode.USER_ACCOUNT_NOT_EXIST.getMessage());
}
return Result.ok().data("User",user);
}