springboot统一返回消息体

本文详细介绍SpringBoot项目中统一返回体的设计方案,包括正常返回对象、异常返回对象及返回状态码的定义,同时介绍了全局统一返回体注解类、自定义返回体处理、区分已知异常与未知异常的方法,并通过实例演示如何实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于已知错误与未知错误,可以对未知错误进行钉钉机器人或者微信机器人的发送,及时的找到错误的地方,进行捕捉,这样错误就会越来越完善

定义正常返回对象、异常返回对象、返回状态码

正常返回对象
import java.io.Serializable;

public class Result implements Serializable {

    private Integer code;

    private String message;

    private Object data;

    public static Result success() {
        Result result = new Result();
        result.setResultCode(ResultCode.SUCCESS);
        return result;
    }

    public static Result success(Object data) {
        Result result = new Result();
        result.setResultCode(ResultCode.SUCCESS);
        result.setData(data);
        return result;
    }

    public static Result failure(ResultCode resultCode) {
        Result result = new Result();
        result.setResultCode(resultCode);
        return result;
    }

    public static Result failure(ResultCode resultCode, Object data) {
        Result result = new Result();
        result.setResultCode(resultCode);
        result.setData(data);
        return result;
    }

    public static Result failure(Integer code, String message, Object data) {
        Result result = new Result();
        result.setCode(code);
        result.setMessage(message);
        result.setData(data);
        return result;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public void setResultCode(ResultCode resultCode) {
        this.code = resultCode.code();
        this.message = resultCode.message();
    }

}
错误返回对象
public class ErrorResult extends RuntimeException {

    private ResultCode resultCode;

    private Object errors;

    public ErrorResult(ResultCode resultCode, Object errors) {
        this.resultCode = resultCode;
        this.errors = errors;
    }

    public ResultCode getResultCode() {
        return resultCode;
    }

    public void setResultCode(ResultCode resultCode) {
        this.resultCode = resultCode;
    }

    public Object getErrors() {
        return errors;
    }

    public void setErrors(Object errors) {
        this.errors = errors;
    }
}
返回状态码
public enum ResultCode {
    // todo 成功状态码
    SUCCESS(200, "成功"),

    // todo 参数错误
    PARAM_IS_NULL(1001, "参数为空"),

    // todo 用户错误
    USER_NOT_LOGIN(2001, "用户未登录"),

    // todo 其他错误
    ERROR(9999, "其他异常");

    private Integer code;
    private String message;

    ResultCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public Integer code() {
        return this.code;
    }

    public String message() {
        return this.message;
    }
}

定义全局统一返回体注解类、自定义返回体、区分已知异常与未知异常、拦截器添加标记

全局统一返回体注解类
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
public @interface ResponseResult {
}
自定义返回体
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
    private static final Logger log = LoggerFactory.getLogger(ResponseResultHandler.class);

    // 标记名称
    public static final String RESPONSE_RESULT = "RESPONSE-RESULT";

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = sra.getRequest();

        ResponseResult responseResult = (ResponseResult) request.getAttribute(RESPONSE_RESULT);
        return responseResult == null ? false : true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        try {
            // todo 异常返回处理
            if (body instanceof ErrorResult) {
                ErrorResult errorResult = (ErrorResult) body;
                return Result.failure(errorResult.getResultCode(), errorResult.getErrors());
            }
        } catch (Exception e) {
            log.error("request uri path: {}, format response body error", request.getURI().getPath(), e);
        }

        // todo 成功返回处理
        return Result.success(body);
    }
}
区分已知异常与未知异常
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理自定义异常
     *
     */
    @ExceptionHandler(value = ErrorResult.class)
    @ResponseBody
    public ErrorResult bizExceptionHandler(ErrorResult result) {
        return result;
    }

    /**
     * 处理其他异常
     *
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ErrorResult exceptionHandler(Exception e) {
        return new ErrorResult(ResultCode.ERROR, e.getMessage());
    }
}
拦截器添加标记
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

@Component
public class LoginInterceptor implements HandlerInterceptor {
    private static final Logger log = LoggerFactory.getLogger(LoginInterceptor.class);

    // 标记名称
    public static final String RESPONSE_RESULT = "RESPONSE-RESULT";

    @Autowired
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // todo 添加标记
        if (handler instanceof HandlerMethod) {
            final HandlerMethod handlerMethod = (HandlerMethod) handler;
            final Class<?> classs = handlerMethod.getBeanType();
            final Method method = handlerMethod.getMethod();

            if (classs.isAnnotationPresent(ResponseResult.class)) {
                request.setAttribute(RESPONSE_RESULT, classs.getAnnotation(ResponseResult.class));
            } else if (method.isAnnotationPresent(ResponseResult.class)) {
                request.setAttribute(RESPONSE_RESULT, method.getAnnotation(ResponseResult.class));
            }
        }
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

新建几个接口测试一下

测试conreoller
import com.zyh.budget.config.ErrorResult;
import com.zyh.budget.config.ResponseResult;
import com.zyh.budget.config.ResultCode;
import com.zyh.budget.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Description //TODO 全局统一返回体测试控制器
 * @Author Zhong Yanghao
 * @Date 2021/03/16 17:00
 */
@RestController
@ResponseResult
@RequestMapping("global")
public class GlobalHandlerController {

    @GetMapping("test")
    public User test() {
        User user = new User();
        user.setName("test");
        user.setPhone("11111111");
        return user;
    }

    @GetMapping("test2")
    public String test2() {
        return "user";
    }

    @GetMapping("err")
    public String err() throws Exception {
        throw new Exception("错误", new Throwable("111"));
    }

    @GetMapping("err2")
    public String err2() {
        throw new ErrorResult(ResultCode.USER_NOT_LOGGEN_IN, "错误");
    }

}

问题

返回String类型会导致无法转换的问题
方法一:在自定义返回体中如果是String类型,单独返回处理,具体修改如下,解决String类型转换异常处
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
    private static final Logger log = LoggerFactory.getLogger(ResponseResultHandler.class);

    // 标记名称
    public static final String RESPONSE_RESULT = "RESPONSE-RESULT";

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = sra.getRequest();

        ResponseResult responseResult = (ResponseResult) request.getAttribute(RESPONSE_RESULT);
        return responseResult == null ? false : true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        try {
            // todo 异常返回处理
            if (body instanceof ErrorResult) {
                ErrorResult errorResult = (ErrorResult) body;
                return Result.failure(errorResult.getResultCode(), errorResult.getErrors());
                
            // 解决String类型转换异常
            } else if (body instanceof String) {
                // 返回String类型时
                return objectMapper.writeValueAsString(Result.success(body));
            }
        } catch (Exception e) {
            log.error("request uri path: {}, format response body error", request.getURI().getPath(), e);
        }

        // todo 成功返回处理
        return Result.success(body);
    }
}
方法二:在webconfig中处理 Object 类型的 HttpMessageConverter 放得靠前一些,解决类型转换异常
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfigurer implements WebMvcConfigurer {

    /**
     * 处理 Object 类型的 HttpMessageConverter 放得靠前一些,解决类型转换异常
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(0, new MappingJackson2HttpMessageConverter());
    }
}
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值