poi上传Excel文件批量添加数据

Excel文件上传批量添加数据

poi使用Excel模板下载数据 : https://blog.csdn.net/kangshifu007/article/details/103174664

步骤 : 

1.添加上传需要的依赖

2.在对应的实体类中添加构造方法(与普通构造稍有不同)

3.在controller层编写解析上传Excel文件的代码

4.在service层调用之前编写代码(我这里是调用的之前编写过的save方法 , 因为save中有复杂的逻辑,如果没有重新编写保存的逻辑代码)

注 : ContractProduct  只是一个实体类

上传文件3要素 : 

1.form表单提交方式为  method="post"

2.表单属性 : enctype="multipart/form-data"

3.标签类型为file : 

1.在pom文件添加必要的依赖

        
        
            org.apache.poi
            poi
            4.0.1
        
        
            org.apache.poi
            poi-ooxml
            4.0.1
        
        
            org.apache.poi
            poi-ooxml-schemas
            4.0.1
        

        
            com.google.code.gson
            gson
            2.8.5
        

        
        
            commons-fileupload
            commons-fileupload
            1.3.1
        

2.在对应的实体类中添加构造方法(与普通构造稍有不同)

说明 : 代码中使用实体类是  ContractProduct  , 实体类中的代码仅供理解 , 只是为了说明实体类中的此构造方法的写法 , 需要根据具体情况修改

public class ContractProduct implements Serializable {

    //实体类属性
    private String id;
    private String productNo;	
    private String productImage;
    private String productDesc;	
    private String loadingRate;	
    private Integer boxNum;		
    private String packingUnit;	
    private Integer cnumber;	
    private Integer outNumber;	
    private Integer finished;	
    private String productRequest
    private Double price;		
    private Double amount;		
    private Integer orderNo;	
    private String contractId;   
    private String factoryName;	
    private String factoryId;


    //构造方法
    //与普通改造不同之处是:Object []objs  不是实体类的属性 , 是传入的一个参数
      public ContractProduct(Object []objs, String companyId, String companyName,String contractId) {

        //objs是一个存放下面属性值的一个数组 , 通过遍历数组方式把Excel中读取的数据逐个赋值给对象属性 , 逐个遍历赋值的前提是Excel中数据顺序要和属性相对应
		this.factoryName = objs[1].toString();
		this.productNo = objs[2].toString();
		this.cnumber = ((Double) objs[3]).intValue();
		this.packingUnit = objs[4].toString();
		this.loadingRate = objs[5].toString();
		this.boxNum = ((Double) objs[6]).intValue();
		this.price = (Double) objs[7];			//单价
		this.productRequest=objs[8].toString();
		this.productDesc=objs[9].toString();
		this.companyId = companyId;
		this.companyName = companyName;
		this.contractId = contractId;
	}

}

3.在controller层编写解析上传Excel文件的代码

说明 1 : 只有两个核心方法  , 第一个方法  inportExcel  根据实际导入的 Excel 文件需要做具体的修改, 代码中第一个for循环索引是1 , 是从文件第二行开始读取的 , 第一行一般是标题 , 如果需要读取第一行那么就修改索引为0

 说明 2 : getCellValue不需要做修改, 这里代码只判断了三种数据类型 , string , 数字(包含日期) , boolean , 一般为三个 , 如果不够可以在switch中添加判断类型

说明 3 (坑):   获取行数: 获取的是行数的最大索引                   获取列数:获取的是最大的列数 ,而不是索引

 

    @RequestMapping("/import")
    public String importExcel(String contractId, MultipartFile file) throws IOException {

        //1.解析excel获得货物的数据
        List list = new ArrayList<>();
        //1.1 工作薄  file =>流
        Workbook workbook = new XSSFWorkbook(file.getInputStream());
        //1.2 得到表
        Sheet sheet = workbook.getSheetAt(0);
        //1.3 得到行
        int lastRowNum = sheet.getLastRowNum();
        Row row = null;
        Cell cell = null;
        for (int i = 1; i <= lastRowNum; i++) {
            //获得行
            row = sheet.getRow(i);
            //1.4 得到单元格
            short lastCellNum = row.getLastCellNum();

            //ContractProduct contractProduct = new ContractProduct();
            Object[] param = new Object[lastCellNum]; //一个数组就是一个对象
            for (int j = 1; j < lastCellNum; j++) {//获得每一个单元格的数据
                //每一个单元格
                cell = row.getCell(j);
                Object cellValue = getCellValue(cell);//获得每一个单元格的值 将每一个值 放入到对象中的对应属性上
                //将数据先存入数组中
                param[j] = cellValue;//  [ null , 值,值,值,值,值,值]
            }
            //封装对象 , 可在第二步中查看具体的封装过程
            ContractProduct contractProduct = new ContractProduct(param, super.companyId, super.companyName, contractId);
            //1.5 获得数据 组装对象
            list.add(contractProduct);
        }
              
        
        //把读取的数据传入service层中 , 需要控制事务
        contractProductService.saveList(list);

        request.setAttribute("contractId", contractId);
        return "redirect:/cargo/contract/list.do";
    }
    
    /*
     * 传入的单元格的数据不同 , 获得不同的数据
     * */
    private static Object getCellValue(Cell cell) {
        Object o = null;
        //获得单元格的类型
        CellType cellType = cell.getCellType();
        switch (cellType) {
            case STRING:
                o = cell.getStringCellValue();//字符串数据
                break;
            case NUMERIC: //数字类型  , 在excel中日期类型是数字类型
                //判断是日期类型 还是数字类型
                if (DateUtil.isCellDateFormatted(cell)) { //是不是日期类型
                    //是日期类型
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                    o = simpleDateFormat.format(cell.getDateCellValue());
                } else {
                    //数字类型
                    o = cell.getNumericCellValue();
                }
                break;
            case BOOLEAN:
                o = cell.getBooleanCellValue();//获得布尔类型数据
                break;
            default:
                break;
        }
        return o;
    }

.4.在service层调用之前编写代码(我这里是调用的之前编写过的save方法 , 因为save中有复杂的逻辑,如果没有重新编写保存的逻辑代码)

说明 : 遍历集合 , 使用循环调用添加方法就可实现批量添加

 //添加方法
    @Override
    public void save(ContractProduct contractProduct) {
        //单个添加的代码
        ......具有一定逻辑的添加代码......

    }



     //通过上传Excel文件批量添加的代码
    @Override
    public void saveList(List list) {
        for (ContractProduct contractProduct : list) {    
             //不能这么直接添加 , 添加一个数据可能要次改其他表数据 , 需要一定逻辑 ,  如果没有逻辑可以这么写
            //contractProductDao.insertSelective(contractProduct);  

            //直接调用之前单个添加方法的代码即可 , 可能添加过程需要逻辑 , 没有必要把逻辑重写一遍
            save(contractProduct);
        }
    }

 

 

 

你可能感兴趣的:(poi上传Excel文件批量添加数据)