近况

最近马上要报名考试了,上一次过了一门科一,运气还算好的,要是一科都没过,真的不想考了
纵使如此,想一次性过科二和科三也是非常难的,况且笔试过后还有面试,而我好像是有点社恐
不过也算是个锻炼自己的机会吧,总要锻炼一下自己的,加油加油,今年下半年一定要一次性过掉笔试
再失败的话,真的很累人,另外最近又有了考个摩托车证的想法,花费大概1500左右,考个摩托车证
以后攒钱买个摩托车也是挺好的,虽然没有钱买小轿车,但是也意味着不用背车贷不是,而且自己非常穷了
能开个摩托车也挺好的~

回归正题,今天记录一下配置发送邮件的功能

  • 导入依赖

    <!--邮件发送依赖-->		
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
  • Jeecg中对消息发送功能的设计

    Jeecg中认为发送短信,发送邮件,发送微信消息,都可以抽象成一个体系,即发送消息的体系
    所以我们可以看到消息发送功能的接口的设计如下:
    ISendMsgHandle接口
    	EmailSendMsgHandle实现类,处理邮件发送的功能
    	SmsSendMsgHandle实现类,处理短信发送的功能
    	WxSendMsgHandle实现类,处理微信消息发送的功能
    
    除此之外,还配合MVC的设计理念,增加SysMessage实体类,SysMessageController,ISysMessageService
    那么前端用户,只需要传递参数,然后SysMessage封装各个类型的参数,例如邮箱属性,短信属性,微信消息属性
    然后Controller根据消息类型调用不同的Handle实现类进行处理,最后处理完了使用ISysMessageService进行处理保存数据到数据库。
    注意:你可能注意到了,整个处理流程:各个消息类型参数->同一个SysMessage对象
    	->同一个SysMessageController->各自的Handle实现类->调用同一个SysMessageServiceImpl
    	你可能会问为什么需要Handle呢?如果把Handle直接写成service的三个方法呢?如果写三个service实现类呢?
    	实际上我也不太懂,但我觉得可能是因为解耦,我并不想跟你模块相关联,把本模块的service使用spring自动注入
    	的方式去导入到其他类中使用,可能过于耦合了,而如果我直接在其他类的方法中使用handle实现类是不是更好?
    	我不知道是不是这个原因。
    
    需要注意的是:其实短信,邮箱和微信消息这三个功能还是有些差异的,例如短信有消息模板的概念
    那本文就不去描述非常完整的功能是如何设计的,主要是我也非常菜,就只针对邮箱功能进行记录吧。
    
    以上是一些碎碎念,描述一下功能的结构是什么样的,下面是邮箱功能实现的具体代码
  • SysMessage

    @Data
    @EqualsAndHashCode(callSuper = false)
    @Accessors(chain = true)
    @TableName("sys_sms")
    public class SysMessage extends JeecgEntity {
    
    	/**
    	 * id
    	 */
    	@TableId(type = IdType.ASSIGN_ID)
    	private String id;
    
    	/**接收人*/
    	@Excel(name = "接收人", width = 15)
    	private java.lang.String esReceiver;
    
    	/**消息标题*/
    	@Excel(name = "消息标题", width = 15)
    	private java.lang.String esTitle;
    
    	/**推送内容*/
    	@Excel(name = "推送内容", width = 15)
    	private java.lang.String esContent;
    
    	/**推送所需参数Json格式*/
    	@Excel(name = "推送所需参数Json格式", width = 15)
    	private java.lang.String esParam;
    
    	/**推送失败原因*/
    	@Excel(name = "推送失败原因", width = 15)
    	private java.lang.String esResult;
    
    	/**发送次数*/
    	@Excel(name = "发送次数", width = 15)
    	private java.lang.Integer esSendNum;
    
    	/**推送状态 0未推送 1推送成功 2推送失败*/
    	@Excel(name = "推送状态 0未推送 1推送成功 2推送失败", width = 15)
    	@Dict(dicCode = "msgSendStatus")
    	private java.lang.String esSendStatus;
    
    	/**推送时间*/
    	@Excel(name = "推送时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
    	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
        @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    	private java.util.Date esSendTime;
    
    
    	/**推送方式:1短信 2邮件 3微信*/
    	@Excel(name = "推送方式:1短信 2邮件 3微信", width = 15)
    	@Dict(dicCode = "msgType")
    	private java.lang.String esType;
    
    	/**备注*/
    	@Excel(name = "备注", width = 15)
    	private java.lang.String remark;
    
    	/**
    	 * 附件文件,前端传递的文件用该属性封装
    	 */
    	@JsonIgnore
    	@TableField(exist = false)
    	private MultipartFile[] multipartFiles;
    
    	/**
    	 * 附件文件,后端发送邮箱需要的文件用该属性封装
    	 */
    	@JsonIgnore
    	@TableField(exist = false)
    	private File[] files;
    }
    
    /*
    	用两个对象封装文件,是感觉这两者转换起来很麻烦,干脆直接分别存了,
    	之后在handle实现类中分别判断哪个里面有文件
    */
  • 所需的枚举类

    /**
     * 推送状态枚举
     */
    public enum SendMsgStatusEnum {
    
    	//推送状态 0未推送 1推送成功 2推送失败
    	WAIT("0"), SUCCESS("1"), FAIL("2");
    
    	private String code;
    
    	private SendMsgStatusEnum(String code) {
    		this.code = code;
    	}
    
    	public String getCode() {
    		return code;
    	}
    
    	public void setStatusCode(String code) {
    		this.code = code;
    	}
    }
    
    
    
    /**
     * 发送消息类型枚举
     */
    public enum SendMsgTypeEnum {
    
    	//推送方式:1短信 2邮件 3微信
    	SMS("1", "SmsSendMsgHandle"),
    	EMAIL("2", "EmailSendMsgHandle"),
    	WX("3","WxSendMsgHandle");
    
    	private String type;
    
    	private String implClass;
    
    	private SendMsgTypeEnum(String type, String implClass) {
    		this.type = type;
    		this.implClass = implClass;
    	}
    
    	public String getType() {
    		return type;
    	}
    
    	public void setType(String type) {
    		this.type = type;
    	}
    
    	public String getImplClass() {
    		return implClass;
    	}
    
    	public void setImplClass(String implClass) {
    		this.implClass = implClass;
    	}
    
    	public static SendMsgTypeEnum getByType(String type) {
    		if (oConvertUtils.isEmpty(type)) {
    			return null;
    		}
    		for (SendMsgTypeEnum val : values()) {
    			if (val.getType().equals(type)) {
    				return val;
    			}
    		}
    		return null;
    	}
    }
  • Controller

    @Slf4j
    @RestController
    @RequestMapping("/sys/message/sysMessage")
    public class SysMessageController extends JeecgController<SysMessage, ISysMessageService> {
    	@Autowired
    	private ISysMessageService sysMessageService;
    
    	@Autowired
    	private EmailSendMsgHandle emailSendMsgHandle;
    
    	@PostMapping(value = "/send")
    	public Result<?> send(SysMessage sysMessage) {
    		String esType = sysMessage.getEsType();
    		if (ObjectUtil.isNotEmpty(esType)) {
    			if (ObjectUtil.equals(esType, SendMsgTypeEnum.EMAIL.getType())){
    				SysMessage message = emailSendMsgHandle.sendMail(sysMessage);
    				return Result.OK(message);
    			}else {
    				return Result.error("其他方式尚在开发中");
    			}
    		}else {
    			return Result.error("发送消息的类型不能为空");
    		}
    	}
    }
  • EmailSendMsgHandle

    @Component
    public class EmailSendMsgHandle implements ISendMsgHandle {
    
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        @Autowired
        private JavaMailSenderImpl mailSender;
    
        @Autowired
        private ISysMessageService sysMessageService;
    
        static String emailFrom;
    
        public static void setEmailFrom(String emailFrom) {
            EmailSendMsgHandle.emailFrom = emailFrom;
        }
    
        /**
         * 发送邮件,新方法,包括检测,发送,和保存邮件发送日志等流程
         */
        public SysMessage sendMail(SysMessage sysMessage) {
            try {
                //1.检测邮件
                checkMail(sysMessage);
                //2.发送邮件
                sendMimeMail(sysMessage);
                //3.保存邮件
                return saveMail(sysMessage);
            } catch (Exception e) {
                logger.error("发送邮件失败:", e);
                sysMessage.setEsSendStatus(SendMsgStatusEnum.FAIL.getCode());
                sysMessage.setEsResult(e.getMessage());
                return sysMessage;
            }
        }
    
        /**
         * 检测邮件信息类
         * @param sysMessage
         */
        private void checkMail(SysMessage sysMessage) {
            if (ObjectUtil.isEmpty(sysMessage.getEsReceiver())) {
                throw new RuntimeException("邮件收信人不能为空");
            }
            if (ObjectUtil.isEmpty(sysMessage.getEsTitle())) {
                throw new RuntimeException("邮件主题不能为空");
            }
            if (ObjectUtil.isEmpty(sysMessage.getEsContent())) {
                throw new RuntimeException("邮件内容不能为空");
            }
        }
    
        /**
         * 构建复杂邮件信息类
         * @param sysMessage
         */
        private void sendMimeMail(SysMessage sysMessage) {
            try {
                MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage(), true);
                sysMessage.setEsType(SendMsgTypeEnum.EMAIL.getType());
                //邮件发信人
                messageHelper.setFrom(getMailSendFrom());
                //邮件收信人
                messageHelper.setTo(sysMessage.getEsReceiver().split(","));
                //邮件主题
                messageHelper.setSubject(sysMessage.getEsTitle());
                //邮件内容
                messageHelper.setText(sysMessage.getEsContent());
                //添加邮件附件,前端
                if (sysMessage.getMultipartFiles() != null) {
                    for (MultipartFile multipartFile : sysMessage.getMultipartFiles()) {
                        messageHelper.addAttachment(multipartFile.getOriginalFilename(), multipartFile);
                    }
                }
    
                //添加邮件附件,后端
                if (sysMessage.getFiles() != null) {
                    Arrays.stream(sysMessage.getFiles()).forEach(file -> {
                        try {
                            messageHelper.addAttachment(file.getName(), file);
                        } catch (MessagingException e) {
                            e.printStackTrace();
                        }
                    });
                }
    
                //发送时间
                if (ObjectUtil.isEmpty(sysMessage.getEsSendTime())) {
                    sysMessage.setEsSendTime(new Date());
                    messageHelper.setSentDate(sysMessage.getEsSendTime());
                }
                //正式发送邮件
                mailSender.send(messageHelper.getMimeMessage());
                sysMessage.setEsSendStatus(SendMsgStatusEnum.SUCCESS.getCode());
                logger.info("发送邮件成功:{}->{}", getMailSendFrom(), sysMessage.getEsReceiver());
            } catch (Exception e) {
                throw new RuntimeException("发送邮件失败",e);
            }
        }
    
        /**
         * 保存邮件
         * @param sysMessage
         * @return
         */
        private SysMessage saveMail(SysMessage sysMessage) {
            sysMessageService.save(sysMessage);
            return sysMessage;
        }
    
        /**
         * 获取邮件发信人
         * @return
         */
        public String getMailSendFrom() {
            return mailSender.getJavaMailProperties().getProperty("from");
        }
    }

文章推荐

其实上面的逻辑也是网上的代码逻辑,来看看别人的代码怎么写的吧