zoukankan      html  css  js  c++  java
  • spring3升级到spring4通用异常处理返回jsonp多了/**/的解决办法

    问题描述

    在spring3中定义了通用的异常处理,具体代码如下:

    public class CommonExceptionHandler implements HandlerExceptionResolver {
        
        private static final Logger logger = LoggerFactory.getLogger(CommonExceptionHandler.class);
    
        @Override
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
                Exception ex) {
    
            ModelAndView mv = new ModelAndView();
            Map<String,Object> model=new HashMap();
    
            mv.addObject("code", 0);
            model.put("errorCode", 0);
            model.put("errorMessage", "系统异常");
            
            logger.info("未捕获处理异常日志开始:");
            logger.info(ex.toString());
            logger.error("System error",ex);
            mv.addObject("model",model);
            return mv;
        }
    
    }
    <bean id="exceptionResolver" class="com.******.exception.CommonExceptionHandler" />

    因为项目前后端分离,前端使用jsonp读取api数据,spring升级后发现如果出现异常前端js没有弹出提示,调试发现返回的数据中多了/**/。

    /**/jQuery172038147174217261703_1533279228074({******});
    

    分析问题

    跟踪源代码调试进入DispatcherServlet:

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
            boolean errorView = false;
            if (exception != null) {
                if (exception instanceof ModelAndViewDefiningException) {
                    this.logger.debug("ModelAndViewDefiningException encountered", exception);
                    mv = ((ModelAndViewDefiningException)exception).getModelAndView();
                } else {
                    Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
                    mv = this.processHandlerException(request, response, handler, exception);
                    errorView = mv != null;
                }
            }
    
            if (mv != null && !mv.wasCleared()) {
                this.render(mv, request, response);
                if (errorView) {
                    WebUtils.clearErrorRequestAttributes(request);
                }
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
            }
    
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
                }
    
            }
        }

    继续跟踪进入render方法:

    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
            Locale locale = this.localeResolver.resolveLocale(request);
            response.setLocale(locale);
            View view;
            if (mv.isReference()) {
                view = this.resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
                if (view == null) {
                    throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
                }
            } else {
                view = mv.getView();
                if (view == null) {
                    throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
                }
            }
    
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'");
            }
    
            try {
                if (mv.getStatus() != null) {
                    response.setStatus(mv.getStatus().value());
                }
    
                view.render(mv.getModelInternal(), request, response);
            } catch (Exception var7) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'", var7);
                }
    
                throw var7;
            }
        }

    然后进入AbstractView里面的render方法:

    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Rendering view with name '" + this.beanName + "' with model " + model + " and static attributes " + this.staticAttributes);
            }
    
            Map<String, Object> mergedModel = this.createMergedOutputModel(model, request, response);
            this.prepareResponse(request, response);
            this.renderMergedOutputModel(mergedModel, this.getRequestToExpose(request), response);
        }

    this.renderMergedOutputModel发现是一个abstract方法,继续追踪实现类AbstractJackson2View:

    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
            OutputStream stream = this.updateContentLength ? this.createTemporaryOutputStream() : response.getOutputStream();
            Object value = this.filterAndWrapModel(model, request);
            this.writeContent((OutputStream)stream, value);
            if (this.updateContentLength) {
                this.writeToResponse(response, (ByteArrayOutputStream)stream);
            }
    
        }

    继续跟踪 this.writeContent:

    protected void writeContent(OutputStream stream, Object object) throws IOException {
            JsonGenerator generator = this.objectMapper.getFactory().createGenerator(stream, this.encoding);
            this.writePrefix(generator, object);
            Class<?> serializationView = null;
            FilterProvider filters = null;
            Object value = object;
            if (object instanceof MappingJacksonValue) {
                MappingJacksonValue container = (MappingJacksonValue)object;
                value = container.getValue();
                serializationView = container.getSerializationView();
                filters = container.getFilters();
            }
    
            if (serializationView != null) {
                this.objectMapper.writerWithView(serializationView).writeValue(generator, value);
            } else if (filters != null) {
                this.objectMapper.writer(filters).writeValue(generator, value);
            } else {
                this.objectMapper.writeValue(generator, value);
            }
    
            this.writeSuffix(generator, object);
            generator.flush();
        }

    继续跟踪 this.writePrefix,发现是一个未实现的方法,子类具有重写,继续跟踪 MappingJackson2JsonView :

    protected void writePrefix(JsonGenerator generator, Object object) throws IOException {
            if (this.jsonPrefix != null) {
                generator.writeRaw(this.jsonPrefix);
            }
    
            String jsonpFunction = null;
            if (object instanceof MappingJacksonValue) {
                jsonpFunction = ((MappingJacksonValue)object).getJsonpFunction();
            }
    
            if (jsonpFunction != null) {
                generator.writeRaw("/**/");
                generator.writeRaw(jsonpFunction + "(");
            }
    
        }

    原来问题是出现在这里

    解决思路

    既然是序列化过程中出现问题,那就不走序列化,直接输出json。

    @ExceptionHandler(Exception.class)
    public void handlingException(HttpServletRequest request, HttpServletResponse response, Exception exception){
    
        Map<String,Object> model=new HashMap();
        model.put("result", "FAULT");
        model.put("errorCode", 0);
        model.put("errorMessage", "系统异常");
        logger.info("未捕获处理异常日志开始:");
        logger.info(exception.toString());
        logger.error("System error",exception);
    
        String callBack = request.getParameter("callback");
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Cache-Control", "no-cache, must-revalidate");
    
        try {
            String json = JSON.toJSONString(model);
            if(StringUtils.isNotBlank(callBack)){
                response.getWriter().write(callBack+"("+json+");");
            }else{
                response.getWriter().write(json);
            }
        } catch (IOException e) {
            logger.error("与客户端通讯异常:"+ e.getMessage(), e);
        }
    }

      

  • 相关阅读:
    Silverlight & Blend动画设计系列三:缩放动画(ScaleTransform) from http://www.cnblogs.com/beniao/archive/2010/03/26/1694157.html
    基于知识库的信息推荐系统
    观察者模式之:一个游戏设想
    Expression Blend制作画卷效果 from http://www.cnblogs.com/alexis/archive/2010/12/23/1915402.html
    为了忘却的生活
    C 文件读写
    VC++中,CString,in,char,等数据类型的相互转化 from:http://blog.csdn.net/heaven13483/article/details/7553176
    【ML2】最小二乘法(least squares)介绍
    机器学习的基本概念
    【ML95】SVM的sklearn.svm.SVC()函数应用
  • 原文地址:https://www.cnblogs.com/qiangking/p/9411586.html
Copyright © 2011-2022 走看看