Spring实现统一捕获接口层异常与邮件警报
Java中提供的try{}catch{}finally{}
来进行异常捕获,然后当系统业务复杂,代码量则多,为了排除系统错误,我们一般在接口层进行异常捕获,捕获到异常时打印日志,通过日志的方式来排除错误。系统越复杂,接口数量越多,如果我们对所有接口都try{}catch{}
的话,那么工作量不仅会很大,以后系统维护难度也会变大。然后SpringMvc在框架层提供给了一种接口层统一处理异常的方法。
- @ExceptionHandler:统一处理某一类异常,从而能够减少代码重复率和复杂度。
public abstract class AbstractController {protected Logger log = LoggerFactory.getLogger(this.getClass());@ExceptionHandler@ResponseBodypublic String handleException(HttpServletRequest request, HttpServletResponse response, Exception ex){if(!(ex instanceof NoNeedHandlerException)){log.error("{}:\n接口参数:{}\n{}", request.getRequestURI(), JSONObject.toJSONString(request.getParameterMap()),CommonMail.getFromException(ex));MonitorInfo monitorInfo = new MonitorInfo();monitorInfo.setMethodName(request.getRequestURI());monitorInfo.setParams(request.getParameterMap());monitorInfo.setException(ex);ExceptionMonitorHelper.monitor(monitorInfo);}else{log.info("{}:\n接口参数:{}\n{}", request.getRequestURI(), JSONObject.toJSONString(request.getParameterMap()), ex.getMessage());}if (ex instanceof HandlerException){HandlerException exception = (HandlerException)ex;return FmtResult(false, exception.getExceptionCode(), exception.getMessage(), "");}return FmtResult(false, ResultCode.CODE_ERROR, ResultCode.ERROR_MESSAGE, "");}}
只需要在handleException对异常进行进行处理即可,这样接口层的异常全部在这个地方统一处理,开发成本和维护成本大大减低。
- 邮件监控与警报
对于一些异常信息,一般都是通过打印日志的方式来记录,通过日志的方式去追溯错误。但是日志很多(尤其是日志打印不规范),很难定位,日志的及时性差,并不能及时通知到开发和运维人员线上错误,尤其是一些线上严重bug。在这里可以通过邮件警报的方式来对系统进行监控。
具体实现如下:
/*** ZSQ 监控信息类*/
public class MonitorInfo {private String methodName;private Map<String, ?> params;private Exception exception;public String getMethodName() {return methodName;}public void setMethodName(String methodName) {this.methodName = methodName;}public Map<String, ?> getParams() {return params;}public void setParams(Map<String, ?> params) {this.params = params;}public Exception getException() {return exception;}public void setException(Exception exception) {this.exception = exception;}
}
/*** ZSQ 2018年4月8日14:39:51* 异常监控类*/
public class ExceptionMonitorHelper {private static final Logger logger = LoggerFactory.getLogger(ExceptionMonitorHelper.class);private static final LinkedBlockingQueue<MonitorInfo> queue = new LinkedBlockingQueue<>(0xfff8);private Thread monitorThread;private volatile boolean isStop = false;public static String ENVIROMENT = null;public void start(){monitorThread = new Thread(new Runnable() {@Overridepublic void run() {while (!isStop) {try {//可以调用queue.drainTo来批量处理异常信息,提升读取速率,减少加锁和释放锁的次数MonitorInfo moniterInfo = queue.take();if (!(moniterInfo.getException() instanceof NoNeedHandlerException)) {logger.debug("接口处理错误:{},{}", JSONObject.toJSONString(moniterInfo), moniterInfo.getException());if (DEV_EMAILS != null) {CommonMail.sendCodeWarnEmail(ENVIROMENT , moniterInfo, ExceptionLevel.SERIOUS);}}} catch (Exception e) {logger.error("exception monitor error {}", e);}}}});monitorThread.setDaemon(true);//设置为守护线程 主线程退出时即退出monitorThread.start();logger.info("exception monitor start");}public void stop(){isStop = true;monitorThread.interrupt();try {monitorThread.join();} catch (InterruptedException e) {logger.error(e.getMessage(), e);}}public static void monitor(MonitorInfo failInfo){try {queue.put(failInfo);} catch (InterruptedException e) {logger.error("exception monitor put error{}", e);}}
}
/***
邮件工具类
**/
public class CommonMail {private static final String NAME = "网";private static final String USERNAME = "system@qq.com";private static final String PASSWD = "Qi123456";private static String MAILHOST = "smtp.exmail.qq.com";// 发送邮件的主机private static int SMTPPORT = 465;private static boolean TLS = true;private static boolean DEBUG = true;private static boolean SSL = true;//开发者邮箱配置private static String DEV_USERNAME;private static String DEV_PASSWD;private static String DEV_NAME;public static String []DEV_EMAILS;static {MAILHOST = ConfigPropertyConfigurer.getContextProperty("mail.mailhost") == null ? "smtp.exmail.qq.com" : ConfigPropertyConfigurer.getContextProperty("mail.mailhost");SMTPPORT = ConfigPropertyConfigurer.getContextProperty("mail.smtpport") == null ? 465 : Integer.parseInt( ConfigPropertyConfigurer.getContextProperty("mail.smtpport"));TLS = ConfigPropertyConfigurer.getContextProperty("mail.tls") == null ? true : Boolean.parseBoolean(ConfigPropertyConfigurer.getContextProperty("mail.tls"));DEBUG = ConfigPropertyConfigurer.getContextProperty("mail.debug") == null ? false : Boolean.parseBoolean(ConfigPropertyConfigurer.getContextProperty("mail.debug"));SSL = ConfigPropertyConfigurer.getContextProperty("mail.ssl") == null ? false : Boolean.parseBoolean(ConfigPropertyConfigurer.getContextProperty("mail.ssl"));DEV_USERNAME = ConfigPropertyConfigurer.getContextProperty("dev.mail.username");DEV_PASSWD = ConfigPropertyConfigurer.getContextProperty("dev.mail.password");DEV_NAME = ConfigPropertyConfigurer.getContextProperty("dev.mail.name");DEV_EMAILS = ConfigPropertyConfigurer.getContextProperty("dev.mail.receivers").split(",");}public static void sendDevEmail(String[] receivers, String subject, String msg){System.setProperty("java.net.preferIPv4Stack", "true");final SimpleEmail email = new SimpleEmail();email.setTLS(TLS);email.setDebug(DEBUG);email.setSSL(SSL);email.setHostName(MAILHOST);email.setSmtpPort(SMTPPORT);email.setAuthenticator(new DefaultAuthenticator(DEV_USERNAME, DEV_PASSWD));try {email.setFrom(DEV_USERNAME, DEV_NAME);for(String receiver:receivers){email.addTo(receiver);} email.setCharset("GB2312");email.setSubject(subject);email.setMsg(msg);new Thread(){ public void run() {try {email.send();} catch (EmailException e) { e.printStackTrace();} } }.start();} catch (EmailException e) {e.printStackTrace();}} public static void sendCodeWarnEmail(final String subject, final String msg, int type){ String sub = "系统警报";if(1 == type){sub += "严重错误";}else if(2 == type){sub += "普通错误";}else if(3 == type){sub += "非预期结果";}sub += subject;final String tsub = sub; sendDevEmail(DEV_EMAILS, tsub, msg); }public static void sendCodeWarnEmail(String enviroment, MonitorInfo monitorInfo, int type){String subject = "环境:"+(StringUtils.isBlank(enviroment)?"正式":enviroment)+"\n"+"方法名称:"+monitorInfo.getMethodName();String msg ="方法参数:\n";msg += (JSON.toJSON(monitorInfo.getParams())+"\n");msg += "异常信息:\n";msg += CommonMail.getFromException(monitorInfo.getException());CommonMail.sendCodeWarnEmail(subject, msg, type);}public static String getFromException(Exception e){StringWriter sw = new StringWriter();e.printStackTrace(new PrintWriter(sw, true));String str = sw.toString();return str;}
}
笔者只是抛砖引玉,大家有更好的方案或优化方法可以提出来,共同学习进步!!!Thank you!!!
Spring实现统一捕获接口层异常与邮件警报相关推荐
- spring aop统一进行日常及异常的处理
什么是AOP 以下摘自百度百科: 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.A ...
- java异常统一处理,Controller层的异常统一处理及返回
Controller层的异常统一处理及返回 一.为什么要做这件事? 不知道你平时在写Controller层接口的时候,有没有注意过抛出异常该怎么处理,是否第一反应是想着用个try-catch来捕获异常 ...
- 【统一异常处理】@ControllerAdvice + @ExceptionHandler 全局处理 Controller 层异常
1.利用springmvc注解对Controller层异常全局处理 对于与数据库相关的 Spring MVC 项目,我们通常会把 事务 配置在 Service层,当数据库操作失败时让 Service ...
- Spring Boot【定制化】~ AOP统一结果处理以及异常拦截
1.简介 用处:统一结果处理与异常拦截. 2.配置步骤 2.1.创建一个spring boot项目(idea) 完整项目结构! 2.2.导入依赖(需要使用到简化环境搭建) <!-- Spring ...
- 利用spring aop统一处理异常和打日志
利用spring aop统一处理异常和打日志 spring aop的概念,很早就写博客介绍了,现在在工作中真正使用. 我们很容易写出的代码 我们很容易写出带有很多try catch 和 logger. ...
- Spring - @ControllerAdvice + @ExceptionHandler全局处理Controller层异常(转)
Spring - @ControllerAdvice + @ExceptionHandler全局处理Controller层异常(转) 参考文章: (1)Spring - @ControllerAdvi ...
- 在Spring Boot中使用切面统一处理自定义的异常
最近我们将项目的一个单独模块提取了一个微服务,这个微服务主要负责其他系统的接入.目的是发布主项目的时候不会影响到其他系统接入.在提取出的微服务中,需要定义一个正常返回的报文和异常返回的报文.正常返回报 ...
- Spring Boot 中如何统一 API 接口响应格式?
今天又要给大家介绍一个 Spring Boot 中的组件–HandlerMethodReturnValueHandler. 在前面的文章中(如何优雅的实现 Spring Boot 接口参数加密解密?) ...
- 使用Spring MVC统一异常处理实战
原文:http://blog.csdn.net/ufo2910628/article/details/40399539 1 描述 在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处 ...
- springMVC02-SSM整合(Result统一响应数据格式、异常页面修改、SSM整合vue-elementUI小案例、SpringMVC的拦截器Interceptor)
文章目录 今日内容 一.SSM整合[重点] 1 SSM整合配置 问题导入 1.1 SSM整合流程 1.2 SSM整合配置 1.2.1 创建工程,添加依赖和插件 1.2.2 Spring整合Mybati ...
最新文章
- 技术人的不惑之路...... | 每日趣闻
- 使用XML与远程服务器进行交互
- swiper 定义放多少张图片,小程序swiper轮播图,自定义样式,两种方法:原生方法和bindchange方法;将点点改为数字(当前第几张 /总共几张);点击点点跳转当前图片...
- Java 8 - 03 Lambda 函数式接口Predicate Consumer Function Supplier
- Python eval函数用法简介
- .NET Core实战项目之CMS 第十七章 CMS网站系统的部署
- java将图片传给页面,java将图片传为设定编码值显示(可做刺绣)
- 怎样找到native speaker的感觉
- Ubuntu, python, CUDA, cuDNN, 驱动, GCC ....的对应关系
- 21天Jenkins打卡Day15项目复制
- javplayer 使用教程_「松下A6系列伺服使用手册」6.出现问题时
- 真实如刀的洞见:和扶墙老师聊技术、组织和商业
- 接口测试第三课(HTTP协议简介) -- 转载
- 爱企查青龙可跑 一个月一张爱奇艺月卡最细教程
- 【知识兔】2022年9月份计算机一级开始报名啦+考试资料
- CrawlSpider实现微信小程序社区爬虫【python爬虫入门进阶】(18)
- Python学习笔记---day02快速上手
- java定时从数据库抓取数据库,java查询数据库java如何实现定时从数据库查询新增的数据?...
- Kafka Streams开发单词计数应用
- Ubuntu 18.04 vscode 编辑器空格显示过小问题解决方案
热门文章
- 苹果4s忘记id密码怎么办_iPhone手机ID密码忘记了怎么办?三种方法轻松解决问题...
- Matlab 实现串口助手
- 郭盛华为什么不去阿里巴巴?原因竟是这个
- xp系统重装后无法连接服务器6,winXP重装系统后不能上网的解决方法
- 万用表测电容方法-电子技术方案
- 本科生学计算机视觉实际吗,成电信通学院本科生在全球计算机视觉顶会CVPR上发表研究成果...
- R语言绘制中国地图,增加指北针、比例尺和九段线区域小图
- ads滤波器仿真(3)——三阶发夹线带通滤波器及其优化
- 下载Google瓦片地图并在Unity中作为场景底图
- PNG生成多尺寸ico文件,开发桌面应用必备