赞
踩
后台在接收前端请求数据的时候,后端处理完需要对前端请求的ajax或者H5页面的跳转做统一的返回处理,同时也需要对可能造成的异常进行全局统一处理,使当程序运行异常的时候ajax返回统一的异常码,H5请求跳转到统一的错误提示页面。
1、先对全局正常返回类进行包装
@RestControllerAdvice(basePackages = {"com.xxx.xxx.v2"}) public class ControllerResponseAdvice implements ResponseBodyAdvice<Object> { private static final Logger logger = LoggerFactory.getLogger(ControllerResponseAdvice.class); @Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { // response是ResultVo类型,或者注释了NotControllerResponseAdvice都不进行包装 return !(methodParameter.getParameterType().isAssignableFrom(ResultVo.class) || methodParameter.hasMethodAnnotation(NotControllerResponseAdvice.class)); } @Override public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { // String类型不能直接包装 if (returnType.getGenericParameterType().equals(String.class)) { ObjectMapper objectMapper = new ObjectMapper(); try { // 将数据包装在ResultVo里后转换为json串进行返回 return objectMapper.writeValueAsString(new ResultVo(data)); } catch (Exception e) { e.printStackTrace(); } } // 否则直接包装成ResultVo返回 return new ResultVo(data); } }
ResultVo 为统一返回的包装类方便前台统一解析。
public class ResultVo { // 状态码 private int code; // 状态信息 private String msg; // 返回对象 private Object data; // 手动设置返回vo public ResultVo(int code, String msg, Object data) { this.code = code; this.msg = msg; this.data = data; } // 默认返回成功状态码,数据对象 public ResultVo(Object data) { this.code = ResultCode.SUCCESS.getCode(); this.msg = ResultCode.SUCCESS.getMsg(); this.data = data; } // 返回指定状态码,数据对象 public ResultVo(ResultCode resultCode, Object data) { this.code = resultCode.getCode(); this.msg = resultCode.getMsg(); this.data = data; } // 只返回状态码 public ResultVo(ResultCode resultCode) { this.code = resultCode.getCode(); this.msg = resultCode.getMsg(); this.data = null; } //省略get set方法 }
NotControllerResponseAdvice.class 这个类是一个注解,意思是忽略返回包装类,大概类似通信接口直接返回 success 就行了,需要要状态吗和返回数据体。注解这边写的可以先忽略注释掉。
这样的话当请求一个controller的时候在没有成功异常返回的都是正常的统一包装体了
@RestController @RequestMapping("/textApi") public class TextApi { @Autowired LoanService loanService; @RequestMapping("/queryLoan") public Loan queryLoan(){ //int i = 1/0; return loanService.queryById(40L); } @RequestMapping("/queryPage") public ModelAndView queryPage(){ //int i = 1/0; return new ModelAndView("/error"); } }
可以看到代码里面直接返回的实体类,但前端接口返回的是在面自动加了ResultVo。
后面还需要对可能的异常做一下统一返回的处理,模拟逻辑错误可以把
int i = 1/0;这行代码的注释放开进行模拟。
首先创建一个全局异常类的拦截处理,对异常进项包装返回前端
@Slf4j @RestControllerAdvice(basePackages = {"com.xxx.xxx.v2"}) public class GlobalExceptionHandlerV2 { private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandlerV2.class); /** * 请求格式为json */ private static final String APPLICATION_JSON = "application/json"; /** * 请求格式为xml */ private static final String XML_HTTP_REQUEST = "XMLHttpRequest"; /** * json后缀 */ private static final String JSON_SUFFIX = ".json"; /** * xml后缀 */ private static final String XML_SUFFIX = ".xml"; /** * 索引越界 */ private static final int INDEX_NOT_FOUND = -1; @ExceptionHandler(value = Exception.class) ModelAndView MethodArgumentNotValidExceptionHandler(Exception e, HttpServletRequest request){ //ajax 请求异常返回统一的错误码 if(isAjaxRequest(request)){ ModelAndView modelAndView=new ModelAndView(new MappingJackson2JsonView()); modelAndView.addObject(new ResultVo(ResultCode.VALIDATE_ERROR, e.getMessage())); e.printStackTrace(); return modelAndView; }else{ //H5页面报错返回统一的样式 ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("msg",e.getMessage()); modelAndView.setViewName("/error"); e.printStackTrace(); return modelAndView; } } /** * 是否是Ajax异步请求 * * @param request 客户端请求 * @return boolean */ public static boolean isAjaxRequest(HttpServletRequest request) { String accept = request.getHeader("accept"); if (accept != null && accept.contains(APPLICATION_JSON)) { return true; } String xRequestedWith = request.getHeader("X-Requested-With"); if (xRequestedWith != null && xRequestedWith.contains(XML_HTTP_REQUEST)) { return true; } String uri = request.getRequestURI(); if (inStringIgnoreCase(uri, JSON_SUFFIX, XML_SUFFIX)) { return true; } String ajax = request.getParameter("__ajax"); return inStringIgnoreCase(ajax, "json", "xml"); } /** * 是否包含字符串(不区分大小写) * * @param str 验证字符串 * @param searchStrings 字符串组 * @return boolean */ public static boolean inStringIgnoreCase(String str, String... searchStrings) { if (str != null && searchStrings != null) { for (String s : searchStrings) { if (str.equalsIgnoreCase(StringUtils.trim(s))) { return true; } } } return false; } }
这里面进行了请求是否为ajax的判断,若是前端为ajax则返回统一的JSON格式,若是H5的页面跳转则跳到统一的error页面,其中 MappingJackson2JsonView这个类需要了解一下。
这个就进行的错误的统一返回包装了,前端获取到数据判断下code 不为约定的成功就是代表数据有问题了。
这个总体可以理解为两个流程:
1、先实现数据的统一返回。
2、全局controller的异常处理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。