前言
在項目開發中,對於異常處理我們通常有多種處理方式,比如:控制層手動捕獲異常,攔截器統一處理異常。今天跟大家分享一種注解的方式,統一攔截異常並處理。
異常處理
在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>