基于PIO把带有数据和图片的excel表导入到数据库中(图片存储到服务器中,可访问图片路径存入在数据库中)

基于PIO把带有数据和图片的excel表导入到数据库中(图片存储到服务器中,可访问图片路径存入在数据库中)



前言

创作来之不易可点一颗小心心

一、工具类getExcelMap说明?

以下工具类都是基于PIO原生态实现的,其中包含了.xls和.xlsx的导入,也涉及到了在excel解析图片。

二、使用步骤

1.引入库

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

2.方法实现:importFile

    public void importFile(MultipartFile file) {

        Map<String, String> fieldMap=new HashMap<>();
        fieldMap.put("id", "id");
        fieldMap.put("姓名", "name");
        fieldMap.put("年龄", "age");
        fieldMap.put("性别", "sex");
        fieldMap.put("电话", "phone");
        fieldMap.put("人物肖像", "photo");
        fieldMap.put("身份证信息", "message");

        //图片存储路径
        String filePath="D://cs/picture/web/";
        //图片访问地址
        String webPath="http://localhost:8080/cccc/pic/";
        List<Map<String,Object>> list=  getExcelMap(file,fieldMap, filePath,webPath);
    }

3.读excel中的数据和图片

excel截图:在这里插入图片描述

代码如下:

/**
* fieldMap:字段信息
* filePath 为图片的存储路径:/aaa/bbb/。
* webPath 为图片的访问路径:http://localhost:8080/aaa/bbb/
* 
*/
public List<Map<String,Object>> getExcelMap(MultipartFile multipartFile,Map<String, String> fieldMap,String filePath,String webPath ) {
        List<Map<String,Object>> list=new ArrayList<>();
        //如果excel表中有日期的话,则把日期规范化
        DateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try (InputStream inputStream = multipartFile.getInputStream()) {
            //读取excel
            Workbook workbook;
            Map<String, PictureData> sheetPictures=null;
            Sheet sheet=null;
            if (multipartFile.getOriginalFilename().endsWith(".xls")) {
                workbook = new HSSFWorkbook(inputStream);
                sheet= workbook.getSheetAt(0);
                //获取图片
                sheetPictures = ExcelUtil.getPictures((HSSFSheet)sheet);
            } else {
                workbook = new XSSFWorkbook(inputStream);
                sheet= workbook.getSheetAt(0);
                //获取图片
                sheetPictures = ExcelUtil.getPictures((XSSFSheet) sheet);
            }
            Map<String,String> printImgMap=null;
            //把图片存入服务器中,返回图片存储路径 printImgMap
            if (sheetPictures.size()!=0){
                printImgMap= ExcelUtil.printImg( sheetPictures,filePath,webPath);
            }

            //获取的firstRowNum其实是=0的,firstCellNum 也是=0
            int firstRowNum = sheet.getFirstRowNum();
            Row firstRow = sheet.getRow(firstRowNum);
            int lastRowNum = sheet.getLastRowNum();
            int firstCellNum = firstRow.getFirstCellNum();
            int lastCellNum = firstRow.getLastCellNum();
            //firstRowNum + 1是因为单元格都是坐标(0,0)开始算的。excel表中的第一行是表头,所以不需要获取,就直接从第二行数据行开始
            for (int i = firstRowNum + 1; i <= lastRowNum; i++) {
                Row row = sheet.getRow(i);
               //空表格就不需要进循环了,根据第一列名称的有无来判断是否是空白行
               /**
                * formatter.formatCellValue(row.getCell(0))这个方法就相当于:
                * Cell cell = row.getCell(0);
               	* cell.setCellType(CellType.STRING);
                * value = cell.getStringCellValue();
               	*/
                DataFormatter formatter = new DataFormatter();
                if (StringUtil.isBlank(formatter.formatCellValue(row.getCell(0)))){
                    break;
                }
                String value = "";
                Map<String,Object> map=new LinkedHashMap<>();
                log.info("lastCellNum------>{}",lastCellNum);
                for (int j = firstCellNum; j < lastCellNum; j++) {
                    value = "";
                    Cell cell = row.getCell(j);
					//null != cell避免遇到空指针。使用StringUtil.isNotBlank(cell)的话会报错,原因是如果单元格没有内容的话会报空指针异常。
                    if(null != cell) {
                        log.info("第【{}】行,第【{}】列数据:{}", i, j, cell);
                        //单元格为整数、小数、日期
                        if (cell.getCellType().equals(CellType.NUMERIC)) {
                            if (DateUtil.isCellDateFormatted(cell)) {
                                Date d = cell.getDateCellValue();
                                value = formater.format(d);
                            } else {
                                cell.setCellType(CellType.STRING);
                                value = cell.getStringCellValue();
                            }
                         //单元格中有图片存在
                        }else if(StringUtil.isNotBlank(printImgMap.get(i + "_" +j))){
                            value=printImgMap.get(i+"_"+j);
                        } else {
                            cell.setCellType(CellType.STRING);
                            value = cell.getStringCellValue();
                        }
                    }
					//遍历列,获得第一行对应的表头所在列的单元格中的字段中文名称。然后根据字段中文名获取到字段英文名。为key值。
                    Cell headCell = firstRow.getCell(j);
                    log.info("headCell[{}]:{}", j, headCell);
                    String fieldNameCn = headCell.getStringCellValue();
                    log.info("fieldNameCn:{}", fieldNameCn);
                    String fieldNameEn = fieldMap.get(fieldNameCn);
                    log.info("fieldNameEn:{}", fieldNameEn);
                    map.put(fieldNameEn,value);
                    log.info("map:{}",map);
                }
                list.add(map);
            }
        } catch (IOException e) {
            log.error("拼接sql发生异常 [{}]", e);
        }
        return list;
    }

4.ExcelUtil:获取图片和存图片

public class ExcelUtil{

 /**  支持单个图片
     * 获取Excel2003图片
     * @param sheet 当前sheet对象
     * @return Map key:图片单元格索引(0_11)String,value:图片流PictureData
     * @throws IOException
     */
    public static Map<String, PictureData> getPictures(HSSFSheet sheet) {
        Map<String, PictureData> map = new HashMap<>();
        List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
        for (HSSFShape shape : list) {
            if (shape instanceof HSSFPicture) {
                HSSFPicture picture = (HSSFPicture) shape;
                HSSFClientAnchor cAnchor = (HSSFClientAnchor) picture.getAnchor();
                PictureData pData = picture.getPictureData();
                String key = cAnchor.getRow1() + "_" + cAnchor.getCol1();
                map.put(key, pData);
            }
        }
        return map;
    }

    /**
     * 获取图片和位置 (xlsx)
     * @param sheet
     * @return Map key:图片单元格索引(0_1)String,value:图片流PictureData
     * @throws IOException
     */
    public static Map<String, PictureData> getPictures (XSSFSheet sheet) throws IOException {
        Map<String, PictureData> map = new HashMap<>();
        for (POIXMLDocumentPart dr : sheet.getRelations()) {
            if (dr instanceof XSSFDrawing) {
                XSSFDrawing drawing = (XSSFDrawing) dr;
                List<XSSFShape> shapes = drawing.getShapes();
                for (XSSFShape shape : shapes) {
                    XSSFPicture pic = (XSSFPicture) shape;
                    XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
                    CTMarker ctMarker = anchor.getFrom();
                    String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol();
                    map.put(picIndex, pic.getPictureData());
                }
            }
        }
        return map;
    }


 /**
     * 图片写出 
     * @param mapList为图片对象
     * @param webPath 为图片的访问路径:http://localhost:8080/aaa/bbb/
     * @param filePath 为图片的存储路径:/aaa/bbb/。
     * @throws IOException
     */

    //图片写出
    public static Map printImg(Map<String, PictureData> mapList,String filePath,String webPath) throws IOException {
        Map<String, String> map = new HashMap<>();
        mapList.forEach((key, pic) -> {
            // 文件扩展名
            String ext = pic.suggestFileExtension();
            // 图片数据
            byte[] data = pic.getData();
            //图片保存路径 医院名称+微信公众号/医院照片+图片后缀
            String ImgName= UUID.randomUUID().toString()+"." + ext;
            //写入到对应的文件夹路径下面去
            //filePath+imgName=/aaa/bbb/xxxxx.jpg
            try (FileOutputStream out = new FileOutputStream(filePath+imgName)) {
            out.write(bytes);
        	} catch (Exception e) {
            e.printStackTrace();
        	}
        	//map中的value为:http://localhost:8080/aaa/bbb/xxxxx.jpg
            map.put(key, webPath+ImgPath);
            });
            return map;
        }

    }


}

5.导入报错

有一天,导入未带图片的.xlsx表单,报以下错误:
XSSFSimpleShape cannot be cast to org.apache.poi.xssf.usermodel.XSSFPicture

1.原因是:低版本改成了高版本Excel,解析有问题
  解决办法:将【xlsx】另存为【xls】
 
2.报错显示的是类型转换错误,我明明是用XSSFShape类型转换的,XSSFShapeGroup是那来的?在网上查到XSSFShapeGroup是获取组合形状的。
  解决办法:在excel表里面找到组合形状的图形,取消组合

3.原因是:默认导入包含矩形形状表格时出错,代码在获取所有图片的时候把所有Shape强转成XSSFPicture,实际上是XSSFSimpleShape,强制失败
在ExcelUtil:获取图片和存图片的代码14行出现问题。
  解决办法:
  List<XSSFShape> shapes = drawing.getShapes();
  替换成
  	 List<XSSFShape> shapes = drawing.getShapes()
                        .stream().filter(s->s instanceof XSSFPicture).collect(Collectors.toList());

总结

由于List<Map<String,Object>> getExcelMap最后的返回list存入数据库去的方式是使用jdbc原生态insert语句拼接而成的,过程很复杂,但其核心取excel中的数据和图片已实现

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值