在做需求开发的时候,碰到一个需求:某个操作可能会失败(因为数据或其他原因导致了异常),后台只是捕获了异常,然后笼统的提示该操作失败。但是这样不能从页面直接看到异常原因,由于这个功能是我们公司自己的人员使用的,后台领导要求把异常的详细信息都展示在页面上或者存储到数据库的日志表中。这样可以方便的去解决这个异常。
Exception的方法中,用的最多的是getMessage()和printStackTrace(),前者获取的信息太少,无法定位到异常出现的类、方法和行数;后者可以打印异常堆栈的详细信息,但是它没有返回值,我们也就无法获取到信息进行展示和存储。通过查询资料,发现org.apache.commons.lang.exception包下面有一个异常相关的工具类:ExceptionUtils,它里面有一个方法,可以获取到异常对象Exception的完整信息,并且是String类型的:
//拿到日志栈的完整信息
String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e);
它得到的信息是详细下堆栈信息,举例如下:
java.lang.StringIndexOutOfBoundsException: String index out of range: -13
at java.lang.String.substring(String.java:1931)
at com.chinacreator.approve.service.LocalOrganizationService_new.handlerXzcfData_new(LocalOrganizationService_new.java:1224)
at com.chinacreator.approve.service.LocalOrganizationService_new.updateApproveXzcf_new(LocalOrganizationService_new.java:1183)
at com.chinacreator.approve.service.LocalOrganizationService_new.mergeOrgOperationForUpdate(LocalOrganizationService_new.java:973)
at com.chinacreator.approve.service.LocalOrganizationService_new$$FastClassBySpringCGLIB$$61ca30de.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:700)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:633)
at com.chinacreator.approve.service.LocalOrganizationService_new$$EnhancerBySpringCGLIB$$ad4a1df3.mergeOrgOperationForUpdate(<generated>)
at com.chinacreator.approve.web.rest.LocalOrganizationController.mergeOrg(LocalOrganizationController.java:246)
at sun.reflect.GeneratedMethodAccessor799.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:139)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:295)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:249)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:236)
at org.jboss.resteasy.springmvc.ResteasyHandlerAdapter.createModelAndView(ResteasyHandlerAdapter.java:96)
at org.jboss.resteasy.springmvc.ResteasyHandlerAdapter.handle(ResteasyHandlerAdapter.java:82)
at org.jboss.resteasy.springmvc.ResteasyHandlerAdapter.handle(ResteasyHandlerAdapter.java:26)
at org.jboss.resteasy.springmvc.ResteasyWebHandlerTemplate.handle(ResteasyWebHandlerTemplate.java:39)
at org.jboss.resteasy.springmvc.ResteasyHandlerAdapter.handle(ResteasyHandlerAdapter.java:47)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:919)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:851)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:855)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:755)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:829)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1496)
at com.chinacreator.asp.comp.sys.oauth2.common.spi.DefaultSpi.onTokenCheckSuccess(DefaultSpi.java:67)
at com.chinacreator.asp.comp.sys.oauth2.sso.client.filter.OAuth2SSOFilter.handleInnerCall(OAuth2SSOFilter.java:537)
at com.chinacreator.asp.comp.sys.oauth2.sso.client.filter.OAuth2SSOFilter.doAuthcFilter(OAuth2SSOFilter.java:463)
at com.chinacreator.asp.comp.sys.oauth2.sso.client.filter.OAuth2SSOFilter.doFilter(OAuth2SSOFilter.java:99)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1484)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1484)
at filter.AccessFilter.doFilter(AccessFilter.java:35)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1484)
at com.chinacreator.c2.web.filter.GZIPFilter.doFilter(GZIPFilter.java:74)
at com.chinacreator.c2.web.filter.Filter.doFilter(Filter.java:69)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1476)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:499)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:557)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:428)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.Server.handle(Server.java:370)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)
at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:982)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:1043)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:865)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:240)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:667)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
at java.lang.Thread.run(Thread.java:748)
可以看到它的内容是比较多的,如果全部显示在页面不太合适,所以可以只截取前面那些跟我们自己的代码相关的即可,因此最终我的处理方式如下:
} catch (Exception e) {
e.printStackTrace();
//拿到日志栈的完整信息
String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e);
if(fullStackTrace.length()>1000){
fullStackTrace = fullStackTrace.substring(0,1000);
}
LOG.error("修改目录引用表失败,异常信息:" + e.toString());
throw new RuntimeException("修改目录引用表失败,异常信息:" + fullStackTrace);
}
参考:https://my.oschina.net/u/1472917/blog/417232