起因
- 为什么要做这个功能,因为发现开发者平时不看服务器日志出现异常才看还要上服务器查log,后来想起为什么不发送短信告知程序开发者,短信接口是收费的成本太高,于是可以用邮件代替短信这样既省了短信费用也能实时告知开发者你的程序出行了异常可以在生产环境快速定位问题出现的位置
- 下面贴上实现的代码
setp 1
- 引入email pom文件
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
setp 2
- 自定义注解
package com.jx.esb.producer.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @ClassName: Developer * @Description: TODO(开发者邮箱) * @author gangyu2 * @date 2019年7月18日 下午5:42:11 * */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DeveloperEmail { String email() default ""; }
setp 3
- 实现一个拦截器
package com.jx.esb.producer.handle; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import com.jx.esb.producer.annotation.DeveloperEmail; /** * @ClassName: TokenHandlerInterceptor * @Description: TODO(token验证) * @author gangyu2 * @date 2019年5月13日 下午4:29:25 */ @Component public class EmailHandlerInterceptor implements HandlerInterceptor{ Logger logger=LoggerFactory.getLogger(TokenHandlerInterceptor.class); public static EMAIL="email"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { DeveloperEmail email = ((HandlerMethod) handler).getMethodAnnotation(DeveloperEmail.class); if (handler.getClass().isAssignableFrom(HandlerMethod.class)) { if(email != null) { request.setAttribute(EMAIL, email.email()); } return true; } else { return true; } } }
setp 4
- 在
application-dev.properties
配置邮箱##############################[邮箱 配置]################################################### spring.mail.host=smtp.qq.com spring.mail.username=597205393@qq.com spring.mail.password=你的授权码 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=false spring.mail.properties.mail.smtp.starttls.required=false ##############################[邮箱 配置]###################################################
- 实现邮箱服务
package com.jx.esb.producer.impl; import java.io.File; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.FileSystemResource; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; @Service public class MailUtil { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private JavaMailSender sender; @Value("${spring.mail.username:''}") private String from; /** * 发送纯文本的简单邮件 * @param to * @param subject * @param content */ public void sendSimpleMail(String to, String subject, String content){ SimpleMailMessage message = new SimpleMailMessage(); message.setFrom(from); message.setTo(new String[] {to,from});//默认抄送给自己主邮箱就是我自己的号 message.setSubject(subject); message.setText(content); try { sender.send(message); logger.info("简单邮件已经发送。"); } catch (Exception e) { logger.error("发送简单邮件时发生异常!", e); } } /** * 发送html格式的邮件 * @param to * @param subject * @param content */ public void sendHtmlMail(String to, String subject, String content){ MimeMessage message = sender.createMimeMessage(); try { //true表示需要创建一个multipart message MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(content, true); sender.send(message); logger.info("html邮件已经发送。"); } catch (MessagingException e) { logger.error("发送html邮件时发生异常!", e); } } /** * 发送带附件的邮件 * @param to * @param subject * @param content * @param filePath */ public void sendAttachmentsMail(String to, String subject, String content, String filePath){ MimeMessage message = sender.createMimeMessage(); try { //true表示需要创建一个multipart message MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(content, true); FileSystemResource file = new FileSystemResource(new File(filePath)); String fileName = filePath.substring(filePath.lastIndexOf(File.separator)); helper.addAttachment(fileName, file); sender.send(message); logger.info("带附件的邮件已经发送。"); } catch (MessagingException e) { logger.error("发送带附件的邮件时发生异常!", e); } } /** * 发送嵌入静态资源(一般是图片)的邮件 * @param to * @param subject * @param content 邮件内容,需要包括一个静态资源的id,比如:<img src=\"cid:rscId01\" > * @param rscPath 静态资源路径和文件名 * @param rscId 静态资源id */ public void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId){ MimeMessage message = sender.createMimeMessage(); try { //true表示需要创建一个multipart message MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(content, true); FileSystemResource res = new FileSystemResource(new File(rscPath)); helper.addInline(rscId, res); sender.send(message); logger.info("嵌入静态资源的邮件已经发送。"); } catch (MessagingException e) { logger.error("发送嵌入静态资源的邮件时发生异常!", e); } } }
setp 5
- 全局异常处理
package com.jx.esb.producer.handle; import java.io.PrintWriter; import java.io.StringWriter; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.RestControllerAdvice; import com.jx.common.tool.utils.Result; import com.jx.common.tool.utils.MailUtil; /** * * @ClassName: ExceptionHandle * @Description: TODO(异常信息统一返回处理) * @author gangyu * @date 2019年1月25日 上午10:26:31 * */ @RestControllerAdvice public class ExceptionHandle { private final static Logger LOGGER = LoggerFactory.getLogger(ExceptionHandle.class); @Autowired HttpServletRequest request; @Autowired private MailUtil mailUtil ; /** * 全局异常捕捉处理,判断错误是否是已定义的已知错误,不是则由未知错误代替,同时记录在log中 * @param e * @return */ @ExceptionHandler(value = Exception.class) public Result exceptionGet(Exception e) { String email=(String)request.getAttribute(EmailHandlerInterceptor.EMAIL); //发送邮件 if(StringUtils.isNotBlank(email)) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); mailUtil.sendSimpleMail(email, "异常信息", sw.toString()); } LOGGER.error("全局异常捕获",e); /*if (e instanceof BaseException) { BaseException MyException = (BaseException) e; return Result.fail(MyException.getErrorCode(), MyException.getMessage()); }*/ return Result.fail(e.getMessage()); } /** * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器 * * @param binder */ @InitBinder public void initBinder(WebDataBinder binder) { } }
setp 6
- controller层加上
DeveloperEmail
注解/** * @Title: deleteBlackList * @Description: TODO(测试异常发件) * @author gangyu2 * @date 2019年7月19日上午10:48:39 */ @DeveloperEmail(email = "这里是编写此方法的开发者") @RequestMapping(value = "test", method = RequestMethod.POST) public void deleteBlackList() throws Exception { int i=1/0; }
setp 7
- 结果
在也不用担心服务报错找不人处理了