zoukankan      html  css  js  c++  java
  • spring 全局请求,根据请求类型返回json或html

    转 : https://blog.csdn.net/Dongguabai/article/details/110510818

    @ControllerAdvice 全局异常响应页面和 JSON

    我这里页面以 Thymeleaf 为例子,相关配置:

    spring:
      thymeleaf:
        cache: false
        mode: HTML5
        encoding: UTF-8
        prefix: classpath:/templates/

    判断是否是 AJAX:

    public static boolean isAjaxRequest(HttpServletRequest request) {
          return request.getHeader("x-requested-with") != null;
    }

    异常拦截器:

    /**
     * @author Dongguabai
     * @Description
     * @Date 创建于 2020-12-02 10:43
     */
    @ControllerAdvice
    @ResponseBody
    @Slf4j
    public class GlobalExceptionHandler {
    
        private static final String ERROR_PAGE = "error";
    
        @ExceptionHandler(Exception.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public Object handleException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Exception e) throws UnsupportedEncodingException {
            if (isAjaxRequest(httpServletRequest)){
                 //这里返回项目中自定义的统一响应对象即可
                return json(e);
            }
            return view(e);
        }
    
      这里返回项目中自定义的统一响应对象即可
        private ResponseX json(Exception e) {
            return new ResponseX();
        }
     
            //这里返回 ModelAndView 
        public ModelAndView view(Exception e) {
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setStatus(HttpStatus.BAD_REQUEST);
            modelAndView.setViewName(ERROR_PAGE);
            modelAndView.addObject("msg","msg");
            modelAndView.addObject("code","code");
            return modelAndView;
        }
    }

    error.html:

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <head th:insert="fragments/header"/>
        <title>error</title>
    </head>
    <body>
      <span th:text="${code}" ></span> - <span th:text="${msg}" ></span>
    </body>
    </html>

    这里补充说明下,建议不要使用拦截器做,当然不是说拦截器不行(处理响应流即可),主要是拦截器其实是无法处理 Controller 中的异常的:

    org.springframework.web.servlet.DispatcherServlet#triggerAfterCompletion:

        private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, Exception ex) throws Exception {
            if (mappedHandler != null) {
                mappedHandler.triggerAfterCompletion(request, response, ex);
            }
    
            throw ex;
        }

    转: https://www.jianshu.com/p/a9bcfe733713

    SpringBoot:Web项目中如何优雅的同时处理Json和Html请求的异常

    在一个web项目开发中,通常都会涉及到Html和Json请求。当出现异常的时候,我们需要根据请求类型返回不同的信息。如果是Json请求,那么就返回String或者ReponseEntity类型;如果是html请求,就要返回ModelAndView的错误页面。

    我们当然可以对Controller的每个接口方法抛出的异常单独处理。但这样做会导致大量的重复工作。Spring MVC为我们提供了@ControllerAdvice和@ExceptionHandler`两个注解来实现全局的异常处理。关于这两个注解的用法可以参考这里

    这解决了大部分的问题,但是如果同一个Controller中既有html又有json接口方法怎么办呢?我们当然可以拆分成两个Controller,一个包含html接口,另一个包含json接口。但是这样做不够灵活,而且我更习惯根据业务逻辑来归类接口。有没有更好的方法呢?

    其实在写异常处理方法时,我们可以将请求信息作为参数传入,并根据请求类型来返回不同的数据。


    public class BaseController{
        private Boolean isJson(HttpServletRequest request){
            String header = request.getHeader("content-type");
            return header != null && header.contains("json");
        }
    
        @Override
        @ExceptionHandler(BaseException.class)
        public Object handleBaseException(HttpServletRequest request, baseException e) {
            if(isJson(request)) {
                return ResponseUtils.restResponse(
                        e.getCode(),
                        e.getMessage(),
                        e.getStatus()
                );
            } else {
                ModelAndView modelAndView = initModelAndView();
                if (e.getCode().equalsIgnoreCase("login_first")) {
                    modelAndView.setViewName("redirect:/list");
                }
                if (e.getCode().equalsIgnoreCase("real_name_not_set")) {
                    modelAndView.setViewName("redirect:/account");
                }else{
                    modelAndView.setViewName("/404");
                }
                modelAndView.addObject("exception", e);
                return modelAndView;
            }
        }
    }

    这里我们写了一个BaseController,并在Controller中实现了异常捕获的逻辑。isJson()通过判断请求的Content-Type是否包含json字符串来判断该请求类型。当然,更好更合适的方式是通过包头中的Accept中的信息类判断。需要注意的是handleBaseException()方法返回了Object类型,这样我们就可以根据需要返回不同类型的数据了。以后只要Contrller继承BaseController就不用再考虑异常的问题了。

    但是,如果异常是在进入接口方法之前被抛出的呢。比如404,406错误,根本不会执行接口方法,因此也无法被ExceptionHandler捕获。这部分异常如何处理呢?

    Spring Boot提供了一个统一的/error地址用于所有未被捕获的异常抛出。默认设置下显示的是一个whitelabel error page


    通过实现ErrorController,我们可以定制这个错误页面。
    @Controller
    public class MpErrorController extends BaseController implements ErrorController {
        private static final String PATH = "/error";
    
        @RequestMapping(value = PATH)
        public Object error() throws Exception {
            throw new BaseException();
        }
    
        @Override
        public String getErrorPath() {
            return PATH;
        }
    }

    我们希望这个error页面也根据请求的类型做出不同的逻辑处理。因此,可以直接在error()抛出BaseException异常,并且让这个Controller继承于BaseController。这样,被抛出的异常也会被handleBaseException()捕获了。

    至此,我们比较优雅的实现了全局的异常处理。所有的BaseException异常处理逻辑都集中在handleBaseException()方法中。




  • 相关阅读:
    正则表达式(转)
    Collections中的shuffle()方法
    Fermat定理
    哈希算法(转)
    Hungarian method (匈牙利算法)----解决指派问题(转)
    蒙塔卡洛模拟
    线程的礼让
    线程间的沟通
    安装rlwrap
    yum切到光盘源
  • 原文地址:https://www.cnblogs.com/fps2tao/p/14576622.html
Copyright © 2011-2022 走看看