发送邮件工具类及操作(例子)

1.所需要工具类

 1.1ExcelUtil工具

    
package com.finlabtech.pinjamancepatanalyse.util;

import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * excel util
 */
public class ExcelUtil implements Closeable {

   private final Logger logger  = LoggerFactory.getLogger(ExcelUtil.class);

   private Workbook workbook;
   private Sheet sheet;
   private CellStyle[] cellStyles;
   private LinkedHashMap<String, String> propertyMapping;
   private Map<String, Short> map;
   private PropertyDescriptor[] propertyDescriptors;

   /**
    * @param propertyMapping LinkedHashMap:对象属性和excel表头对应,对象属性为key,表头中文名为value,map.put的顺序即为excel列的顺序
    * @return
    */
   public ExcelUtil setPropertyMapping(LinkedHashMap<String, String> propertyMapping){
      this.propertyMapping = propertyMapping;
      this.map = new HashMap<String, Short>();
      Short i = 0;
      for(String e : propertyMapping.keySet()){
         this.map.put(e, i++);
      }
      return this;
   }
   

   /**
    * 创建一个工作簿
    * @param <T>
    * @return this
    */
   public <T> ExcelUtil createWorkbook() {
      workbook =  new XSSFWorkbook();
      return this;
   }

    /**导出
     * @param sheetName sheet
     * @param datas datas
     * @param clazz clazz
     * @return this
     */
    public <T> void createExcel(String sheetName, List<?> datas, Class<T> clazz) {
       setPropertyDescriptors(clazz);
       //初始化 样式数组大小
       cellStyles = new CellStyle[propertyMapping.size()];
      sheet = workbook.createSheet(sheetName);
      //写表头按照map 的顺序
      Row titleRow = sheet.createRow(0); // 头
      int titleCellIndex = 0;
      for (String titleName : propertyMapping.values()) {
         Cell cell = titleRow.createCell(titleCellIndex);
         cellStyles[titleCellIndex] = workbook.createCellStyle();
         cell.setCellValue(titleName);
         formatHeadCell(cell, 0, titleCellIndex++);
      }
      //数据
      if(datas != null && !datas.isEmpty()) {
         for (int i = 0; i < datas.size(); i++) {
            Object dataObj = datas.get(i);
            Row row = sheet.createRow(i + 1);
            Object[] fields = propertyMapping.keySet().toArray();
            for(int j = 0; j < fields.length; j++){
               Cell cell = row.createCell(j);
               for (int p =0 ; p < propertyDescriptors.length ; p++) {
                  String name = propertyDescriptors[p].getName();
                  if(fields[j].toString().equals(name)){
                     Method method = propertyDescriptors[p].getReadMethod();
                     Object value = null;
                     try {
                        value = method.invoke(dataObj, null);
                     } catch (Exception e) {
                        logger.error(e.getMessage(),e);
                     }
                     if(value == null) {
                        cell.setCellValue("");
                     }else {
                        if(value instanceof String) {
                           cell.setCellValue((String)value);
                        }else if(value instanceof Integer) {
                           cell.setCellValue((double)value);
                        }
                     }
                     formatContentCell(cell, i, j,value);
                  }
               }

            }
         }
      }
    }


   /**
    * 设置属性描述器
    * @param c
    * @param <T>
    */
   private <T> void setPropertyDescriptors(Class<T> c) {
      BeanInfo beaninfo;
      try {
         beaninfo = Introspector.getBeanInfo(c);
         this.propertyDescriptors = beaninfo.getPropertyDescriptors();
      } catch (IntrospectionException e) {
         logger.error(e.getMessage(),e);
      }
   }


   /**
    * 将工作簿转成字节数组
    * @return byte[]
    */
   public byte[] toByteArray() {
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      try {
         workbook.write(out);
      } catch (IOException e) {
         logger.error("[ExcelUtil] 关流异常", e);
      } finally{
         try {
            workbook.close();
            out.close();
         } catch (IOException e) {
            logger.error("[ExcelUtil] 关流异常", e);
         }
      }
      return out.toByteArray();
   }

    /**
     * 需要子类实现抽象方法,目的每个导出所需样式 可个性化配置,excel主体的样式
     */
    protected void formatContentCell(Cell cell, int rowIndex, int colIndex,Object value) {
      if(value == null) {
         cell.setCellValue("");
      }else {
         // 自适应宽度
         int cellLength = value.toString().getBytes().length;
         // excel有列宽限制的 255字符
         if (cellLength > 125) {
            cellLength = 125;
         } else if (cellLength < 10) {
            cellLength = 10;
         }
         sheet.setColumnWidth(colIndex, cellLength * 2 * 256);
      }
      cell.setCellStyle(cellStyles[colIndex]);
    }
    
    /**
     *     需要子类实现抽象方法,目的每个导出所需样式 可 个性化配置,excel主体的样式
     */
   protected void formatHeadCell(Cell cell, int rowIndex, int colIndex) {
      sheet.setColumnWidth(colIndex, 10 * 2 * 256);
      setGeneralProperty(cellStyles[colIndex]);
      cell.setCellStyle(cellStyles[colIndex]);
    }
   /**
    * 功能描述:设置EXCEL表格基本样式
    */
   protected void setGeneralProperty(CellStyle style) {
      style.setBorderBottom(BorderStyle.THIN);
      style.setBottomBorderColor(HSSFColor.BLACK.index);
      style.setBorderLeft(BorderStyle.THIN);
      style.setLeftBorderColor(HSSFColor.BLACK.index);
      style.setBorderRight(BorderStyle.THIN);
      style.setRightBorderColor(HSSFColor.BLACK.index);
      style.setBorderTop(BorderStyle.THIN);
      style.setTopBorderColor(HSSFColor.BLACK.index);
      style.setAlignment(HorizontalAlignment.CENTER);
   }

   @Override
   public void close(){
      try {
         if (workbook != null) {
            workbook.close();
         }
      } catch (IOException e) {
         logger.error("[ExcelUtil] 关流异常");
      }
   }
}

1.2MailUtil工具

package com.finlabtech.pinjamancepatanalyse.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

import javax.mail.internet.MimeMessage;
import java.io.Serializable;

@Slf4j
public class MailUtil implements Serializable {
    /**
     * 发送一个支持html 和 附件 的邮件
     * @param param Sender,Subject,Receiver,ContentText,AttachmentFileName,Attachment必选,Copier选填
     */
    public static void sendHtmlAndAttachmentMail(SendMailParam param){

        JavaMailSender mailSender = ApplicationContextHolder.getBean("sysMailSender");
        MimeMessage mimeMessage;
        try {
            mimeMessage = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
            helper.setFrom(param.getSender());
            helper.setSubject(param.getSubject());
            helper.setTo(param.getReceiver());
            if (ArrayUtils.isNotEmpty(param.getCopier())) {
                helper.setCc(param.getCopier());
            }
            helper.setText(param.getContentText(),Boolean.TRUE);
            helper.addAttachment(param.getAttachmentFileName(), param.getInputStreamSource());
            mailSender.send(mimeMessage);
        } catch (Exception e) {
            log.error("[MailUtilSendMail] 邮件发送失败。", e);
        }

    }
}

1.3SendMailParam

package com.finlabtech.pinjamancepatanalyse.util;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.core.io.InputStreamSource;

import java.io.Serializable;

@Data
@NoArgsConstructor
public class SendMailParam implements Serializable {
    private static final long serialVersionUID = -1L;

    private String subject;
    private String sender;
    private String[] receiver;
    private String[] copier;
    private String contentText;
    private String attachmentFileName;
    private InputStreamSource inputStreamSource;

    /**
     * 附件邮件参数
     * @param subject 主题
     * @param sender 发件人
     * @param receiver 收件人
     * @param copier 抄送人
     * @param contentText 内容
     * @param attachmentFileName 附件名称
     * @param inputStreamSource 附件流
     */
    public SendMailParam(String subject, String sender, String[] receiver, String[] copier, String contentText, String attachmentFileName, InputStreamSource inputStreamSource) {
        this.subject = subject;
        this.sender = sender;
        this.receiver = receiver;
        this.copier = copier;
        this.contentText = contentText;
        this.attachmentFileName = attachmentFileName;
        this.inputStreamSource = inputStreamSource;
    }
}

1.4需要写自己的对应实体类

eg:

package com.finlabtech.pinjamancepatanalyse.model.analyse;

import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
public class BillData implements Serializable {

    private static final long serialVersionUID = -1L;

    private String payId;

    private String amount;

    private String tradeTime;

    private String bankCode;

    private String accountNumber;

    private String userId;

    private String orderId;

    private String type;

    private String diff;

    private String differenceBelong;

    private String payStatus;

    private String status;

    private String channel;

}

1.5邮件的config配置

package com.finlabtech.pinjamancepatanalyse.config.mail;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import java.util.Properties;

@Configuration
public class MailConfig {
    @Value("${sys.mail.from}")
    private String username;
    @Value("${sys.mail.host}")
    private String host;
    @Value("${sys.mail.port}")
    private int port;
    @Value("${sys.mail.password}")
    private String password;

    @Bean(name = "sysMailSender")
    public JavaMailSender getSender(){

        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
        javaMailSender.setUsername(username);
        javaMailSender.setHost(host);
        javaMailSender.setPort(port);
        javaMailSender.setDefaultEncoding("UTF-8");
        javaMailSender.setPassword(password);
        javaMailSender.setProtocol("smtp");
        Properties prop = new Properties() ;
        prop.put("mail.smtp.auth", "true") ;
        prop.put("mail.smtp.timeout", "25000") ;
        javaMailSender.setJavaMailProperties(prop);
        return javaMailSender;
    }
}

1.6properties配置

sys.mail.from=system@*.com
sys.mail.host=smtp.exmail.qq.com
sys.mail.password=*
sys.mail.port=25
sys.mail.receiver=**.*@*.com,***.*@*.com

1.7ApplicationContextHolder调用

package com.finlabtech.pinjamancepatanalyse.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextHolder implements ApplicationContextAware {

    /**
     * Spring应用上下文环境
     */
    private static ApplicationContext applicationContext;

    /**
     * 实现ApplicationContextAware接口的回调方法,设置上下文环境.
     *
     * @param applicationContext Spring ApplicationContext上下文
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        ApplicationContextHolder.applicationContext = applicationContext;
    }

    /**
     * 获取一个ApplicationContext.
     *
     * @return ApplicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 根据名称获取一个对象.
     *
     * @param name bean名称
     * @return Object 指定的bean
     * @throws BeansException 如果找不到bean
     */
    public static <T> T getBean(String name) throws BeansException {
        return (T) applicationContext.getBean(name);
    }

    /**
     * 获取名称为name的bean,自动转为所需类型.
     *
     * @param <T>          需求的bean类型
     * @param name         bean名称
     * @param requiredType 需求的bean类型
     * @return 指定类型的bean
     * @throws BeansException 如果找不到匹配的类型,或是类型不能被转换,或是bean实例化失败
     */
    public static <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return applicationContext.getBean(name, requiredType);
    }

    /**
     * 获取类型为requiredType的对象.
     *
     * @param <T>          需求的bean类型
     * @param requiredType 需求的bean类型
     * @return 指定类型的bean
     * @throws BeansException 如果找不到匹配的类型
     */
    public static <T> T getBean(Class<T> requiredType) throws BeansException {
        return applicationContext.getBean(requiredType);
    }

    /**
     * 检测一个bean是否已经被定义.
     *
     * @param name bean名称
     * @return boolean 如果bean已经被定义,则返回true,否则返回false
     */
    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }

    /**
     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype.
     *
     * @param name bean名称
     * @return boolean 如果是singleton则返回true
     * @throws NoSuchBeanDefinitionException 如果bean名称不存在
     */
    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
        return applicationContext.isSingleton(name);
    }

    /**
     * 获取给定名字的bean的类型.
     *
     * @param name bean名称
     * @return Class bean类型
     * @throws NoSuchBeanDefinitionException 如果bean名称不存在
     */
    public static Class getType(String name) throws NoSuchBeanDefinitionException {
        return applicationContext.getType(name);
    }

    /**
     * 取出指定bean的别名列表.
     *
     * @param name bean名称
     * @return 如果有别名,返回别名,否则返回空数组.
     * @throws NoSuchBeanDefinitionException 如果bean名称不存在
     */
    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
        return applicationContext.getAliases(name);
    }

}

2.例子

 List<BillData> billData = new LinkedList<>();

    for (TradeCheck tradeCheck : weTradeChecks) {
        BillData check = new BillData();
        check.setPayId(tradeCheck.getPayId());
        check.setAccountNumber(tradeCheck.getAccountNumber());
        check.setAmount(tradeCheck.getAmount().toString());
        check.setBankCode(tradeCheck.getBankCode());
        check.setChannel(tradeCheck.getChannel().equals(1) ? "xendit" : "其他");
        check.setOrderId(tradeCheck.getOrderId().toString());
        check.setPayStatus(tradeCheck.getPayStatus());
        String diff;
        switch (tradeCheck.getDiff()) {
            case 0:
                diff = "我方单边";
                break;
            case 1:
                diff = "Xendit单边";
                break;
            case 2:
                diff = "双方差异";
                break;
            case 3:
                diff = "无差异";
                break;
            default:
                diff = "其他";
        }
        check.setDiff(diff);

        String belong;
        switch (tradeCheck.getDifferenceBelong()) {
            case 0:
                belong = "没有差异";
                break;
            case 1:
                belong = "我方记录";
                break;
            case 2:
                belong = "对方记录";
                break;
            default:
                belong = "其他";
        }
        check.setDifferenceBelong(belong);
        check.setStatus(tradeCheck.getStatus().equals(1) ? "已处理" : "未处理");
        check.setTradeTime(tradeCheck.getTradeTime().toString());
        check.setType(tradeCheck.getType() == 1 ? "放款" : "还款");
        check.setUserId(tradeCheck.getUserId().toString());
        billData.add(check);
    }

    int noDiff = noTradeChecks.size();

    String content = "对账后差异总笔数=" + weTradeChecks.size() + ",一致笔数=" + noDiff + ",部分差异数据如下,该天的对账差异数据在附件中,请及时查看并处理";

    SendMailParam param = new SendMailParam();
    param.setReceiver(receiver.split(","));
    param.setSender(username);
    param.setSubject("Finlabtech-Xendit贷款/还款资金对账差异_" + paramMap.get("start") + "~" + paramMap.get("end"));
    param.setContentText(content);
    param.setAttachmentFileName("对账结果.xlsx");
    ExcelUtil excel = null;
    try {
        excel = new ExcelUtil();
        excel.createWorkbook();
        excel.setPropertyMapping(getFeedbackMap()).createExcel("对账详情", billData, BillData.class);
        param.setInputStreamSource(new ByteArrayResource(excel.toByteArray()));
        MailUtil.sendHtmlAndAttachmentMail(param);
    } catch (Exception e) {
        log.error("对账邮件异常 e={}", e);
    } finally {
        if (excel != null) {
            excel.close();
        }
    }
}

private LinkedHashMap<String, String> getFeedbackMap() {
    LinkedHashMap<String, String> param = new LinkedHashMap<>();

    param.put("payId", "支付id(还/放)");
    param.put("amount", "交易金额");
    param.put("tradeTime", "交易时间(放/还)");
    param.put("bankCode", "银行代码");
    param.put("accountNumber", "用户银行账号");
    param.put("userId", "用户id");
    param.put("orderId", "订单id");
    param.put("type", "交易类型");
    param.put("diff", "对账差异");
    param.put("differenceBelong", "差异归属");
    param.put("payStatus", "交易状态");
    param.put("status", "对账处理状态");
    param.put("channel", "渠道");

    return param;
}

猜你喜欢

转载自blog.csdn.net/Alice_8899/article/details/79468780