问题描述

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

  

spring3升级到spring4通用异常处理返回jsonp多了/**/的解决办法的更多相关文章

  1. 移动端点击返回时强制页面刷新解决办法(pageshow)

    在做移动端项目的时候经常遇到这样一个功能比如: 返回后页面不刷新,一些失效的信息依然显示在页面上.这个问题在iphone手机上会出现,在Android手机上返回时会自动刷新(由于手机机器种类不多,无法 ...

  2. windows7系统下升级到IE11时无法使用F12开发人员工具的解决办法

    windows7系统下升级到IE11时,发现F12开发人员工具无法使用,打开都是空白的 解决办法,就是下载IE11的补丁,下载地址为:https://www.microsoft.com/zh-CN/d ...

  3. Hibernate查询视图返回null问题说明及解决办法

    在Hibernate中对含有主键的单表操作比较简单,直接使用Hibernate针对数据库表对象进行反向生成代码,直接调用就可以了.但是在实际项目当中,经常会用到不少的多表联合查询操作,网上有很多示例, ...

  4. IAR升级之后,编译stm32官方工程报错的解决办法

    IAR升级之后,打开stm32官方例程,编译时提示如下错误: Error[Pe147]: declaration is incompatible with "__nounwind __int ...

  5. 解决spring3升级到spring4后jackjson报错

    1.这里说的是基于spring+springmvc+hibernate框架(其实跟持久层框架也没关系) 2.首先是springmvc的配置,处理json数据都会用到的.第5行是spring-4.x的写 ...

  6. Spring3升级到Spring4时, 运行时出现找不到MappingJacksonHttpMessageConverter的情况

    [org.springframework.web.context.ContextLoader]Context initialization failed org.springframework.bea ...

  7. spring3升级到spring4

    升级又失败了,dao层太多要改了,记录一下修改的内容,也是没白费我一下午时间 1. org.springframework.orm.hibernate3.annotation.AnnotationSe ...

  8. @ControllerAdvice全局异常处理不起作用原因及解决办法

    这段时间使用springboot搭建基础框架,作为springboot新手,各种问题都有. 当把前端框架搭建进来时,针对所有controller层的请求,所发生的异常,需要有一个统一的异常处理,然后返 ...

  9. phpMyAdmin - 错误 您应升级到 MySQL 5.5.0 或更高版本,解决办法。。。

    折腾自己的个人网站,装了个数据库管理工具,遇到您应升级到 MySQL 5.5.0 或更高版本... 采用降级phpmyadmin版本的方法解决了: 查找phpmyadmin/libraries/com ...

随机推荐

  1. JS中构造函数与原型对象的同名属性,实例会取哪一个

    构造函数与原型对象的同名属性,实例会取哪一个? 看了下面的过程,再回忆JS高程3里关于这部分的示意图.实例my在new的时候,本身就获得了a属性,所以my.a是1,倘若在new的时候如果没有赋予a属性 ...

  2. android 流量统计

    1 android通过架构流量统计TrafficStats类可以直接获得     获得总流量受理TrafficStats.getTotalRxBytes(),     获得总传出流量TrafficSt ...

  3. php自动加载类文件探讨,spl_autoload_register自动加载原理

    spl_autoload_register函数是实现自动加载未定义类功能的的重要方法,所谓的自动加载意思就是 我们的new 一个类的时候必须先include或者require的类文件,如果没有incl ...

  4. Obtaining Directory Change Notifications(微软的例子,使用FindFirstChangeNotification,FindNextChangeNotification,FindCloseChangeNotification API函数)

    An application can monitor the contents of a directory and its subdirectories by using change notifi ...

  5. wpf控件开发基础(2) -属性系统(1)

    原文:wpf控件开发基础(2) -属性系统(1) 距离上篇写的时间有1年多了.wpf太大,写的东西实在太多,我将依然围绕着自定义控件来展开与其相关的技术点. 也欢迎大家参与讨论.这篇我们将要讨论的是W ...

  6. Swift程式语言(中国版)(8.8 %)

    前言 今天Apple宣布了一项新的编程语言Swift.还提供了一个近400页The Swift Programming Language(Swift程式语言). 虽然我没有开发者账户.不能实际锻炼机S ...

  7. Wireshark非标准分析port无流量

    Wireshark非标准分析port无流量 2.2.2  非标准分析port无流量Wireshark非标准分析port流量 应用程序执行使用非标准port号总是网络分析专家最关注的.关注该应用程序是否 ...

  8. C#选择多个文件并读取多个文件数据

    原文:C#选择多个文件并读取多个文件数据 版权声明:本文为博主原创文章,转载请附上链接地址. https://blog.csdn.net/ld15102891672/article/details/8 ...

  9. WPF中实现图片文件转换成Visual对象,Viewport3D对象转换成图片

    原文:WPF中实现图片文件转换成Visual对象,Viewport3D对象转换成图片 1.图片文件转换成Visual对象 private Visual CreateVisual(string imag ...

  10. 面向对象举例(一) —— 顶点(vertex)、边(edge)与图(graph)

    Graph: class Graph(dict): def __init__(self, vs=[], es=[]): for v in vs: self.add_vertex(v) for e in ...