zoukankan      html  css  js  c++  java
  • Apache POI

    Apache POI

    晚来天欲雪,能饮一杯无?

    一、POI介绍

    Apache POI是用Java编写的免费开源的跨平台的Java API,Apache POI提供API给Java程 序对Microsoft Office格式档案读和写的功能,其中使用最多的就是使用POI操作Excel文 件。
    jxl:专门操作Excel
    maven坐标:
    enter description here

    POI结构:
    enter description here

    二、入门案例

    1. 从Excel文件读取数据

    使用POI可以从一个已经存在的Excel文件中读取数据。

    //使用POI读取Excel文件中的数据
    @Test
    public void test1() throws Exception{
        //加载指定文件,创建一个Excel对象(工作簿)
        XSSFWorkbook excel = new XSSFWorkbook(new FileInputStream(new File("C:\io\score.xlsx")));
        //读取Excel文件中第一个Sheet标签页
        XSSFSheet sheet = excel.getSheetAt(0);
        //遍历Sheet标签页,获得每一行数据
        for (Row row : sheet) {
            //遍历行,获得每个单元格对象
            for (Cell cell : row) {
                System.out.println(cell.getStringCellValue());
            }
        }
        //关闭资源
        excel.close();
    }
    

    定义目录结构如下:
    enter description here
    通过上面的入门案例可以看到,POI操作Excel表格封装了几个核心对象:

    enter description here
    enter description here

    上面案例是通过遍历工作表获得行,遍历行获得单元格,最终获取单元格中的值。
    还有一种方式就是获取工作表最后一个行号,从而根据行号获得行对象,通过行获取最 后一个单元格索引,从而根据单元格索引获取每行的一个单元格对象,代码如下:

    //使用POI读取Excel文件中的数据
    @Test
    public void test2() throws Exception{
        //加载指定文件,创建一个Excel对象(工作簿)
        XSSFWorkbook excel = new XSSFWorkbook(new FileInputStream(new File("c:\io\score.xlsx")));
        //读取Excel文件中第一个Sheet标签页
        XSSFSheet sheet = excel.getSheetAt(0);
        //获得当前工作表中最后一个行号,需要注意:行号从0开始
        int lastRowNum = sheet.getLastRowNum();
        System.out.println("lastRowNum = " + lastRowNum);
        for(int i=0;i<=lastRowNum;i++){
            XSSFRow row = sheet.getRow(i);//根据行号获取每一行
            //获得当前行最后一个单元格索引
            short lastCellNum = row.getLastCellNum();
            System.out.println("lastCellNum = " + lastCellNum);
            for(int j=0;j<lastCellNum;j++){
                XSSFCell cell = row.getCell(j);//根据单元格索引获得单元格对象
                System.out.println(cell.getStringCellValue());
            }
        }
        //关闭资源
        excel.close();
    }
    

    2. 向Excel文件写入数据

    使用POI可以在内存中创建一个Excel文件并将数据写入到这个文件,最后通过输出流将 内存中的Excel文件下载到磁盘。

    //使用POI向Excel文件写入数据,并且通过输出流将创建的Excel文件保存到本地磁盘
    @Test
    public void test3() throws Exception{
        //在内存中创建一个Excel文件(工作簿)
        XSSFWorkbook excel = new XSSFWorkbook();
        //创建一个工作表对象
        XSSFSheet sheet = excel.createSheet("oracle");
        //在工作表中创建行对象
        XSSFRow title = sheet.createRow(0);
        //在行中创建单元格对象
        title.createCell(0).setCellValue("姓名");
        title.createCell(1).setCellValue("地址");
        title.createCell(2).setCellValue("年龄");
    
        XSSFRow dataRow = sheet.createRow(1);
        dataRow.createCell(0).setCellValue("小明");
        dataRow.createCell(1).setCellValue("北京");
        dataRow.createCell(2).setCellValue("20");
    
        //创建一个输出流,通过输出流将内存中的Excel文件写到磁盘
        FileOutputStream out = new FileOutputStream(new File("c:\io\hello.xlsx"));
        excel.write(out);
        out.flush();
        excel.close();
    }
    

    三、批量导入预约设置信息

    预约设置信息对应的数据表为t_ordersetting,预约设置操作对应的页面为 ordersetting.html。
    t_ordersetting表结构:
    enter description here
    orderDate:预约日期
    number:可预约人数
    reservations:已预约人数
    批量导入预约设置信息操作过程:
    1、点击模板下载按钮下载Excel模板文件
    2、将预约设置信息录入到模板文件中
    3、点击上传文件按钮将录入完信息的模板文件上传到服务器
    4、通过POI读取上传文件的数据并保存到数据库

    1. 完善页面

    1-1. 提供模板文件

    资料中已经提供了Excel模板文件ordersetting_template.xlsx,将文件放在 health_backend工程的template目录。
    enter description here

    1-2. 实现模板文件下载

    为模板下载按钮绑定事件实现模板文件下载。
    enter description here
    enter description here

    1-3. 文件上传

    使用ElementUI的上传组件实现文件上传并绑定相关事件。
    enter description here
    enter description here
    enter description here

    2. 后台代码

    2-1. controller

    将POIUtils工具类复制到health_common工程

    package cn.jiyun.utils;
    
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.List;
    import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.Row;
    import org.apache.poi.ss.usermodel.Sheet;
    import org.apache.poi.ss.usermodel.Workbook;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import org.springframework.web.multipart.MultipartFile;
    
    public class POIUtils {
        private final static String xls = "xls";
        private final static String xlsx = "xlsx";
        private final static String DATE_FORMAT = "yyyy/MM/dd";
        /**
         * 读入excel文件,解析后返回
         * @param file
         * @throws IOException
         */
        public static List<String[]> readExcel(MultipartFile file) throws IOException {
            //检查文件
            checkFile(file);
            //获得Workbook工作薄对象
            Workbook workbook = getWorkBook(file);
            //创建返回对象,把每行中的值作为一个数组,所有行作为一个集合返回
            List<String[]> list = new ArrayList<String[]>();
            if(workbook != null){
                for(int sheetNum = 0;sheetNum < workbook.getNumberOfSheets();sheetNum++){
                    //获得当前sheet工作表
                    Sheet sheet = workbook.getSheetAt(sheetNum);
                    if(sheet == null){
                        continue;
                    }
                    //获得当前sheet的开始行
                    int firstRowNum  = sheet.getFirstRowNum();
                    //获得当前sheet的结束行
                    int lastRowNum = sheet.getLastRowNum();
                    //循环除了第一行的所有行
                    for(int rowNum = firstRowNum+1;rowNum <= lastRowNum;rowNum++){
                        //获得当前行
                        Row row = sheet.getRow(rowNum);
                        if(row == null){
                            continue;
                        }
                        //获得当前行的开始列
                        int firstCellNum = row.getFirstCellNum();
                        //获得当前行的列数
                        int lastCellNum = row.getPhysicalNumberOfCells();
                        String[] cells = new String[row.getPhysicalNumberOfCells()];
                        //循环当前行
                        for(int cellNum = firstCellNum; cellNum < lastCellNum;cellNum++){
                            Cell cell = row.getCell(cellNum);
                            cells[cellNum] = getCellValue(cell);
                        }
                        list.add(cells);
                    }
                }
                workbook.close();
            }
            return list;
        }
    
        //校验文件是否合法
        public static void checkFile(MultipartFile file) throws IOException{
            //判断文件是否存在
            if(null == file){
                throw new FileNotFoundException("文件不存在!");
            }
            //获得文件名
            String fileName = file.getOriginalFilename();
            //判断文件是否是excel文件
            if(!fileName.endsWith(xls) && !fileName.endsWith(xlsx)){
                throw new IOException(fileName + "不是excel文件");
            }
        }
        public static Workbook getWorkBook(MultipartFile file) {
            //获得文件名
            String fileName = file.getOriginalFilename();
            //创建Workbook工作薄对象,表示整个excel
            Workbook workbook = null;
            try {
                //获取excel文件的io流
                InputStream is = file.getInputStream();
                //根据文件后缀名不同(xls和xlsx)获得不同的Workbook实现类对象
                if(fileName.endsWith(xls)){
                    //2003
                    workbook = new HSSFWorkbook(is);
                }else if(fileName.endsWith(xlsx)){
                    //2007
                    workbook = new XSSFWorkbook(is);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return workbook;
        }
        public static String getCellValue(Cell cell){
            String cellValue = "";
            if(cell == null){
                return cellValue;
            }
            //如果当前单元格内容为日期类型,需要特殊处理
            String dataFormatString = cell.getCellStyle().getDataFormatString();
            if(dataFormatString.equals("m/d/yy")){
                cellValue = new SimpleDateFormat(DATE_FORMAT).format(cell.getDateCellValue());
                return cellValue;
            }
            //把数字当成String来读,避免出现1读成1.0的情况
            if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){
                cell.setCellType(Cell.CELL_TYPE_STRING);
            }
            //判断数据的类型
            switch (cell.getCellType()){
                case Cell.CELL_TYPE_NUMERIC: //数字
                    cellValue = String.valueOf(cell.getNumericCellValue());
                    break;
                case Cell.CELL_TYPE_STRING: //字符串
                    cellValue = String.valueOf(cell.getStringCellValue());
                    break;
                case Cell.CELL_TYPE_BOOLEAN: //Boolean
                    cellValue = String.valueOf(cell.getBooleanCellValue());
                    break;
                case Cell.CELL_TYPE_FORMULA: //公式
                    cellValue = String.valueOf(cell.getCellFormula());
                    break;
                case Cell.CELL_TYPE_BLANK: //空值
                    cellValue = "";
                    break;
                case Cell.CELL_TYPE_ERROR: //故障
                    cellValue = "非法字符";
                    break;
                default:
                    cellValue = "未知类型";
                    break;
            }
            return cellValue;
        }
    }
    

    在health_backend工程创建OrderSettingController并提供upload方法

    /**
     * 预约设置
     */
    @RestController
    @RequestMapping("/ordersetting")
    public class OrderSettingController {
        @Reference
        private OrderSettingService orderSettingService;
        //文件上传,实现预约设置数据批量导入
        @RequestMapping("/upload")
        public Result upload(@RequestParam("excelFile") MultipartFile excelFile){
            try {
                List<String[]> list = POIUtils.readExcel(excelFile);//使用POI解析表格数据
                List<OrderSetting> data = new ArrayList<>();
                for (String[] strings : list) {
                    String orderDate = strings[0];
                    String number = strings[1];
                    OrderSetting orderSetting = new OrderSetting(new Date(orderDate),Integer.parseInt(number));
                    data.add(orderSetting);
                }
                //通过dubbo远程调用服务实现数据批量导入到数据库
                orderSettingService.add(data);
                return new Result(true, MessageConstant.IMPORT_ORDERSETTING_SUCCESS);
            } catch (IOException e) {
                e.printStackTrace();
                //文件解析失败
                return new Result(false, MessageConstant.IMPORT_ORDERSETTING_FAIL);
            }
        }
    }
    

    定义后的目录结构:
    enter description here

    2-2. 服务接口

    创建OrderSettingService服务接口并提供新增方法。

    public interface OrderSettingService {
        void add(List<OrderSetting> data);
    }
    

    定义后的目录结构:
    enter description here

    2-3. 服务实现类

    创建服务实现类OrderSettingServiceImpl并实现新增方法。

    /**
     * 预约设置服务
     */
    @Service(interfaceClass = OrderSettingService.class)
    @Transactional
    public class OrderSettingServiceImpl implements OrderSettingService{
    
        @Autowired
        private OrderSettingDao orderSettingDao;
    
        //批量导入预约设置数据
        @Override
        public void add(List<OrderSetting> list) {
            if(list != null && list.size() > 0){
                for (OrderSetting orderSetting : list) {
                    //判断当前日期是否已经进行了预约设置
                    long countByOrderDate = orderSettingDao.findCountByOrderDate(orderSetting.getOrderDate());
                    if(countByOrderDate > 0){
                        //已经进行了预约设置,执行更新操作
                        orderSettingDao.editNumberByOrderDate(orderSetting);
                    }else{
                        //没有进行预约设置,执行插入操作
                        orderSettingDao.add(orderSetting);
                    }
                }
            }
        }
    }
    

    定义目录结构如下:
    enter description here

    2-4. Dao接口

    创建Dao接口OrderSettingDao并提供更新和新增方法。

    public interface OrderSettingDao {
        long findCountByOrderDate(Date orderDate);
    
        void editNumberByOrderDate(OrderSetting orderSetting);
    
        void add(OrderSetting orderSetting);
    }
    

    定义目录结构如下:enter description here

    2-5. Mapper映射文件

    创建Mapper映射文件OrderSettingDao.xml并提供相关SQL

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.bianyi.dao.OrderSettingDao">
        <insert id="add" parameterType="com.bianyi.pojo.OrderSetting">
            insert into t_ordersetting
              (orderDate,number,reservations)
                          values
              (#{orderDate},#{number},#{reservations})
        </insert>
    
        <update id="editNumberByOrderDate" parameterType="com.bianyi.pojo.OrderSetting">
            update t_ordersetting
              set number = #{number}
              where orderDate = #{orderDate}
        </update>
    
        <select id="findCountByOrderDate" parameterType="date" resultType="long">
            select count(id) from t_ordersetting where orderDate = #{orderDate}
        </select>
    </mapper>
    

    定义后的目录结构:enter description here

    我等的船还不来
  • 相关阅读:
    远程安装WinXP OEM版系统的痛苦经历
    许可证服务因许可证不够出现占用CPU的故障
    AvayaP133G2和3Com 3300交换机间的Vlan连接
    从win2000升级到win2003后ISA2000缓存的问题
    大型局域网中用ISA隔离部分计算机
    ORACLE学习第二天
    ORACLE ROWID解析
    ORA32773问题解决
    ORACLE学习第三天
    ORACLE表空间迁移
  • 原文地址:https://www.cnblogs.com/lxs1204/p/14190045.html
Copyright © 2011-2022 走看看