java 使用poi生成简单excel表格并发送邮件

时间:2024-03-20 20:36:33

由于最近项目原因需要使用Java将数据导出成excel文件并发送给某邮箱,借鉴了各位前辈大佬们的经验写了个简单的demo方法。现将代码记录如下:

详细介绍可参考:https://www.cnblogs.com/huajiezh/p/5467821.html

poi 表格背景色:https://www.cnblogs.com/toumh/p/npoi-color-value.html

总体的思路就是:1、使用poi工具的HSSFWorkbook类创建一张表

                             2、创建行(row),自定义相关行的样式或内容来生成标题、表头或表数

                                  据

                             3、行内创建单元格(cell),每个cell对应行内一个列元素,所以填充的数

                                  组或集合必须是有序的

 

一、首先是使用到的依赖jar包

<!-- poi excel生成依赖jar-->
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId>
  <version>3.17</version>
</dependency>
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi</artifactId>
  <version>3.17</version>
</dependency>
<!--发送邮件依赖jar包-->
  <!-- https://mvnrepository.com/artifact/javax.mail/javax.mail-api -->
  <dependency>
    <groupId>javax.mail</groupId>
    <artifactId>javax.mail-api</artifactId>
    <version>1.6.1</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/com.sun.mail/javax.mail -->
  <dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.1</version>
  </dependency>

 二、cell单元格工具类

          这个类是自己编写用于筛除一些表数据BUG的,实际上可以不使用

package com.demo.po;

import org.apache.poi.hssf.usermodel.HSSFCell;

import java.math.BigDecimal;
import java.sql.Date;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.regex.Pattern;

public class CellUtil {
    
    public static String returnCellValue(HSSFCell cell){
        String cellvalue = "";
        if (null != cell) {   
            switch (cell.getCellType()) {   
            case HSSFCell.CELL_TYPE_NUMERIC: // 数字
                return String.valueOf(cell.getNumericCellValue()).trim();
            case HSSFCell.CELL_TYPE_STRING: // 字符串
                return String.valueOf(cell.getStringCellValue()).trim();
            case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
                return String.valueOf(cell.getBooleanCellValue()).trim();
            case HSSFCell.CELL_TYPE_FORMULA: // 公式
                return String.valueOf(cell.getCellFormula()).trim();
            case HSSFCell.CELL_TYPE_BLANK: // 空值
                return "";  
            case HSSFCell.CELL_TYPE_ERROR: // 故障
                return ""; 
            default:   
                return "";   
            }   
        } else {   
            
        }  
        return cellvalue;
    }
    
    //避免cell.setCellValue(checkOrderQmSave.getSellOrderNo())中参数为空就会报错
    public static void setCellValue(HSSFCell cell, Object object){
        if(object == null){
            cell.setCellValue("");  
        }else{
            if (object instanceof String) {
                cell.setCellValue(String.valueOf(object));
            }else if(object instanceof Long){
                Long temp = (Long)object;
                String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue());
                cell.setCellValue(cellvalue);  
            }else if(object instanceof Double){
                Double temp = (Double)object;
                String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue());
                cell.setCellValue(cellvalue);  
            }else if(object instanceof Float){
                Float temp = (Float)object;
                String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue());
                cell.setCellValue(cellvalue);  
            }else if(object instanceof Integer){
                Integer temp = (Integer)object;
                cell.setCellValue(temp.intValue());  
            }else if(object instanceof BigDecimal){
                BigDecimal temp = (BigDecimal)object;
                String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue());
                cell.setCellValue(cellvalue);  
            }else{
                cell.setCellValue("");  
            }
        }
    }
    public static void setCellValue(HSSFCell cell, Object object, String model){
        if(object == null){
            cell.setCellValue("");  
        }else{
            if (object instanceof String) {
                cell.setCellValue(String.valueOf(object));
            }else if(object instanceof Long){
                Long temp = (Long)object;
                String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue());
                cell.setCellValue(cellvalue);  
            }else if(object instanceof Double){
                Double temp = (Double)object;
                String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue());
                cell.setCellValue(cellvalue);  
            }else if(object instanceof Float){
                Float temp = (Float)object;
                String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue());
                cell.setCellValue(cellvalue);  
            }else if(object instanceof Integer){
                Integer temp = (Integer)object;
                cell.setCellValue(temp.intValue());  
            }else if(object instanceof BigDecimal){
                BigDecimal temp = (BigDecimal)object;
                String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue());
                cell.setCellValue(cellvalue);  
            }else if(object instanceof Date){
                cell.setCellValue(new SimpleDateFormat(model).format(object));
            }else if(object instanceof java.util.Date){
                cell.setCellValue(new SimpleDateFormat(model).format(object));
            }else{
                cell.setCellValue("");  
            }
        }
    }
    public static void setCellValue(HSSFCell cell, String object){
        if(object == null){
            cell.setCellValue("");  
        }else{
            cell.setCellValue(object);  
        }
    }
    public static void setCellValue(HSSFCell cell, Long object){
        if(object == null){
            cell.setCellValue("");  
        }else{
            cell.setCellValue(object.doubleValue());  
        }
    }
    public static void setCellValue(HSSFCell cell, Double object){
        if(object == null){
            cell.setCellValue("");  
        }else{
            cell.setCellValue(object.doubleValue());  
        }
    }
    public static void setCellValue(HSSFCell cell, double object){
        
            cell.setCellValue(object);  
        
    }
    public static void setCellValue(HSSFCell cell, Date object, String model){
        if(object == null){
            cell.setCellValue("");  
        }else{
            cell.setCellValue(new SimpleDateFormat(model).format(object));
        }
    }
    public static void setCellValue(HSSFCell cell, java.util.Date object, String model){
        if(object == null){
            cell.setCellValue("");  
        }else{
            cell.setCellValue(new SimpleDateFormat(model).format(object));
        }
    }
    public static void setCellValue(HSSFCell cell, BigDecimal object){
        if(object == null){
            cell.setCellValue("");  
        }else{
            cell.setCellValue(object.toString());  
        }
    }
    
    //判断EXCEL表格高度用 row.setHeight((short) CellUtil.getExcelCellAutoHeight(TAR_VAL_ALL_STRING, 280, 30));
    public static float getExcelCellAutoHeight(String str, float defaultRowHeight, int fontCountInline) {
        int defaultCount = 0;
        for (int i = 0; i < str.length(); i++) {
            int ff = getregex(str.substring(i, i + 1));
            defaultCount = defaultCount + ff;
        }
        if (defaultCount > fontCountInline){
            return ((int) (defaultCount / fontCountInline) + 1) * defaultRowHeight;//计算
        } else {
            return defaultRowHeight;
        }
    }
    public static int getregex(String charStr) {
        if("".equals(charStr) || charStr == null){
            return 1;
        }
        // 判断是否为字母或字符
        if (Pattern.compile("^[A-Za-z0-9]+$").matcher(charStr).matches()) {
            return 1;
        }
        // 判断是否为全角
        if (Pattern.compile("[\u4e00-\u9fa5]+$").matcher(charStr).matches()) {
            return 2;
        }
        //全角符号 及中文
        if (Pattern.compile("[^x00-xff]").matcher(charStr).matches()) {
            return 2;
        }
        return 1;
    }
}

三、表格创建并发送邮件

     这一段是重点!这一段是重点!这一段是重点!

package com.demo;

import com.bnwisdom.dao.BnVoteDao;
import com.bnwisdom.dao.BnVoteOptionDao;
import com.bnwisdom.dao.BnVoteOptionGroupDao;
import com.bnwisdom.dao.BnVoteRecordsDao;
import com.bnwisdom.po.ApiResult;
import com.bnwisdom.po.CellUtil;
import com.bnwisdom.po.ConfigUtils;
import com.bnwisdom.service.ExportSendMailService;
import com.bnwisdom.vo.BnVoteOptionGroupVo;
import com.bnwisdom.vo.BnVoteOptionVo;
import com.bnwisdom.vo.BnVoteVo;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.*;
import javax.mail.internet.*;
import javax.mail.util.ByteArrayDataSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @Author 一只菜鸡
 * @CreateTime 2019/4/1 14:32
 * @Version 1.0
 * @Descr
 **/
public class ExportSendMail{
    //日志打印
    Logger log=Logger.getLogger(ExportSendMailServiceImpl.class);

    public String exportSendEmail(String userEmail) throws Exception {
        //表的标题名称
        String sheetName="教师满意度调查(投票统计表)";
        //表头集合
        List<String> tableHead=new ArrayList<String>(); 
        tableHead.add("投票对象")
        tableHead.add("很满意")
        tableHead.add("满意")
          .  .  .  .
        //表格内数据内容,此处为一个双层集合数组,外层数组代表的是总的表格内容,数组长度为行数(不包括标题和表头),
        //第二层数组类似于行,数组内每个元素对应一个单元格,因此二层数组长度应与表头数组长度一致,不然会出现单元格缺失
        List<List<Object>> tableBody=new ArrayList<>();
        List<Object> tableRow1=new ArrayList<>();
        tableRow1.add("张三");
        tableRow1.add(2);
        tableRow1.add(1);
          .  .  .  .
       List<Object> tableRow2=new ArrayList<>();
       tableRow2.add("李四");
       tableRow2.add(1);
       tableRow2.add(2);
          .  .  .  .
       tableBody.add(tableRow1);
       tableBody.add(tableRow2);
        boolean boo = false;
        try {
            InputStream is = exportXls(sheetName,tableHead,tableBody);
            if(is == null){
                return "创建表格失败";
            }else{
                boo = sendMail(is, sheetName, userEmail);
                is.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (boo) {
            return "导出成功";
        } else {
            return "导出数据失败";
        }
    }

    /**
     * 生成表格并返回结果流
     * @param sheetName  表名
     * @param tableHead  表头
     * @param tableBody  表格数据(双层集合数组)
     * @return 生成的表格以流的形式返回
     * @throws Exception
     */
     public InputStream exportXls( String sheetName,List<String> tableHead,List<List<Object>> tableBody)
            throws Exception {
        HSSFWorkbook workbook = new HSSFWorkbook();
         // 创建一张excel表
        HSSFSheet sheet = workbook.createSheet(sheetName);
         //   ---------------- 表标题样式 -------------------
         HSSFFont headfont = workbook.createFont();
         headfont.setFontName("宋体");
         // 设置字体大小
         headfont.setFontHeightInPoints((short) 18);
         //粗体显示
         headfont.setBold(true);
         //设置单元格样式
         HSSFCellStyle headstyle = workbook.createCellStyle();
         //设置文字样式
         headstyle.setFont(headfont);
         // 单元格内容左右居中
         // 设置单元格上下居中
         headstyle.setAlignment(HorizontalAlignment.CENTER);
         headstyle.setVerticalAlignment(VerticalAlignment.CENTER);
         // 设置标题固定
         headstyle.setLocked(true);

//   ---------------  表头样式 -----------------
         HSSFFont font = workbook.createFont();
         font.setFontName("宋体");
         font.setFontHeightInPoints((short) 12);
         HSSFCellStyle style = workbook.createCellStyle();
         //设置表头背景色
         style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index);
         style.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.index);
         style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
         //单元格边框属性设置
         style.setBorderBottom(BorderStyle.THIN);
         style.setBorderLeft(BorderStyle.THIN);
         style.setBorderRight(BorderStyle.THIN);
         style.setBorderTop(BorderStyle.THIN);
         style.setFont(font);
         style.setAlignment(HorizontalAlignment.CENTER);
         style.setVerticalAlignment(VerticalAlignment.CENTER);
         style.setLocked(true);

//   -------------- 普通单元格样式(中文) ---------------
         HSSFFont font2 = workbook.createFont();
         font2.setFontName("宋体");
         font2.setFontHeightInPoints((short) 12);
         font2.setBold(true);
         HSSFCellStyle style2 = workbook.createCellStyle();
         style2.setBorderBottom(BorderStyle.THIN);
         style2.setBorderLeft(BorderStyle.THIN);
         style2.setBorderRight(BorderStyle.THIN);
         style2.setBorderTop(BorderStyle.THIN);
         style2.setFont(font2);
         // 设置单元格内容自动换行
         style2.setWrapText(true);
         style2.setAlignment(HorizontalAlignment.CENTER);
         style2.setVerticalAlignment(VerticalAlignment.CENTER);

         //设置默认行高
        sheet.setDefaultRowHeight((short)360);
        // 第一行,添加表的标题
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, tableHead.size()-1));
        HSSFRow row = sheet.createRow(0);
        row.setHeight((short) 0x349);
        HSSFCell cell = row.createCell(0);
        cell.setCellStyle(headstyle);
        CellUtil.setCellValue(cell, sheetName);

        //第二行,添加表头
        row = sheet.createRow(1);
        row.setHeight((short)0x180);
        for (int j = 0; j < tableHead.size(); j++) {
            //设置每列的宽度 (自定义列宽) 4200为每列最小宽度
            int dataLength=tableHead.get(j).getBytes().length*2*232;
            sheet.setColumnWidth((short)j,dataLength<4200?4200:dataLength);
            //在行内创建一个单元格
            cell = row.createCell(j);
            //单元格设置自定样式 style(上边有定义)
            cell.setCellStyle(style);
            cell.setCellType(HSSFCell.CELL_TYPE_STRING);
            //将数据填充进表格内 cell:创建的单元格    tableHead.get(j):数据
            CellUtil.setCellValue(cell, tableHead.get(j));
        }

        // 设置列值-每行数据的内容
        for (int i = 0; i < tableBody.size(); i++) {
            //标题、表头字段共占了2行,所以在填充数据的时候要加2,也就是数据要从第3行开始填充
            row = sheet.createRow(i + 2);
            for (int j = 0; j < tableBody.get(i).size(); j++) {
                    cell = row.createCell(j);
                    cell.setCellStyle(style2);
                    cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                    CellUtil.setCellValue(cell, tableBody.get(i).get(j));
            }
        }
        //以下代码需要修改为下载到某个路径
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        workbook.write(bos);
        return new ByteArrayInputStream(bos.toByteArray());
    }

    /**
     * 发送邮件
     * @param is  表格输出流
     * @param fileName  发送的文件名称 (例:xxxx统计表)
     * @param reUserMail  收件人邮箱(例:[email protected])
     */
    public boolean sendMail(InputStream is, String fileName, String reUserMail){
        log.info("[ 开始发送邮件... ]");
        Transport transport = null;
        try{
            System.setProperty("mail.mime.splitlongparameters","false");
            Properties props = new Properties();
            // 设置发送邮件的邮件服务器的属性(这里使用网易的smtp服务器)
            props.put("mail.smtp.host","smtp.exmail.qq.com");
            // 需要经过授权,也就是有户名和密码的校验,这样才能通过验证(一定要有这一条)
            props.put("mail.smtp.auth", "true");
            // 用刚刚设置好的props对象构建一个session
            Session session = Session.getDefaultInstance(props);
            // 有了这句便可以在发送邮件的过程中在console处显示过程信息,供调试使
            // 用(你可以在控制台(console)上看到发送邮件的过程)
            session.setDebug(false);
            // 用session为参数定义消息对象
            MimeMessage message = new MimeMessage(session);
            // 加载发件人地址
            message.setFrom(new InternetAddress("[email protected]"/*删除此段-发件邮箱*/));
            // 加载收件人地址
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(reUserMail));
            // 加载标题
            message.setSubject(fileName);

            // 向multipart对象中添加邮件的各个部分内容,包括文本内容和附件
            Multipart multipart = new MimeMultipart();

            // 设置邮件的文本内容
            BodyPart contentPart = new MimeBodyPart();
            contentPart.setText("请查看附件");
            multipart.addBodyPart(contentPart);
            // 添加附件
            BodyPart messageBodyPart = new MimeBodyPart();
            DataSource source = new ByteArrayDataSource(is, "application/msexcel");
            // 添加附件的内容
            messageBodyPart.setDataHandler(new DataHandler(source));
            // 添加附件的标题
            // 这里很重要,通过下面的Base64编码的转换可以保证你的中文附件标题名在发送时不会变成乱码
            messageBodyPart.setFileName(MimeUtility.encodeText(fileName+".xls"));
            multipart.addBodyPart(messageBodyPart);

            // 将multipart对象放到message中
            message.setContent(multipart);
            // 保存邮件
            message.saveChanges();
            // 发送邮件
            transport = session.getTransport("smtp");
            // 连接服务器的邮箱
            transport.connect("smtp.exmail.qq.com", "aaaa"/*删除此段-发件人名称*/, "123456"/*删除此段-发件人邮箱密码*/);
            // 把邮件发送出去
            transport.sendMessage(message, message.getAllRecipients());
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }finally {
            try {
                transport.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }
}

附上一张效果截图 

java 使用poi生成简单excel表格并发送邮件