springboot后台统一返回处理

后台在接收前端请求数据的时候,后端处理完需要对前端请求的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的异常处理。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值