Przeglądaj źródła

feat: 发送缺失邮件逻辑开发

chenjianhua 7 miesięcy temu
rodzic
commit
18b3f511d0

+ 5 - 0
service-base/pom.xml

@@ -226,6 +226,11 @@
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
     </dependencies>
 
 <!--    <build>-->

+ 2 - 1
service-base/src/main/java/com/simuwang/base/common/enums/ResultCode.java

@@ -10,7 +10,8 @@ import lombok.Generated;
  */
 public enum ResultCode {
     CONNECT_SUCCESS(20000, "链接成功"),
-    CONNECT_ERROR(20005, "连接失败,请检查账号及协议相关信息");
+    CONNECT_ERROR(20005, "连接失败,请检查账号及协议相关信息"),
+    SEND_SUCCESS(200, "邮件发送成功");
 
     private final int code;
     private final String msg;

+ 51 - 7
service-base/src/main/java/com/simuwang/base/common/util/EmailUtil.java

@@ -11,18 +11,19 @@ import com.simuwang.base.common.conts.EmailTypeConst;
 import com.simuwang.base.pojo.dto.EmailContentInfoDTO;
 import com.simuwang.base.pojo.dto.MailboxInfoDTO;
 import com.sun.mail.imap.IMAPStore;
-import jakarta.mail.Message;
-import jakarta.mail.MessagingException;
-import jakarta.mail.Session;
-import jakarta.mail.Store;
-import jakarta.mail.internet.MimeBodyPart;
-import jakarta.mail.internet.MimeMultipart;
-import jakarta.mail.internet.MimeUtility;
+import jakarta.activation.DataHandler;
+import jakarta.mail.*;
+import jakarta.mail.internet.*;
+import jakarta.mail.util.ByteArrayDataSource;
 import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.mail.javamail.JavaMailSender;
 
 import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.*;
 
 /**
@@ -245,4 +246,47 @@ public class EmailUtil {
         }
         return props;
     }
+    public static  void senEmail(MailboxInfoDTO mailboxInfoDTO, String emails, File file, JavaMailSender javaMailSender) throws Exception {
+        logger.info("send email begin .........");
+        // 根据Session 构建邮件信息
+        MimeMessage message = javaMailSender.createMimeMessage();
+        // 创建邮件发送者地址
+        Address from = new InternetAddress(mailboxInfoDTO.getAccount());
+        String[] emailArr = emails.split(";");
+        Address[] toArr = new Address[emailArr.length];
+        for(int idx=0;idx<emailArr.length;idx++){
+            if(StringUtils.isNotEmpty(emailArr[idx])){
+                Address to = new InternetAddress(emailArr[idx]);
+                toArr[idx] = to;
+            }
+        }
+        message.setFrom(from);
+        message.setRecipients(Message.RecipientType.TO, toArr);
+        // 邮件主题
+        message.setSubject("产品净值补发");
+        // 邮件容器
+        MimeMultipart mimeMultiPart = new MimeMultipart();
+        // 设置HTML
+        BodyPart bodyPart = new MimeBodyPart();
+        logger.info("组装 htmlText.........");
+        // 邮件内容
+        String htmlText ="<p>您好,附件为产品的数据未发送到最新,麻烦尽快发送缺失的数据。若是产品清算或者有其他原因不再发送数据,还请将产品的清算日期或者不再发送数据的原因发送给我们,非常感谢~\n</p>";
+        bodyPart.setContent(htmlText, "text/html;charset=utf-8");
+        //设置附件
+        BodyPart filePart=new MimeBodyPart();
+        filePart.setFileName(file.getName());
+        filePart.setDataHandler(
+                new DataHandler(
+                        new ByteArrayDataSource(
+                                Files.readAllBytes(Paths.get(file.getAbsolutePath())), "application/octet-stream")));
+        mimeMultiPart.addBodyPart(bodyPart);
+        mimeMultiPart.addBodyPart(filePart);
+        message.setContent(mimeMultiPart);
+        message.setSentDate(new Date());
+        // 保存邮件
+        message.saveChanges();
+        // 发送邮件
+        javaMailSender.send(message);
+    }
+
 }

+ 3 - 3
service-base/src/main/java/com/simuwang/base/common/util/ExcelUtil.java

@@ -293,10 +293,10 @@ public class ExcelUtil {
             HSSFRow row = sheet.createRow(0);
             // 第四步,创建单元格,并设置值表头 设置表头居中
             HSSFCellStyle style = wb.createCellStyle();
-            style.setAlignment(HorizontalAlignment.RIGHT);
+            style.setAlignment(HorizontalAlignment.LEFT);
             style.setWrapText(true);
-            sheet.setColumnWidth(0, 5000);
-            sheet.setColumnWidth(1, 5000);
+            sheet.setColumnWidth(0, 10000);
+            sheet.setColumnWidth(1, 10000);
             sheet.setColumnWidth(2, 5000);
             sheet.setColumnWidth(3, 8000);
             sheet.setColumnWidth(4, 8000);

+ 2 - 0
service-base/src/main/java/com/simuwang/base/mapper/CompanyEmailSendHistoryMapper.java

@@ -29,4 +29,6 @@ public interface CompanyEmailSendHistoryMapper {
     long countCompanyEmailList(CompanyEmailPageQuery companyEmailPageQuery);
 
     long countCompanyEmailhistory(CompanyEmailHistoryPageQuery companyEmailHistoryPageQuery);
+
+    void saveCompanyEmailSendHistory(CompanyEmailSendHistoryDO historyDO);
 }

+ 8 - 0
service-base/src/main/java/com/simuwang/base/mapper/DeletionInfoMapper.java

@@ -1,6 +1,7 @@
 package com.simuwang.base.mapper;
 
 import com.simuwang.base.pojo.dos.DeletionInfoDO;
+import com.simuwang.base.pojo.dos.EmailDeletionInfoDO;
 import com.simuwang.base.pojo.dos.FundDeletionInfoDO;
 import com.simuwang.base.pojo.dto.query.DeletionPageQuery;
 import com.simuwang.base.pojo.dto.query.FundDeletionPageQuery;
@@ -39,4 +40,11 @@ public interface DeletionInfoMapper {
     DeletionInfoDO getDeletionInfoDO(DeletionInfoDO deletionInfoDO);
 
     void saveDeletionInfoDO(DeletionInfoDO deletionInfoDO);
+
+    void removeDistributeDeletion(@Param("fundId")String fundId);
+
+    List<EmailDeletionInfoDO> getDeletionInfoByFundId(@Param("fundIdList") List<String> fundIdList);
+
+    void updateSendStatusByFundId(@Param("fundIdList")List<String> fundIdList);
+
 }

+ 2 - 0
service-base/src/main/java/com/simuwang/base/mapper/FundInfoMapper.java

@@ -39,4 +39,6 @@ public interface FundInfoMapper {
     String getCompanyNameByFundId(@Param("fundId") String fundId);
 
     String getInceptionDateByFundId(@Param("fundId")String fundId);
+
+    List<String> getFundIdByCompanyId(@Param("companyId")String companyId);
 }

+ 1 - 1
service-base/src/main/java/com/simuwang/base/pojo/dos/CompanyEmailSendHistoryDO.java

@@ -36,7 +36,7 @@ public class CompanyEmailSendHistoryDO {
      */
     private String email;
     /**
-     * 邮箱地址
+     * 发送状态1-成功,0-失败
      */
     private Integer sendStatus;
     /**

+ 4 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/DeletionInfoDO.java

@@ -73,6 +73,10 @@ public class DeletionInfoDO {
      * 更新时间
      */
     private Date updateTime;
+    /**
+     * 是否发送过邮件
+     */
+    private Integer isSend;
 
     public DeletionInfoVO toVO() {
         DeletionInfoVO deletionInfoVO = new DeletionInfoVO();

+ 33 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/EmailDeletionInfoDO.java

@@ -0,0 +1,33 @@
+package com.simuwang.base.pojo.dos;
+
+import com.simuwang.base.pojo.vo.FundDeletionInfoVO;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * FileName: DeletionInfoDO
+ * Author:   chenjianhua
+ * Date:     2024/9/17 18:45
+ * Description: ${DESCRIPTION}
+ */
+@Data
+public class EmailDeletionInfoDO {
+    /**
+     * 基金名称
+     */
+    private String fundName;
+    /**
+     * 公司名称
+     */
+    private String companyName;
+    /**
+     * 缺失类型
+     */
+    private String deletionType;
+    /**
+     * 缺失日期
+     */
+    private String deletionDate;
+
+}

+ 5 - 0
service-base/src/main/resources/mapper/CompanyEmailHistoryMapper.xml

@@ -15,6 +15,11 @@
         <result column="creatorid" property="creatorId"/>
         <result column="updaterid" property="updaterId"/>
     </resultMap>
+    <insert id="saveCompanyEmailSendHistory"
+            parameterType="com.simuwang.base.pojo.dos.CompanyEmailSendHistoryDO">
+        insert into PPW_EMAIL.company_email_send_history(company_id,email,send_status,send_time,send_remark,isvalid,createtime,updatetime,creatorid,updaterid)
+        values (#{companyId},#{email},#{sendStatus},#{sendTime},#{sendRemark},#{isvalid},#{createTime},#{updateTime},#{creatorId},#{updaterId})
+    </insert>
     <update id="deleteEmailHistory">
         update PPW_EMAIL.company_email_send_history set isvalid =0,updatetime=sysdate() where email in
         <foreach item="email" collection="emailList" open="(" separator="," close=")">

+ 32 - 2
service-base/src/main/resources/mapper/DeletionInfoMapper.xml

@@ -15,10 +15,11 @@
         <result column="createtime" property="createTime"/>
         <result column="updaterid" property="updaterId"/>
         <result column="updatetime" property="updateTime"/>
+        <result column="is_send" property="isSend"/>
     </resultMap>
     <insert id="saveDeletionInfoDO" parameterType="com.simuwang.base.pojo.dos.DeletionInfoDO">
-        insert into PPW_EMAIL.deletion_info(fund_id,deletion_type,deletion_date,isvalid,createtime,updatetime)
-        values (#{fundId},#{deletionType},#{deletionDate},#{isvalid},#{createTime},#{updateTime})
+        insert into PPW_EMAIL.deletion_info(fund_id,deletion_type,deletion_date,isvalid,createtime,updatetime,is_send)
+        values (#{fundId},#{deletionType},#{deletionDate},#{isvalid},#{createTime},#{updateTime},#{isSend})
     </insert>
     <update id="update" parameterType="com.simuwang.base.pojo.dos.FundDeletionInfoDO">
         update PPW_EMAIL.deletion_info set fund_id=#{fundId},deletion_type=#{deletionType},deletion_date=#{deletionDate},remark=#{remark},updatetime=#{updateTime}
@@ -211,4 +212,33 @@
         and fund_id=#{fundId} and deletion_date=#{deletionDate} and deletion_type=#{deletionType}
     </select>
 
+    <resultMap id="BaseEmailMap" type="com.simuwang.base.pojo.dos.EmailDeletionInfoDO">
+        <result column="fund_name" property="fundName"/>
+        <result column="company_name" property="companyName"/>
+        <result column="deletion_date" property="deletionDate"/>
+        <result column="deletion_type" property="deletionType"/>
+    </resultMap>
+    <select id="getDeletionInfoByFundId" resultType="com.simuwang.base.pojo.dos.EmailDeletionInfoDO">
+            select info.fund_name,c.company_name,d.deletion_type,d.deletion_date
+            from PPW_EMAIL.deletion_info d
+            join PPW_EMAIL.pvn_fund_info info on d.fund_id=info.fund_id
+            join PPW_EMAIL.pvn_company_info c on c.company_id=info.trust_id
+            where d.isvalid=1 and info.isvalid=1 and c.isvalid=1 and d.remark is null and d.is_send=0
+            and d.fund_id in
+            <foreach collection="fundIdList" index="index" item="fundId" separator="," open="(" close=")">
+                #{fundId}
+            </foreach>
+            order by info.fund_id desc,d.deletion_type desc,d.deletion_date desc
+    </select>
+    <update id="removeDistributeDeletion" parameterType="java.lang.String">
+        update PPW_EMAIL.deletion_info set isvalid=0,updatetime=sysdate() where fund_id=#{fundId} and remark is null
+    </update>
+    <update id="updateSendStatusByFundId">
+        update PPW_EMAIL.deletion_info d set is_send=1,updatetime=sysdate() where isvalid=1
+        and d.fund_id in
+        <foreach collection="fundIdList" index="index" item="fundId" separator="," open="(" close=")">
+            #{fundId}
+        </foreach>
+    </update>
+
 </mapper>

+ 4 - 0
service-base/src/main/resources/mapper/FundInfoMapper.xml

@@ -160,5 +160,9 @@
     <select id="getInceptionDateByFundId" resultType="java.lang.String" parameterType="java.lang.String">
         select inception_date from PPW_EMAIL.pvn_fund_info where fund_id=#{fundId} and isvalid=1
     </select>
+    <select id="getFundIdByCompanyId" resultType="java.lang.String" parameterType="java.lang.String">
+        select info.fund_id from PPW_EMAIL.pvn_fund_info info join PPW_EMAIL.pvn_company_info c on info.trust_id=c.company_id
+        where info.isvalid=1 and c.isvalid=1 and c.company_id=#{companyId}
+    </select>
 
 </mapper>

+ 13 - 1
service-deploy/src/main/resources/application.yml

@@ -50,6 +50,19 @@ spring:
     date-format: yyyy-MM-dd HH:mm:ss
     time-zone: Asia/Shanghai
 
+  mail:
+    host: smtp.exmail.qq.com
+    port: 465
+    protocol: smtp
+    username: chenjianhua@simuwang.com
+    password: Cjh@2021
+    properties:
+      mail:
+        smtp:
+          auth: true
+          ssl:
+            enable: true
+
 email-rule:
   nav: "净值,业绩报酬,规模"
   valuation: "估值表"
@@ -59,7 +72,6 @@ email:
   file:
     path: /data/file/nav
 
-
 # 配置
 simuwang:
   # 是否启用quartz定时任务功能

+ 132 - 4
service-manage/src/main/java/com/simuwang/manage/service/impl/CompanyEmailConfigServiceImpl.java

@@ -1,17 +1,36 @@
 package com.simuwang.manage.service.impl;
 
+import com.simuwang.base.common.enums.DeletionType;
 import com.simuwang.base.common.enums.OpenStatusType;
+import com.simuwang.base.common.enums.ResultCode;
+import com.simuwang.base.common.util.DateUtils;
+import com.simuwang.base.common.util.EmailUtil;
+import com.simuwang.base.common.util.ExcelUtil;
 import com.simuwang.base.common.util.StringUtil;
 import com.simuwang.base.mapper.CompanyEmailConfigMapper;
+import com.simuwang.base.mapper.CompanyEmailSendHistoryMapper;
+import com.simuwang.base.mapper.DeletionInfoMapper;
+import com.simuwang.base.mapper.FundInfoMapper;
 import com.simuwang.base.pojo.dos.CompanyEmailConfigDO;
+import com.simuwang.base.pojo.dos.CompanyEmailSendHistoryDO;
+import com.simuwang.base.pojo.dos.EmailDeletionInfoDO;
+import com.simuwang.base.pojo.dto.ExcelDeletionInfoDTO;
+import com.simuwang.base.pojo.dto.MailboxInfoDTO;
 import com.simuwang.base.pojo.vo.CompanyEmailConfigVO;
 import com.simuwang.manage.service.CompanyEmailConfigService;
+import jakarta.annotation.Resource;
+import jakarta.mail.Message;
+import jakarta.mail.Store;
+import jakarta.mail.internet.MimeMessage;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.stereotype.Service;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
 
 /**
  * FileName: CompanyEmailConfigServiceImpl
@@ -23,6 +42,28 @@ import java.util.List;
 public class CompanyEmailConfigServiceImpl implements CompanyEmailConfigService {
     @Autowired
     private CompanyEmailConfigMapper companyEmailConfigMapper;
+
+    @Autowired
+    private CompanyEmailSendHistoryMapper companyEmailSendHistoryMapper;
+    @Autowired
+    private FundInfoMapper fundInfoMapper;
+    @Autowired
+    private DeletionInfoMapper deletionInfoMapper;
+    @Resource
+    private JavaMailSender javaMailSender;
+
+    @Value("${email.file.path}")
+    private String path;
+    @Value("${spring.mail.username}")
+    private String account;
+    @Value("${spring.mail.password}")
+    private String password;
+    @Value("${spring.mail.host}")
+    private String host;
+    @Value("${spring.mail.port}")
+    private String port;
+    @Value("${spring.mail.protocol}")
+    private String protocol;
     @Override
     public void saveCompanyEmailConfig(List<CompanyEmailConfigVO> companyEmailConfigVOS) {
         try{
@@ -79,11 +120,98 @@ public class CompanyEmailConfigServiceImpl implements CompanyEmailConfigService
         for(Integer id : idList){
             CompanyEmailConfigDO configDO = companyEmailConfigMapper.selectCompanyEmailConfigById(id);
             //把缺失数据的邮件发送到该公司名下的邮箱地址
-            sendEmail(configDO.getCompanyId(),configDO.getEmail());
+            if(configDO.getOpenStatus().equals(OpenStatusType.YES.getCode())){
+                sendEmail(configDO.getCompanyId(),configDO.getEmail());
+            }
         }
     }
     //邮件校验处理
     private void sendEmail(String companyId, String email) {
+        List<String> fundIdList = fundInfoMapper.getFundIdByCompanyId(companyId);
+        if(fundIdList.size() < 1){
+            return;
+        }
+        List<EmailDeletionInfoDO> emailDeletionInfoDOS = deletionInfoMapper.getDeletionInfoByFundId(fundIdList);
+        for(EmailDeletionInfoDO infoDO : emailDeletionInfoDOS){
+            infoDO.setDeletionType(DeletionType.getDeletionTypeByCode(Integer.valueOf(infoDO.getDeletionType())).getInfo());
+        }
+        if(emailDeletionInfoDOS.size() > 0){
+            //将数据写入excel文件
+            File file = writeExcelFile(emailDeletionInfoDOS);
+            file.setWritable(true);
+            file.setReadable(true);
+            file.setExecutable(true);
+            try {
+                MailboxInfoDTO dto = getFromEmailInfo();
+                EmailUtil.senEmail(dto,email,file,javaMailSender);
+                //发送成功之后修改数据为已发送
+                deletionInfoMapper.updateSendStatusByFundId(fundIdList);
+                //写入发送历史
+                saveCompanyEmailSendHistory(companyId,email,1,ResultCode.SEND_SUCCESS.getMsg());
+            } catch (Exception e) {
+                saveCompanyEmailSendHistory(companyId,email,0,e.getMessage());
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    private void saveCompanyEmailSendHistory(String companyId, String email,Integer sendStatus,String msg) {
+        CompanyEmailSendHistoryDO historyDO = new CompanyEmailSendHistoryDO();
+        historyDO.setCompanyId(companyId);
+        historyDO.setEmail(email);
+        historyDO.setSendStatus(sendStatus);
+        historyDO.setSendRemark(msg);
+        historyDO.setIsvalid(1);
+        historyDO.setSendTime(DateUtils.getNowDate());
+        historyDO.setCreateTime(DateUtils.getNowDate());
+        historyDO.setCreateTime(DateUtils.getNowDate());
+        companyEmailSendHistoryMapper.saveCompanyEmailSendHistory(historyDO);
+    }
+
+
+    private MailboxInfoDTO getFromEmailInfo(){
+        MailboxInfoDTO dto = new MailboxInfoDTO();
+        dto.setAccount(account);
+        dto.setProtocol(protocol);
+        dto.setPassword(password);
+        dto.setPort(port);
+        dto.setHost(host);
+        return dto;
+    }
 
+    private File writeExcelFile(List<EmailDeletionInfoDO> emailDeletionInfoDOS) {
+        Map<String,List<List<String>>> values = new HashMap<>();
+        List<String> head = new ArrayList<>();
+        head.add("基金全称");
+        head.add("管理人");
+        head.add("缺失类型");
+        head.add("缺失日期");
+        String sheetName = "基金缺失明细";
+        List<List<String>> dataList = new ArrayList<>();
+        for(EmailDeletionInfoDO dto : emailDeletionInfoDOS){
+            List<String> data = new ArrayList<>();
+            data.add(dto.getFundName());
+            data.add(dto.getCompanyName());
+            data.add(dto.getDeletionType());
+            data.add(dto.getDeletionDate());
+            dataList.add(data);
+        }
+        values.put(sheetName,dataList);
+        HSSFWorkbook wb = ExcelUtil.getHSSFWorkbook(sheetName,head,values,null);
+        File file = new File(path+"/"+DateUtils.getDate()+"基金缺失明细.xls");
+        if(!file.exists()){
+            try {
+                file.createNewFile();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        try {
+            wb.write(file);
+            wb.close();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return file;
     }
 }

+ 1 - 0
service-manage/src/main/java/com/simuwang/manage/task/FundDeletionTask.java

@@ -292,6 +292,7 @@ public class FundDeletionTask {
         DeletionInfoDO oldDeletionDO = deletionInfoMapper.getDeletionInfoDO(deletionInfoDO);
         if(StringUtil.isNull(oldDeletionDO)){
             deletionInfoDO.setIsvalid(1);
+            deletionInfoDO.setIsSend(0);
             deletionInfoDO.setUpdateTime(DateUtils.getNowDate());
             deletionInfoDO.setCreateTime(DateUtils.getNowDate());
             deletionInfoMapper.saveDeletionInfoDO(deletionInfoDO);