zoukankan      html  css  js  c++  java
  • 利用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);
        }
    
    }
    
  • 相关阅读:
    python爬取网页
    python异常处理
    本周总结
    改变promise状态有三种resolve、reject、throw
    详解Promise.race()可以解决多个异步请求那个请求先返回
    Promise.all()方方详解
    你不知道的Promise构造函数Promise(excutor)
    你不知道的Promise状态变化机制
    Promise练习文件读取
    关于async函数的错误处理
  • 原文地址:https://www.cnblogs.com/junlinsky/p/14183502.html
Copyright © 2011-2022 走看看