前言
在项目开发中,对于异常处理我们通常有多种处理方式,比如:控制层手动捕获异常,拦截器统一处理异常。今天跟大家分享一种注解的方式,统一拦截异常并处理。
异常处理
在spring 3.2中,新增了@RestControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中。
创建 RRExceptionHandler,并添加 @RestControllerAdvice注解,来这样就可以拦截所有控制层上抛出来的异常。
/** * 异常处理器 * 创建时间 2017年11月20日 */ @RestControllerAdvice public class RRExceptionHandler { @Autowired private IMailService mailService; private Logger logger = LoggerFactory.getLogger(getClass()); @Value("${alarm.email}") private String[] email; /** * 自定义异常 */ @ExceptionHandler(RRException.class) public Result handleRRException(RRException e){ Result r = new Result(); r.put("code", e.getCode()); r.put("msg", e.getMessage()); return r; } @ExceptionHandler(DuplicateKeyException.class) public Result handleDuplicateKeyException(DuplicateKeyException e){ logger.error(e.getMessage(), e); return Result.error("数据库中已存在该记录"); } @ExceptionHandler(Exception.class) public Result handleException(Exception e){ StringWriter stringWriter = new StringWriter(); e.printStackTrace(new PrintWriter(stringWriter)); Email mail = new Email(); mail.setEmail(email); mail.setSubject("工作流系统告警"); mail.setContent(stringWriter.toString()); //mailService.send(mail); mailService.sendFreemarker(mail); logger.error(e.getMessage(), e); return Result.error(); } }
自定义异常 RRException:
/** * 自定义异常 * 创建时间 2017年11月20日 */ public class RRException extends RuntimeException { private static final long serialVersionUID = 1L; private String msg; private int code = 500; public RRException(String msg) { super(msg); this.msg = msg; } public RRException(String msg, Throwable e) { super(msg, e); this.msg = msg; } public RRException(String msg, int code) { super(msg); this.msg = msg; this.code = code; } public RRException(String msg, int code, Throwable e) { super(msg, e); this.msg = msg; this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } }
邮件通知
邮件通知,需要引入以下配置:
<!-- email --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <!-- freemarker 模版 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
配置模板邮件参数:
# freemarker
spring.freemarker.template-loader-path=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.enabled=true
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.allow-request-override=false
spring.freemarker.check-template-location=true
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false
# 邮件配置
spring.mail.host=smtp.163.com
spring.mail.username=13105423559@163.com
spring.mail.password=123456
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
# 告警通知 多个以逗号分隔
alarm.email = 345849402@qq.com
定义Email封装类:
/** * Email封装类 */ public class Email implements Serializable { private static final long serialVersionUID = 1L; // 必填参数 private String[] email;// 接收方邮件 private String subject;// 主题 private String content;// 邮件内容 // 选填 private String template;// 模板 private HashMap<String, String> kvMap;// 自定义参数 public Email() { super(); } public Email(String[] email, String subject, String content, String template, HashMap<String, String> kvMap) { super(); this.email = email; this.subject = subject; this.content = content; this.template = template; this.kvMap = kvMap; } public String[] getEmail() { return email; } public void setEmail(String[] email) { this.email = email; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getTemplate() { return template; } public void setTemplate(String template) { this.template = template; } public HashMap<String, String> getKvMap() { return kvMap; } public void setKvMap(HashMap<String, String> kvMap) { this.kvMap = kvMap; } }
发送接口:
public interface IMailService { /** * 纯文本 * @param mail * @throws Exception */ public void send(Email mail); /** * 模版发送 freemarker * @param mail * @throws Exception */ public void sendFreemarker(Email mail); }
发送实现:
@Service public class MailServiceImpl implements IMailService { private static final Logger logger = LoggerFactory.getLogger(MailServiceImpl.class); @Autowired private JavaMailSender mailSender;//执行者 @Autowired public Configuration configuration;//freemarker @Value("${spring.mail.username}") public String USER_NAME;//发送者 @Value("${server.path}") public String PATH;//邮件服务地址,用于显示图片 //文本分割 static { System.setProperty("mail.mime.splitlongparameters","false"); } @Override public void send(Email mail) { try { logger.info("发送邮件:{}",mail.getContent()); SimpleMailMessage message = new SimpleMailMessage(); message.setFrom(USER_NAME); message.setTo(mail.getEmail()); message.setSubject(mail.getSubject()); message.setText(mail.getContent()); mailSender.send(message); } catch (Exception e) { e.printStackTrace(); } } @Override public void sendFreemarker(Email mail) { try { MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); //这里可以自定义发信名称比如:工作流 helper.setFrom(USER_NAME,"工作流"); helper.setTo(mail.getEmail()); helper.setSubject(mail.getSubject()); Map<String, Object> model = new HashMap<String, Object>(); model.put("mail", mail); model.put("path", PATH); Template template = configuration.getTemplate(mail.getTemplate()); String text = FreeMarkerTemplateUtils.processTemplateIntoString( template, model); helper.setText(text, true); mailSender.send(message); } catch (Exception e) { e.printStackTrace(); } } }
定义发送模板 notify.ftl :
<!doctype html> <html lang="zh-cmn-Hans"> <head> <meta charset="UTF-8"> <meta name="renderer" content="webkit" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <title>Document</title> </head> <body> 您好:${mail.content} </body> </html>