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);
}
}
spring3升级到spring4通用异常处理返回jsonp多了/**/的解决办法的更多相关文章
- 移动端点击返回时强制页面刷新解决办法(pageshow)
在做移动端项目的时候经常遇到这样一个功能比如: 返回后页面不刷新,一些失效的信息依然显示在页面上.这个问题在iphone手机上会出现,在Android手机上返回时会自动刷新(由于手机机器种类不多,无法 ...
- windows7系统下升级到IE11时无法使用F12开发人员工具的解决办法
windows7系统下升级到IE11时,发现F12开发人员工具无法使用,打开都是空白的 解决办法,就是下载IE11的补丁,下载地址为:https://www.microsoft.com/zh-CN/d ...
- Hibernate查询视图返回null问题说明及解决办法
在Hibernate中对含有主键的单表操作比较简单,直接使用Hibernate针对数据库表对象进行反向生成代码,直接调用就可以了.但是在实际项目当中,经常会用到不少的多表联合查询操作,网上有很多示例, ...
- IAR升级之后,编译stm32官方工程报错的解决办法
IAR升级之后,打开stm32官方例程,编译时提示如下错误: Error[Pe147]: declaration is incompatible with "__nounwind __int ...
- 解决spring3升级到spring4后jackjson报错
1.这里说的是基于spring+springmvc+hibernate框架(其实跟持久层框架也没关系) 2.首先是springmvc的配置,处理json数据都会用到的.第5行是spring-4.x的写 ...
- Spring3升级到Spring4时, 运行时出现找不到MappingJacksonHttpMessageConverter的情况
[org.springframework.web.context.ContextLoader]Context initialization failed org.springframework.bea ...
- spring3升级到spring4
升级又失败了,dao层太多要改了,记录一下修改的内容,也是没白费我一下午时间 1. org.springframework.orm.hibernate3.annotation.AnnotationSe ...
- @ControllerAdvice全局异常处理不起作用原因及解决办法
这段时间使用springboot搭建基础框架,作为springboot新手,各种问题都有. 当把前端框架搭建进来时,针对所有controller层的请求,所发生的异常,需要有一个统一的异常处理,然后返 ...
- phpMyAdmin - 错误 您应升级到 MySQL 5.5.0 或更高版本,解决办法。。。
折腾自己的个人网站,装了个数据库管理工具,遇到您应升级到 MySQL 5.5.0 或更高版本... 采用降级phpmyadmin版本的方法解决了: 查找phpmyadmin/libraries/com ...
随机推荐
- 获取全局上下文(getApplicationContext)_创建Shared Preference工具类_实现自动登录
获取全局上下文(getApplicationContext)_创建Shared Preference工具类_实现自动登录 ===========================获取全局上下文(getA ...
- C# await 高级用法
原文:C# await 高级用法 本文告诉大家 await 的高级用法,包括底层原理. 昨天看到太子写了一段代码,我开始觉得他修改了编译器,要不然下面的代码怎么可以编译通过 await "林 ...
- HTTP协议(一些报头字段的作用,如cace-control、keep-alive)
---恢复内容开始--- Http连接是一种短连接,是一种无状态的连接. 所谓的无状态,是指浏览器每次向服务器发起请求的时候,不是通过一个连接,而是每次都建立一个新的连接. 如果是一个连接的话,服务器 ...
- Qt、Qte与Qtopia(Qt嵌入式的发展历程)
Qt的授权是分为两条线,商业版和开源版.如果使用商业版的Qt,那么开发出的程序可以是私有的和商业的:如果使用的是开源版的Qt,由于其使用的是GPL协议,那么可发出的程序也必须是GPL的.不过自从qt ...
- spring cloud eureka 服务端开启密码认证后,客户端无法接入问题
Eureka服务端开启密码的认证比较简单 在pom文件中加入: <dependency> <groupId>org.springframework.boot</group ...
- Emoji:搜索将与您找到表情符号背后的故事
眼下.秉已经开始支持emoji搜索,这意味着,你可以插入或粘贴系列emoji表情,让我们的爱.微笑.食品等..些表情随意组合,必应总会带给你非常多有趣的但却没有不论什么实际用途的搜索结果. 这是一项非 ...
- 【狼窝乀野狼】Windows Server 2008 R 配置 Microsoft Server 2008 远程登录连接
如果你已经了解了,或者你已经经历了,那么此篇文章对你是毫无用处.因为文笔深处未必有自己亲身体验来的真实有效. 闲话少说,直接上菜. 最近脑子“抽筋”,想安装一个服务器来玩玩,那么怎么选择呢?我的PC是 ...
- wpf XMAL中隐藏控件
原文:wpf XMAL中隐藏控件 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a771948524/article/details/9264569 ...
- 构建自己的PHP框架(日志)
完整项目地址:https://github.com/Evai/Aier 日志在程序开发中有着十分重要的作用,帮助开发者更快的找到程序错误并即时处理.下面制作一个非常简单的记录日志类. 在 servic ...
- WPF中StringFormat的用法
原文:WPF中StringFormat的用法 WPF中StringFormat的用法可以参照C#中string.Format的用法 1. C#中用法: 格式化货币(跟系统的环境有关,中文系统默认格式化 ...