Spring boot-返回值封装与业务异常
对于spring来说 返回值封装与业务异常 是一项很古老却实用的技术
然而在我上一份工作的时候依然碰到公司的新项目没有这2步处理
在SpringMVC时期已经可以通过xml配置达成以上目的
不过xml配置太过繁琐而且不容易排错 远不如Spring boot的注解+java代码清爽
以下将逐步详述配置方法
- 在***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>
- 添加通用返回值的包装类Result
import lombok.Data;
@Data
public class Result {
private String status = "success";
private String msg = "";
private int code = 200;
private Object result;
}
- 实现自定义的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);
}
}
- 将自定义的处理类作为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);
}
}
- 添加业务异常的包装类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);
}
}
- 添加业务异常处理
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());
}
}
}
小结:
- 通过返回值封装可以使我们的代码更简洁
在类上添加@RestController注解
直接返回java类(例如 一个包含元素56的数组)
前台就可以得到如下json
{
"status": "success",
"msg": "",
"code": 200,
"result": [56]
}
- 通过业务异常处理可以使我们的代码逻辑更清晰 例如:
当我们认为前台传来的某个值不应为**空*时 只要
if (!StringUtils.hasLength(id)) {
throw new MyException("id不应为空");
}
前台就可以得到如下json
{
"status": "error",
"msg": "id不应为空",
"code": 501,
"result": null
}