利用POI实现电子表格导出/导入操作

利用POI实现电子表格导出/导入操作

1. 需要的依赖

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>

2. 工具类

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: 枫叶
 * Date: 2020/12/22
 * Description:  excel读写工具类,需要poi-4.0.1.jar、poi-ooxml-4.0.1.jar、poi-ooxml-schemas-4.0.1.jar、xmlbeans-3.0.2.jar四个核心jar包
 * 还需要commons-collections4-4.2.jar和commons-compress-1.18.jar两个辅助包
 * Version: V1.0
 */
@SuppressWarnings("all")
public class POIUtil {

    /**
     * 根据fileType不同读取excel文件
     *
     * @param path 请求硬盘物理路径中的一个excel文件可以是xls,也可以是xlsx文件
     * @return 返回数据列表
     */
    public static List<List<String>> readExcelForPOI(InputStream ins, String fileType) throws IOException {
        List<List<String>> lists = new ArrayList<>();
        Workbook wb = null;
        if ("xls".equals(fileType)) {                  // 判断是2003版本还是2007之后的版本,xls为2003版本,xlsx为2007版本
            wb = new HSSFWorkbook(ins);                 // HSSFWorkbook类型对应2003版本
        } else if ("xlsx".equals(fileType)) {
            wb = new XSSFWorkbook(ins);                 // XSSFWorkbook类型对应2007之后版本
        } else {
            return null;
        }
        Sheet sheet = wb.getSheetAt(0);             //假设读取第一个工作页sheet,index默认从0开始,如果存在多个sheet,那么需要循环Sheet判断
        for (Row row : sheet) {                       //循环读取第一个工作页中的每一行记录
            ArrayList<String> list = new ArrayList<>();
            for (Cell cell : row) {                   // 循环读取一行中的每一列数据
                cell.setCellType(CellType.STRING);    // 根据不同类型转化成字符串
                list.add(cell.getStringCellValue());   // 获取当前列中的数据
            }
            lists.add(list);
        }
        return lists;
    }

    public static List<List<String>> readExcelForPOI(String path) {
        String fileType = path.substring(path.lastIndexOf(".") + 1);   // 获取文件的后缀名
        List<List<String>> lists = null;          // 里面的list代表每一行数据,外面list代表所有行数据,实际项目中,需要把excel中的每一行数据做成POJO对象处理
        InputStream is = null;                                             // 生成输入流
        try {
            lists = readExcelForPOI(is, fileType);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return lists;
    }

    /**
     * 创建Excel.xls   返回一个Workbook对象,外部调用方式:首先创建一个OutputStream对象,然后通过workbook.write(out);完成输出
     *
     * @param lists 需要写入excel的数据
     * @param name  文件名
     * @return 返回一个excel poi Workbook对象,如果没有解析成功,或者没有传入数据列表,则会返回null
     * @throws IOException 如果IO失败会抛出异常
     */
    public static Workbook creatExcelForPOI(List<List<String>> lists, String name) throws IOException {
        /*
        操作excel五个核心  1.Font字体   2.CellStyle样式单   3.Sheet页   4.Row行   5.Cell列
        企业使用的是DOM4J、SAX完成xml解析,POI完成excel解析
        DOM4J:(50M大小以下)解析机制,首先完整读取xml,把xml所有的内容放入了电脑内存中,操作性能极高,而且在使用读取规则更方便
        SAX:解析机制,基于xml每一个节点位置来循环读取加载
        POI:解析机制,类似于SAX,并且可以和DOM4J、SAX结合完成读写操作
         */
        Workbook wb = new HSSFWorkbook();                        //  创建2003 excel对象 HSSFWorkbook类型对应2003版本    XSSFWorkbook类型对应2007之后版本
        Sheet sheet = wb.createSheet(name);                      // 创建第一个sheet(页),并命名,注意这里只创建一页,如果业务需求,可以添加多页

        Font f = wb.createFont();                                // 创建字体
        f.setFontHeightInPoints((short) 10);                     // 创建字体样式:字体大小
        f.setColor(IndexedColors.BLACK.getIndex());              // 创建字体样式:字体类型(这里设置的是黑体)
        f.setBold(true);                                         // 创建字体样式:粗体

        CellStyle cs = wb.createCellStyle();                     // 创建单元格每列格式对象
        cs.setFont(f);                                           // 把字体样式保存到样式单中
        cs.setBorderLeft(BorderStyle.THIN);                      // 设置具有边框的效果:左边框
        cs.setBorderRight(BorderStyle.THIN);                     // 设置具有边框的效果:右边框
        cs.setBorderTop(BorderStyle.THIN);                       // 设置具有边框的效果:上边框
        cs.setBorderBottom(BorderStyle.THIN);                    // 设置具有边框的效果:下边框
        cs.setAlignment(HorizontalAlignment.CENTER);             // 设置文字居中的效果

        if (lists == null || lists.size() == 0) {                 // 如果没有传递数据列表,则直接返回null
            return null;
        }

        for (int i = 0; i < lists.size(); i++) {                 // 设置每行每列的值  Row 行,Cell 方格 , Row 和 Cell 都是从0开始计数的
            Row row01 = sheet.createRow(i);                      // 在当前sheet页上创建一个新行
            List<String> listInner = lists.get(i);
            for (int j = 0; j < listInner.size(); j++) {
                sheet.setColumnWidth(j, 256 * 35);            // 设置列宽。第一个参数表示要为第几列,第二个参数表示列的宽度,值为像素值。
                Cell cell01 = row01.createCell(j);               // 在row行上创建一列
                cell01.setCellValue(listInner.get(j));         // 在此列上写入数据
                cell01.setCellStyle(cs);                         // 在此列上添加样式
            }
        }
        return wb;
    }
}

3. 导出数据库中的记录

这里使用servlet演示,ssm和boot需将代码迁移到controller中

/**
 * @author 枫叶
 * @version 1.0
 * @date 2020/12/23
 */
@WebServlet(value = {
        "/download/yongHuList"
},
        name = "download")
public class DownLoadServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        YongHuService yongHuService = new YongHuServiceImpl();
        //获取用户列表
        List<YongHu> yongHuList = yongHuService.selectYhList();
        List<List<String>> rowList = new ArrayList<>(yongHuList.size()+1);

        List<String> title = new ArrayList<>(1);
        title.add("用户名");
        title.add("密码");
        title.add("是否锁定");
        title.add("部门");
        title.add("权限");

        rowList.add(title);
        yongHuList.forEach(yongHu -> {
            List<String> row = new ArrayList<>(5);
            row.add(yongHu.getYongHuMing());
            row.add(yongHu.getMiMa());
            row.add(yongHu.getSuoDing() == 0 ? "否" : "是");
            row.add(yongHu.getBuMen().getBmMing());
            row.add(yongHu.getQuanXian().getQuanXianMing());
            rowList.add(row);
        });

        Workbook workbook = POIUtil.creatExcelForPOI(rowList, "用户");

        if (workbook != null) {
            resp.setCharacterEncoding("UTF-8");
            resp.setHeader("Content-Disposition", "attachment; filename=" + System.currentTimeMillis() + ".xls");
            //获取响应报文输出流对象
            ServletOutputStream out = resp.getOutputStream();
            //输出
            workbook.write(out);
            out.flush();
            out.close();
        } else {
            resp.setContentType("text/html;charset=utf-8");
            resp.getWriter().println(DataResponse.error("系统错误,或excel文件格式错误。"));
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

4. 上传excel文件并解析数据存到数据库

/**
 * @author 枫叶
 * @version 1.0
 * @date 2020/12/23
 */
@WebServlet(value = {
        "/upload/yongHuList"
},
        name = "upload")
public class UpLoadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        YongHuService yongHuService = new YongHuServiceImpl();
        BuMenService buMenService = new BuMenServiceImpl();
        QuanXianService quanXianService = new QuanXianServiceImpl();

        List<BuMen> buMenList = buMenService.chaXunBuMenList();
        List<QuanXian> quanXianList = quanXianService.selectQuanXianList();

        // 设置请求对象语言编码为UTF-8
        req.setCharacterEncoding("UTF-8");
        //固定写法
        boolean isMultipart = ServletFileUpload.isMultipartContent(req);
        if (isMultipart) {
            // 创建工厂(这里用的是工厂模式)
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 获取ServletContext
            ServletContext servletContext = req.getSession().getServletContext();
            // 获取从ServletContext中得到上传来的数据,fileupload固定的参数:javax.servlet.context.tempdir
            File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
            // fileupload封装上传来的文件的各种属性(上传来的文件的大小、文件名等)
            factory.setRepository(repository);
            // fileupload生成对应的数据参数对象
            ServletFileUpload upload = new ServletFileUpload(factory);
            // 把request转成fileupload中FileItem的实例
            List<FileItem> items = upload.parseRequest(req);
            System.out.println(items);

            FileItem item = items.get(0);
            String fieldName = item.getName();
            System.out.println("文件:"+fieldName+"读取成功");
            int lastIndex = fieldName.lastIndexOf(".");
            String houZhui = fieldName.substring(lastIndex + 1);
            System.out.println(houZhui);
            if (!("xls".equals(houZhui) || "xlsx".equals(houZhui))) {
                resp.getWriter().println(DataResponse.error("只能传Excel文件"));
                return;
            }
            InputStream fis = item.getInputStream();
            List<List<String>> lists = POIUtil.readExcelForPOI(fis, houZhui);
            if (lists == null || lists.size() == 0) {
                resp.getWriter().println(DataResponse.error("文件中没有数据。"));
                return;
            }
            List<YongHu> yongHuList = new ArrayList<>(lists.size() - 1);
            for (int i = 1; i < lists.size(); i++) {
                YongHu yongHu = new YongHu();
                List<String> row = lists.get(i);
                String col1 = row.get(0);
                String col2 = row.get(1);
                String col3 = row.get(2);
                String col4 = row.get(3);
                String col5 = row.get(4);
                yongHu.setYongHuMing(col1);
                yongHu.setMiMa(col2);
                short suoDing = (short) ("是".equals(col3) ? 1 : 0);
                yongHu.setSuoDing(suoDing);

                //将部门名映射成部门id
                int bmId = 0;
                for (BuMen buMen : buMenList) {
                    if (buMen.getBmMing().equals(col5)) {
                        bmId = buMen.getBid();
                        break;
                    }
                }
                yongHu.setBmId(bmId);
                //将权限名映射成权限id
                int qxId = 0;
                for (QuanXian quanXian : quanXianList) {
                    if (quanXian.getQuanXianMing().equals(col5)){
                        qxId=quanXian.getQxId();
                        break;
                    }
                }
                yongHu.setQxId(qxId);
                yongHuList.add(yongHu);
            }
            //数据存入数据库
            if (yongHuService.addYhList(yongHuList)) {
                resp.getWriter().println(DataResponse.ok("成功导入" + yongHuList.size() + "条数据"));
                return;
            }
            resp.getWriter().println(DataResponse.error("导入失败,请严格按照文件模板的格式写入EXCEL。"));
        }
    }
}

5. 上面用到的返回封装类DataResponse如下

public class DataResponse{
    private final Map<String,Object> result;

    @Override
    public String toString() {
            //这里也用到了fastJSON并且设置了日期的格式化格式
        JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd hh:mm:ss";
        return JSON.toJSONString(result,SerializerFeature.WriteDateUseDateFormat);
    }

    public DataResponse(Integer code,String msg,Object data){
        result = new HashMap<>();
        result.put("code",code);
        result.put("msg",msg);
        result.put("data",data);
    }

    public DataResponse(Integer code,String msg){
        this(code,msg,null);
    }

    public DataResponse() {
        result=new HashMap<>();
    }

    public DataResponse put(String key,Object value){
        result.put(key,value);
        return this;
    }

    public static DataResponse ok(){
        return new DataResponse(200,"成功!");
    }

    public static DataResponse ok(String msg){
        return new DataResponse(200,msg);
    }

    public static DataResponse ok(int code,String msg){
        return new DataResponse(code,msg);
    }
    public static DataResponse ok(String msg,Object data){
        return new DataResponse(200,msg,data);
    }
    public static DataResponse ok(int code,String msg,Object data){
        return new DataResponse(200,msg,data);
    }

    public static DataResponse error(){
        return new DataResponse(500,"服务器错误,操作失败!");
    }

    public static DataResponse error(String msg){
        return new DataResponse(500,msg);
    }

    public static DataResponse error(int code,String msg){
        return new DataResponse(code,msg);
    }

    public Object get(String key){
        return result.get(key);
    }

    public Object getData(){
        return result.get("data");
    }

    public void setCode(int code) {
        result.put("code",code);
    }

    public void setMsg(String msg) {
        result.put("msg",msg);
    }

    public void setData(Object data) {
        result.put("data",data);
    }

}
原文地址:https://www.cnblogs.com/junlinsky/p/14183502.html