Spring boot-返回值封装与业务异常

对于spring来说 返回值封装与业务异常 是一项很古老却实用的技术
然而在我上一份工作的时候依然碰到公司的新项目没有这2步处理
在SpringMVC时期已经可以通过xml配置达成以上目的
不过xml配置太过繁琐而且不容易排错 远不如Spring boot的注解+java代码清爽

以下将逐步详述配置方法

  1. 在***pom.xml中添加依赖
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.3</version>
  </parent>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  1. 添加通用返回值的包装类Result
import lombok.Data;

@Data
public class Result {
    private String status = "success";
    private String msg = "";
    private int code = 200;
    private Object result;
}
  1. 实现自定义的ResponseBody处理类OutputProxy
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;

import demo.entity.Result;

public class OutputProxy implements HandlerMethodReturnValueHandler
{
    private HandlerMethodReturnValueHandler proxyObject;

    public OutputProxy(HandlerMethodReturnValueHandler proxyObject)
    {
        this.proxyObject = proxyObject;
    }

    @Override
    public boolean supportsReturnType(MethodParameter returnType)
    {
        return proxyObject.supportsReturnType(returnType);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest) throws Exception
    {
        Result result = new Result();
        result.setResult(returnValue);
        proxyObject.handleReturnValue(result, returnType, mavContainer, webRequest);
    }
}

  1. 将自定义的处理类作为bean提交给框架
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;

@Configuration
public class OutputConfig implements InitializingBean
{
    @Autowired
    private RequestMappingHandlerAdapter handlerAdapter;

    @Override
    public void afterPropertiesSet() throws Exception
    {
        List<HandlerMethodReturnValueHandler> list = handlerAdapter.getReturnValueHandlers();
        List<HandlerMethodReturnValueHandler> newList = new ArrayList<>();
        if (null != list)
        {
            for (HandlerMethodReturnValueHandler valueHandler : list)
            {
                if (valueHandler instanceof RequestResponseBodyMethodProcessor)
                {
                    OutputProxy proxy = new OutputProxy(valueHandler);
                    newList.add(proxy);
                }
                else
                {
                    newList.add(valueHandler);
                }
            }
        }
        handlerAdapter.setReturnValueHandlers(newList);
    }
}
  1. 添加业务异常的包装类MyException
import javax.servlet.ServletException;

public class MyException extends RuntimeException
{
    private static final long serialVersionUID = 881236006282985783L;

    private static final Integer STACK_INDEX = 2;

    public MyException(String msg)
    {
        super(msg);
        String position = Thread.currentThread().getStackTrace()[STACK_INDEX].getClassName() + "."
                + Thread.currentThread().getStackTrace()[STACK_INDEX].getMethodName() + "("
                + Thread.currentThread().getStackTrace()[STACK_INDEX].getFileName() + ":"
                + Thread.currentThread().getStackTrace()[STACK_INDEX].getLineNumber() + ")";
        System.err.println(msg + "    " + position);
    }

}
  1. 添加业务异常处理
import java.util.List;

import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import demo.entity.Result;
import demo.utils.ResultUtil;

@ControllerAdvice
public class ExceptionHandle
{
    private static final int MSG_NUM = 501;
    private static final int VALID_NUM = 502;
    private static final int USUAL_NUM = 500;

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public Result handle(Exception e)
    {
        if (e instanceof MyException)
        {
            return ResultUtil.error(MSG_NUM, e.getMessage());
        }
        else if (e instanceof MethodArgumentNotValidException)
        {
            BindingResult result = ((MethodArgumentNotValidException) e).getBindingResult();
            List<ObjectError> errors = result.getAllErrors();
            ObjectError error = errors.get(errors.size() - 1);
            return ResultUtil.error(VALID_NUM, error.getDefaultMessage());
        }
        else
        {
            e.printStackTrace();
            return ResultUtil.error(USUAL_NUM, e.getMessage());
        }
    }
}

小结:

  1. 通过返回值封装可以使我们的代码更简洁
    在类上添加@RestController注解
    直接返回java类(例如 一个包含元素56的数组)
    前台就可以得到如下json
{
	"status": "success",
	"msg": "",
	"code": 200,
	"result": [56]
}
  1. 通过业务异常处理可以使我们的代码逻辑更清晰 例如:
    当我们认为前台传来的某个值不应为**空*时 只要
if (!StringUtils.hasLength(id)) {
    throw new MyException("id不应为空");
}

前台就可以得到如下json

{
	"status": "error",
	"msg": "id不应为空",
	"code": 501,
	"result": null
}

posted on 2021-03-01 21:50  柴刀  阅读(123)  评论(0编辑  收藏  举报

导航