问题描述

在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. C# 控制台使用 UAC 权限

    原文:C# 控制台使用 UAC 权限 本文告诉大家如何在 C# 控制台项目使用 UAC 权限.这个方法在 WPF 和 控制台都是可以使用. 右击项目,点击添加文件,找到程序清单 在 WPF 使用 UA ...

  2. git撤销操作总结

    git checkout . #本地所有修改的.没有的提交的,都返回到原来的状态 git stash #把所有没有提交的修改暂存到stash里面.可用git stash pop回复. git rese ...

  3. Linq知识小总结

    一.投影操作符 Select Select操作符对单个序列或集合中的值进行投影. 返回 IEnumerable<类名> //查询语法 var query = from e in db.Em ...

  4. 纯洁CSS3实现图片墙

    预赛 DIV+CSS基金会 CSS3的transform 和 transition说明 主要用于transform的rotate/scale 动画过渡的几个參数(transition-property ...

  5. Android中SQLite数据库操作(1)——使用SQL语句操作SQLite数据库

    下面是最原始的方法,用SQL语句操作数据库.后面的"Android中SQLite数据库操作(2)--SQLiteOpenHelper类"将介绍一种常用的android封装操作SQL ...

  6. 《北京IT报道》你可以成为下一个《万万没有想到》?

    10一个月29当天上午,一位名为<北京IT报道>在视频短剧IT朋友谁快速刷新的互联网商业圈.这种制作粗糙.演员表情僵硬.安置赤裸网络剧,但对布局和内容因IT互联网从业者的生活,深受广大用户 ...

  7. 绑定到异步的ObservableCollection

    原文:绑定到异步的ObservableCollection 在进行WPF开发过程中,需要从一个新的线程中操作ObservableCollection,结果程序抛出一个NotSupportedExcep ...

  8. Java和Flex积分误差(两)

    1.错误原因 usage: java org.apache.catalina.startup.Catalina [ -config {pathname} ] [ -nonaming ] { -help ...

  9. 初次使用glog

    一.安装配置 1.简单介绍 google 出的一个C++轻量级日志库,支持下面功能: ◆ 參数设置,以命令行參数的方式设置标志參数来控制日志记录行为: ◆ 严重性分级,依据日志严重性分级记录日志: ◆ ...

  10. struts1和struts2安全线

    Servlet的生命周期是"初始化->init->service->destroy->卸载". 这里大家都知道,我们在web.xml里面定义一个servle ...