前言

在项目开发中,对于异常处理我们通常有多种处理方式,比如:控制层手动捕获异常,拦截器统一处理异常。今天跟大家分享一种注解的方式,统一拦截异常并处理。

异常处理

在spring 3.2中,新增了@RestControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中。

创建 RRExceptionHandler,并添加 @RestControllerAdvice注解,来这样就可以拦截所有控制层上抛出来的异常。

  1. /**
  2. * 异常处理器
  3. * 创建时间 2017年11月20日
  4. */
  5. @RestControllerAdvice
  6. public class RRExceptionHandler {
  7.  
  8. @Autowired
  9. private IMailService mailService;
  10.  
  11. private Logger logger = LoggerFactory.getLogger(getClass());
  12.  
  13. @Value("${alarm.email}")
  14. private String[] email;
  15.  
  16. /**
  17. * 自定义异常
  18. */
  19. @ExceptionHandler(RRException.class)
  20. public Result handleRRException(RRException e){
  21. Result r = new Result();
  22. r.put("code", e.getCode());
  23. r.put("msg", e.getMessage());
  24. return r;
  25. }
  26.  
  27. @ExceptionHandler(DuplicateKeyException.class)
  28. public Result handleDuplicateKeyException(DuplicateKeyException e){
  29. logger.error(e.getMessage(), e);
  30. return Result.error("数据库中已存在该记录");
  31. }
  32.  
  33. @ExceptionHandler(Exception.class)
  34. public Result handleException(Exception e){
  35. StringWriter stringWriter = new StringWriter();
  36. e.printStackTrace(new PrintWriter(stringWriter));
  37. Email mail = new Email();
  38. mail.setEmail(email);
  39. mail.setSubject("工作流系统告警");
  40. mail.setContent(stringWriter.toString());
  41. //mailService.send(mail);
  42. mailService.sendFreemarker(mail);
  43. logger.error(e.getMessage(), e);
  44. return Result.error();
  45. }
  46. }

自定义异常 RRException:

  1. /**
  2. * 自定义异常
  3. * 创建时间 2017年11月20日
  4. */
  5. public class RRException extends RuntimeException {
  6.  
  7. private static final long serialVersionUID = 1L;
  8.  
  9. private String msg;
  10.  
  11. private int code = 500;
  12.  
  13. public RRException(String msg) {
  14. super(msg);
  15. this.msg = msg;
  16. }
  17.  
  18. public RRException(String msg, Throwable e) {
  19. super(msg, e);
  20. this.msg = msg;
  21. }
  22.  
  23. public RRException(String msg, int code) {
  24. super(msg);
  25. this.msg = msg;
  26. this.code = code;
  27. }
  28.  
  29. public RRException(String msg, int code, Throwable e) {
  30. super(msg, e);
  31. this.msg = msg;
  32. this.code = code;
  33. }
  34.  
  35. public String getMsg() {
  36. return msg;
  37. }
  38.  
  39. public void setMsg(String msg) {
  40. this.msg = msg;
  41. }
  42.  
  43. public int getCode() {
  44. return code;
  45. }
  46.  
  47. public void setCode(int code) {
  48. this.code = code;
  49. }
  50. }

邮件通知

邮件通知,需要引入以下配置:

  1. <!-- email -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-mail</artifactId>
  5. </dependency>
  6. <!-- freemarker 模版 -->
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-freemarker</artifactId>
  10. </dependency>

配置模板邮件参数:

  1. # freemarker
  2. spring.freemarker.template-loader-path=classpath:/templates/
  3. spring.freemarker.suffix=.ftl
  4. spring.freemarker.enabled=true
  5. spring.freemarker.cache=false
  6. spring.freemarker.charset=UTF-8
  7. spring.freemarker.content-type=text/html
  8. spring.freemarker.allow-request-override=false
  9. spring.freemarker.check-template-location=true
  10. spring.freemarker.expose-request-attributes=false
  11. spring.freemarker.expose-session-attributes=false
  12. spring.freemarker.expose-spring-macro-helpers=false
  13.  
  14. # 邮件配置
  15. spring.mail.host=smtp.163.com
  16. spring.mail.username=13105423559@163.com
  17. spring.mail.password=123456
  18. spring.mail.properties.mail.smtp.auth=true
  19. spring.mail.properties.mail.smtp.starttls.enable=true
  20. spring.mail.properties.mail.smtp.starttls.required=true
  21.  
  22. # 告警通知 多个以逗号分隔
  23. alarm.email = 345849402@qq.com

定义Email封装类:

  1. /**
  2. * Email封装类
  3. */
  4. public class Email implements Serializable {
  5. private static final long serialVersionUID = 1L;
  6. // 必填参数
  7. private String[] email;// 接收方邮件
  8. private String subject;// 主题
  9. private String content;// 邮件内容
  10. // 选填
  11. private String template;// 模板
  12. private HashMap<String, String> kvMap;// 自定义参数
  13.  
  14. public Email() {
  15. super();
  16. }
  17.  
  18. public Email(String[] email, String subject, String content, String template, HashMap<String, String> kvMap) {
  19. super();
  20. this.email = email;
  21. this.subject = subject;
  22. this.content = content;
  23. this.template = template;
  24. this.kvMap = kvMap;
  25. }
  26.  
  27. public String[] getEmail() {
  28. return email;
  29. }
  30.  
  31. public void setEmail(String[] email) {
  32. this.email = email;
  33. }
  34.  
  35. public String getSubject() {
  36. return subject;
  37. }
  38.  
  39. public void setSubject(String subject) {
  40. this.subject = subject;
  41. }
  42.  
  43. public String getContent() {
  44. return content;
  45. }
  46.  
  47. public void setContent(String content) {
  48. this.content = content;
  49. }
  50.  
  51. public String getTemplate() {
  52. return template;
  53. }
  54.  
  55. public void setTemplate(String template) {
  56. this.template = template;
  57. }
  58.  
  59. public HashMap<String, String> getKvMap() {
  60. return kvMap;
  61. }
  62.  
  63. public void setKvMap(HashMap<String, String> kvMap) {
  64. this.kvMap = kvMap;
  65. }
  66. }

发送接口:

  1. public interface IMailService {
  2. /**
  3. * 纯文本
  4. * @param mail
  5. * @throws Exception
  6. */
  7. public void send(Email mail);
  8. /**
  9. * 模版发送 freemarker
  10. * @param mail
  11. * @throws Exception
  12. */
  13. public void sendFreemarker(Email mail);
  14.  
  15. }

发送实现:

  1. @Service
  2. public class MailServiceImpl implements IMailService {
  3. private static final Logger logger = LoggerFactory.getLogger(MailServiceImpl.class);
  4. @Autowired
  5. private JavaMailSender mailSender;//执行者
  6. @Autowired
  7. public Configuration configuration;//freemarker
  8. @Value("${spring.mail.username}")
  9. public String USER_NAME;//发送者
  10. @Value("${server.path}")
  11. public String PATH;//邮件服务地址,用于显示图片
  12.  
  13. //文本分割
  14. static {
  15. System.setProperty("mail.mime.splitlongparameters","false");
  16. }
  17.  
  18. @Override
  19. public void send(Email mail) {
  20. try {
  21. logger.info("发送邮件:{}",mail.getContent());
  22. SimpleMailMessage message = new SimpleMailMessage();
  23. message.setFrom(USER_NAME);
  24. message.setTo(mail.getEmail());
  25. message.setSubject(mail.getSubject());
  26. message.setText(mail.getContent());
  27. mailSender.send(message);
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. @Override
  33. public void sendFreemarker(Email mail) {
  34. try {
  35. MimeMessage message = mailSender.createMimeMessage();
  36. MimeMessageHelper helper = new MimeMessageHelper(message, true);
  37. //这里可以自定义发信名称比如:工作流
  38. helper.setFrom(USER_NAME,"工作流");
  39. helper.setTo(mail.getEmail());
  40. helper.setSubject(mail.getSubject());
  41. Map<String, Object> model = new HashMap<String, Object>();
  42. model.put("mail", mail);
  43. model.put("path", PATH);
  44. Template template = configuration.getTemplate(mail.getTemplate());
  45. String text = FreeMarkerTemplateUtils.processTemplateIntoString(
  46. template, model);
  47. helper.setText(text, true);
  48. mailSender.send(message);
  49. } catch (Exception e) {
  50. e.printStackTrace();
  51. }
  52. }
  53. }

定义发送模板 notify.ftl :

  1. <!doctype html>
  2. <html lang="zh-cmn-Hans">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="renderer" content="webkit" />
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. 您好:${mail.content}
  11. </body>
  12. </html>

SpringBoot开发案例之异常处理并邮件通知的更多相关文章

  1. SpringBoot开发案例从0到1构建分布式秒杀系统

    前言 ​最近,被推送了不少秒杀架构的文章,忙里偷闲自己也总结了一下互联网平台秒杀架构设计,当然也借鉴了不少同学的思路.俗话说,脱离案例讲架构都是耍流氓,最终使用SpringBoot模拟实现了部分秒杀场 ...

  2. SpringBoot开发案例之多任务并行+线程池处理

    前言 前几篇文章着重介绍了后端服务数据库和多线程并行处理优化,并示例了改造前后的伪代码逻辑.当然了,优化是无止境的,前人栽树后人乘凉.作为我们开发者来说,既然站在了巨人的肩膀上,就要写出更加优化的程序 ...

  3. SpringBoot开发案例之打造私有云网盘

    前言 最近在做工作流的事情,正好有个需求,要添加一个附件上传的功能,曾找过不少上传插件,都不是特别满意.无意中发现一个很好用的开源web文件管理器插件 elfinder,功能比较完善,社区也很活跃,还 ...

  4. SpringBoot开发案例之整合Activiti工作流引擎

    前言 JBPM是目前市场上主流开源工作引擎之一,在创建者Tom Baeyens离开JBoss后,JBPM的下一个版本jBPM5完全放弃了jBPM4的基础代码,基于Drools Flow重头来过,目前官 ...

  5. SpringBoot开发案例之整合Dubbo分布式服务

    前言 在 SpringBoot 很火热的时候,阿里巴巴的分布式框架 Dubbo 不知是处于什么考虑,在停更N年之后终于进行维护了.在之前的微服务中,使用的是当当维护的版本 Dubbox,整合方式也是使 ...

  6. SpringBoot开发案例之整合Kafka实现消息队列

    前言 最近在做一款秒杀的案例,涉及到了同步锁.数据库锁.分布式锁.进程内队列以及分布式消息队列,这里对SpringBoot集成Kafka实现消息队列做一个简单的记录. Kafka简介 Kafka是由A ...

  7. SpringBoot开发案例之分布式集群共享Session

    前言 在分布式系统中,为了提升系统性能,通常会对单体项目进行拆分,分解成多个基于功能的微服务,如果有条件,可能还会对单个微服务进行水平扩展,保证服务高可用. 那么问题来了,如果使用传统管理 Sessi ...

  8. SpringBoot开发案例Nacos配置管理中心

    前言 在开发过程中,通常我们会配置一些参数来实现某些功能,比如是否开启某项服务,告警邮件配置等等.一般会通过硬编码.配置文件或者数据库的形式实现. 那么问题来了,如何更加优雅的实现?欢迎来到 Naco ...

  9. 转载-SpringBoot开发案例之整合日志管理

    转载:https://cloud.tencent.com/developer/article/1097579 有一种力量无人能抵挡,它永不言败生来倔强.有一种理想照亮了迷茫,在那写满荣耀的地方. 00 ...

随机推荐

  1. Java实现 LeetCode 321 拼接最大数

    321. 拼接最大数 给定长度分别为 m 和 n 的两个数组,其元素由 0-9 构成,表示两个自然数各位上的数字.现在从这两个数组中选出 k (k <= m + n) 个数字拼接成一个新的数,要 ...

  2. Java实现 LeetCode 222 完全二叉树的节点个数

    222. 完全二叉树的节点个数 给出一个完全二叉树,求出该树的节点个数. 说明: 完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集 ...

  3. java实现第六届蓝桥杯灾后重建

    灾后重建 题目描述 Pear市一共有N(<=50000)个居民点,居民点之间有M(<=200000)条双向道路相连.这些居民点两两之间都可以通过双向道路到达.这种情况一直持续到最近,一次严 ...

  4. linux 删除文件后 df 查看磁盘空间并没有释放

    1.错误现象 Linux 磁盘空间总是报警,查到到大文件,删除之后,df看到磁盘空间并没有释放. 用du -sh ./* | sort -nr (查看当前目录下文件的大小)通过查找了下发现文件被mys ...

  5. Spring新注解

    @Configuration作用:指定当前类为一个配置类@ComponentScan作用:用于通过注释指定Spring在创建容器时要扫描的包           当配置类作为AnnotationCon ...

  6. HTML的简介和历史发展过程

    HTML的简介和历史发展过程 前言 这次写一篇对于HTML以及CSS的简介,平常我们大家都知道的编程语言有很多种,比如Java.C++.Python等等,每种编程语言都有其独具的特色,不论是语法格式还 ...

  7. @bzoj - 2658@ [Zjoi2012]小蓝的好友(mrx)

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事 ...

  8. Vugen使用技巧

    调整各种选项的超时时间

  9. 网页中为什么常用AT替换@(repost from https://zhidao.baidu.com/question/122291.html)

    经常在个人主页上看到别人的邮箱地址中@被AT符号替代,很是迷惑,这样替代有什么好处呢?还是说html原有的原因使界面中不能出现@,查阅资料后解答如下: 写成AT [at],是为了防止被一些邮件扫描器搜 ...

  10. Eplan PLC连接点模块为什么不显示“路径功能文本”,已解决

    Eplan PLC连接点模块为什么不显示“路径功能文本”,已解决 如果“路径功能文本”的文字开头的位置没有对准PLC模块的中心,PLC连接点模块就不会显示.