1. 程式人生 > >傳送郵件工具類及操作(例子)

傳送郵件工具類及操作(例子)

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=[email protected]*.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;
}