1. 程式人生 > >spring3升級到spring4通用異常處理返回jsonp多了/**/的解決辦法

spring3升級到spring4通用異常處理返回jsonp多了/**/的解決辦法

static lte 彈出 protected rar temp model *** col

問題描述

在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 + "(");
        }

    }

原來問題是出現在這裏

spring3升級到spring4通用異常處理返回jsonp多了/**/的解決辦法