操作Excle表格 上传--下载--打包数据--创建url路径,解析excle数据 java一条龙服务

本人经过十次打磨,发明excle操作表格 ,简单容易入手,速度效率快 !!!!!本文用的是阿里巴巴的poi! 

1.导入pom依赖--第一步

  <!-- EasyExcel start -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.2.1</version>
        </dependency>
        <!-- EasyPoi start -->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-web</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-annotation</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!-- EasyPoi end -->
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>fop-transcoder-allinone</artifactId>
            <version>2.4</version>
        </dependency>

2.下载excle

场景介绍:系统需要用户导入数据 常常限制excle的规范 ,所以需要下载模板进行数据导入,整体实现通过HttpServletResponse response 下载文件  把需要下载的文件放在resources目录下 --springboot会自动识别文件

--- 代码如下--

  //    @ApiOperation(value = "简单测试:下载“分类导入模板文件”", notes = "简单测试:下载“分类导入模板文件”")
    @GetMapping("/simple/downloadTemplate")
    public void simpleDownloadTemplate(HttpServletResponse response) throws IOException {
  //定义resources文件下的路径        
String fileName = "分类导入模板.xlsx";
        Resource r = new ClassPathResource(fileName);
        try (
                FileInputStream fileInputStream = new FileInputStream(r.getFile());
                ServletOutputStream outputStream = response.getOutputStream();

        ) {
            response.setContentType("application/force-download");
            try {

//                fileName = new String(fileName.getBytes("utf-8"), "utf-8");
                fileName = URLEncoder.encode(fileName, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            response.setHeader("Content-Disposition", "attachment;filename=" + UUID.randomUUID() + "_" + fileName);
            //设置下载文件uuid+的名称

            IOUtils.copy(fileInputStream, outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2.1效果如下

3.上传文件Excle

场景介绍:用户下载完文件  然后进行数据上传 --通常需要你去解析数据然后存入数据库中 在确定返回 值 是不是成功 

所以有二个问题:1.存储数据,2.存放excle表格到系统里面 

3.1添加工具类-- fileUtil 

可以自己研究或修改 

convertMultipartFileToFile 这个方法主要是判断文件是否为 xlsx 文件 如果 不是 就报错,是的就存入本地
package com.example.annualmeetingactivitiesmaster.demos.utils;


import org.apache.commons.io.FileUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.UUID;

public class FileUtil {

    /**
     * 转换MultipartFile对象为java.io.File类型
     *
     * @param multipartFile
     * @return
     */
    public static File convertMultipartFileToFile(MultipartFile multipartFile) {
        File result = null;
        try {
            /**
             * UUID.randomUUID().toString()是javaJDK提供的一个自动生成主键的方法。
             * UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,
             * 它保证对在同一时空中的所有机器都是唯一的,是由一个十六位的数字组成,表现出来的形式。
             * 由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,
             * 过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,
             * 全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),
             * UUID的唯一缺陷在于生成的结果串会比较长。
             *
             *
             * File.createTempFile和File.createNewFile()的区别:
             *  后者只是创建文件,而前者可以给文件名加前缀和后缀
             */
            //这里对生成的文件名加了UUID随机生成的前缀,后缀是null
            result = File.createTempFile(UUID.randomUUID().toString(), null);
            multipartFile.transferTo(result);
            result.deleteOnExit();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 根据url获取文件对象
     *
     * @param fileUrl
     * @return
     */
    public static File downloadFile(String fileUrl) {
        File result = null;
        try {
            result = File.createTempFile(UUID.randomUUID().toString(), null);
            URL url = new URL(fileUrl);
            URLConnection connection = url.openConnection();
            connection.setConnectTimeout(3000);
            BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(result));
            byte[] car = new byte[1024];
            int l = 0;
            while ((l = bis.read(car)) != -1) {
                bos.write(car, 0, l);
            }
            bis.close();
            bos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * @param request
     * @return
     */
    public static String getRealPath(HttpServletRequest request) {
        ServletContext sc = request.getSession().getServletContext();
        String uploadDir = sc.getRealPath("/upload");
        return uploadDir;
    }

    public static boolean saveFile(String savePath, String fileFullName, MultipartFile file) throws IOException {
        File uploadFile = new File(savePath + fileFullName);
        FileUtils.writeByteArrayToFile(new File(savePath, fileFullName), file.getBytes());
        return uploadFile.exists();
    }

    public static String mergeFile(int chunksNumber, String ext, String uploadFolderPath,
                                   HttpServletRequest request) {
        //合并分片流
        String mergePath = uploadFolderPath;
        String destPath = getRealPath(request);// 文件路径
        String newName = System.currentTimeMillis() + ext;// 文件新名称
        SequenceInputStream s;
        InputStream s1;
        try {
            s1 = new FileInputStream(mergePath + 0 + ext);
            String tempFilePath;
            InputStream s2 = new FileInputStream(mergePath + 1 + ext);
            s = new SequenceInputStream(s1, s2);
            for (int i = 2; i < chunksNumber; i++) {
                tempFilePath = mergePath + i + ext;
                InputStream s3 = new FileInputStream(tempFilePath);
                s = new SequenceInputStream(s, s3);
            }
            //分片文件存储到/upload/chunked目录下
            StringBuilder filePath = new StringBuilder();
            filePath.append(destPath).append(File.separator).append("chunked").append(File.separator);
            saveStreamToFile(s, filePath.toString(), newName);
            // 删除保存分块文件的文件夹
            deleteFolder(mergePath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return newName;
    }

    private static boolean deleteFolder(String mergePath) {
        File dir = new File(mergePath);
        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                try {
                    file.delete();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return dir.delete();
    }

    private static void saveStreamToFile(SequenceInputStream inputStream, String filePath, String newName)
            throws Exception {
        File fileDirectory = new File(filePath);
        synchronized (fileDirectory) {
            if (!fileDirectory.exists()) {
                if (!fileDirectory.mkdir()) {
                    throw new Exception("文件夹创建失败,路径为:" + fileDirectory);
                }
            }
            if (!fileDirectory.exists()) {
                if (!fileDirectory.mkdir()) {
                    throw new Exception("文件夹创建失败,路径为:" + fileDirectory);
                }
            }
        }
        OutputStream outputStream = new FileOutputStream(filePath + newName);
        byte[] buffer = new byte[1024];
        int len = 0;
        try {
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
                outputStream.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            outputStream.close();
            inputStream.close();
        }
    }
}

3.2 把xlsx存放系统路径 

开发路径和打成jar包后 路径是不一样的!!!!!

打成jar包后 无法识别 资源目录 也就是说无法在往jar包里面存放文件,需要把文件存在本地,也就是在外地添加文件夹。

resources文件 生成的路径匹配问题(开发环境使用存储方式)

Resource resource = new ClassPathResource("resources路径"); 生成的文件 存在打包好的 路径下, 用于开发环境。

打成jar包或者war包 上线环境 创建 appconfig.java

打jar包上传静态资源生成系统路径,获取项目所在的文件夹

@Component
public class AppConfig {

    /**
     * 获取项目所在的文件夹
     * @return
     */
    public String getResPhysicalPath(){
        ApplicationHome home = new ApplicationHome(getClass());
        File jarFile = home.getSource();
        //项目部署的目录
        if(jarFile != null){
            String path = jarFile.getParentFile().getPath();
            return path;
        }
        return null;
    }

}
转换MultipartFile转换File类型
file = FileUtil.convertMultipartFileToFile(uploadFile); //把MultipartFile转换File类型

3.3 进行上传文件确定文件格式,确定上传文件路径(开发环境)

 public String saveByExcelFileV1(@RequestParam("file") MultipartFile uploadFile, HttpServletRequest request) {
        File file = null; //判断文件格式
        String useridentity = null;
        //把MultipartFile转换File类型
        //判断文件类型是否正确  --不建议这样写 有漏洞
        String originalFilename = uploadFile.getOriginalFilename();
        String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
        //判断文件是不是xlsx文件 如果不是 就返回异常
        if (!".xlsx".equalsIgnoreCase(fileType)) {
            return "返回值"
        }
 file = FileUtil.convertMultipartFileToFile(uploadFile)//把MultipartFile转换File类型
      //如果是就存入我的文件夹里面
/**1.存在开发环境中
   Resource resource = new ClassPathResource("路径名"); //资源文件路径
            *log*.info("contextPath:{}", resource.getURL());
          String fileName = UUID.*randomUUID*().toString();  //获取文件随机名
         String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);  //获取文件后缀
           File fileDir = new File();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd/");
            String directory = simpleDateFormat.format(new Date()); //创建时间文件夹
//创建文件夹
            File dir = new File(resource.getFile()+"/"+directory);
            if (!dir.exists()) {
                dir.mkdirs();
            }
//
            File resultImg = new 
   File(resource.getFile()+"/"+directory,fileName+"."+"xlsx");
   log.info("图片上俩,新文件名:" + resultImg.getPath());
  //上传到文件夹中
  file.transferTo(resultImg);
**/


}

3.4 打包 上线环境 存放系统路径

 public ResponseResult saveByExcelFileV1(@RequestParam("file") MultipartFile uploadFile, HttpServletRequest request) {
        File file = null;
        String useridentity = null;
        //把MultipartFile转换File类型
        //判断文件类型是否正确  --不建议这样写 有漏洞
        String originalFilename = uploadFile.getOriginalFilename();
        String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
        if (!".xlsx".equalsIgnoreCase(fileType)) {
            return ResponseResult.fail(ResultCode.XlXSERRORR.getMsg());
        }
/**存入系统路径
//file 为 web层上传的 file文件
 dir = new File(      new AppConfig(). getResPhysicalPath()+"/系统环境的文件夹"+"/"+ directory);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        log.info("图片上传,保存位置:" +new AppConfig(). getResPhysicalPath()+"/系统环境的文件夹"+"/"+ directory);

        //3.给文件重新设置一个名字
        //后缀
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String newFileName = UUID.randomUUID().toString().replaceAll("-", "") + suffix;
        //4.创建这个新文件
        File newFile = new File(      new AppConfig(). getResPhysicalPath() +"/static/bookletsImges"+"/"+ directory + newFileName);
        log.info("图片上俩,新文件名:" + newFile.getPath());
        //5.复制操作 线程
        synchronized (this) {
            try {
                file.transferTo(newFile); //保存文件
                }
**/
}

4.导出数据 变成 Exel文件

确定2个方向: 1.数据是集合 2.变成Exel 的头和列

4.1 确认 实体类的列  下面是示例

package com.example.annualmeetingactivitiesmaster.demos.entity;

import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;



import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import javax.validation.constraints.NotNull;

import java.io.Serializable;


/**
* 
* @TableName xlsx_data
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName( value ="xlsx_data")
@ExcelIgnoreUnannotated //忽悠字段导入
public class XlsxData  implements Serializable {

    /**
    * id
    */
//    @ExcelProperty(index = 0, value ="唯一标识符")

    @TableId(type = IdType.AUTO)
    @Size(max= 255,message="编码长度不能超过255")
//    @NotNull(message="[id]不能为空")
//    @ApiModelProperty("id")
    private Integer xslxId;
    /**
    * 姓名
    */
    @ExcelProperty(index = 1, value ="姓名")
    @Size(max= 255,message="编码长度不能超过255")
//    @ApiModelProperty("姓名")
//    @Length(max= 255,message="编码长度不能超过255")
    private String xslxName;
    /**
    * 手机号
    */
//    @ApiModelProperty("手机号")
    @ExcelProperty(index = 2, value ="手机号")
    private String xslxChargenumber;
    /**
    * 公司
    */
    @ExcelProperty(index = 3, value ="公司")
    @Size(max= 255,message="编码长度不能超过255")
//    @ApiModelProperty("公司")
//    @Length(max= 255,message="编码长度不能超过255")
    private String xslxFirm;
    /**
    * 属于那位用户
    */
//    @ExcelProperty(index = 4, value ="测试")
//    @ApiModelProperty("属于那位用户")
    private Integer xslxUserid;
}

4.2确认数据 变成集合 转换成Exel

 @GetMapping(value = "/xlsx/data/download")
    public void exportData(HttpServletResponse response, HttpServletRequest request) throws IOException {
        String useridentity = null ; //存储用户id
        try {
            String token = request.getHeader("token");
            Claims obj = parseJWT(token); //使用的token解决方法 ,没有就删除
            useridentity = String.valueOf(obj.getSubject());
            log.info(useridentity + "用户id"); //解析出用户的id 进行存储 作为标识 确定导入的数据隶属与那个用户
        } catch (Exception e) {
            throw new RuntimeException(ResultCode.TOKEN_ERROR.getMsg());
        }
        String fileName = URLEncoder.encode("xlsx用户数据", "UTF-8");
        List<XlsxData> xlsxData = this.xlsxService.selectData(useridentity); //修改成自己查询出来的数据集合
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        log.info(xlsxData.toString() + "用户查询的数据");
        EasyExcel.write(response.getOutputStream(), XlsxData.class).sheet("模板").doWrite(xlsxData);
    }

4.3 下载即可 就会正常展示数据

5.上传文件 解析Excel 数据 比较复杂

确定方向 1.数据属于那一列 映射实体,解析数据时候确认出格式

5.1 展示代码 ,不懂可以问我 需要添加 线程锁,不然数据会出问题,把数据封装好,直接给web层即可。

  @Transactional(propagation = Propagation.REQUIRED)
    public List<XlsxData> showData(File file,String token) throws IOException {
        //添加线程锁
        synchronized (this) {
            List<XlsxData> list = new ArrayList<>();
            XSSFWorkbook hssfWorkbook = new XSSFWorkbook(Files.newInputStream(file.toPath()));   //获取工作簿下sheet的个数
            int sheetNum = hssfWorkbook.getNumberOfSheets();
            XSSFCell cell = null;
            System.out.println("该excel文件中总共有:" + sheetNum + "个sheet");
            if (sheetNum>2){
                list.add(null);
                return  list;
//                throw new RuntimeException("文件中sheet数量超过两个");
            }
            //遍历工作簿中的所有数据
            for (int i = 0; i < sheetNum; i++) {
                //读取第i个工作表
                System.out.println("读取第" + (i + 1) + "个sheet");

                XSSFSheet sheet = hssfWorkbook.getSheetAt(i);
                //获取最后一行的num,即总行数。此处从0开始
                int maxRow = sheet.getLastRowNum();
                for (int row = 0; row <= maxRow; row++) {
                    //获取最后单元格num,即总单元格数 ***注意:此处从1开始计数***
                    int maxRol = sheet.getRow(row).getLastCellNum();
                    System.out.println("--------第" + row + "行的数据如下--------");
                    for (int rol = 0; rol < maxRol; rol++) {
                        System.out.print(sheet.getRow(row).getCell(rol) + "  ");
                        cell = sheet.getRow(row).getCell(rol);
                    }
                    if (cell != null && cell.getCellType() != cell.CELL_TYPE_BLANK && row >= 2) {
                        XSSFCell cell3 = sheet.getRow(row).getCell(0);
                        System.out.println(cell3.toString() + "姓名");
                        XSSFCell cell1 = sheet.getRow(row).getCell(1);
                        System.out.println(cell1.toString() + "手机号");
                        XSSFCell cell2 = sheet.getRow(row).getCell(2);
                        System.out.println(cell2.toString() + "公司名字");
                        String xslxChargenumber = cell2.toString();
                        Pattern pattern = Pattern.compile("[0-9]*");
                        Matcher isNum = pattern.matcher(cell2.toString());
                        if (!isNum.matches()) { //判断手机号
                            xslxChargenumber = "0";
                        } else if (xslxChargenumber == null || xslxChargenumber.equals("")) {
                            xslxChargenumber = "0";
                        }
                        Integer integer = Integer.valueOf(xslxChargenumber);
                        //转换用户id
                        Integer userid = Integer.valueOf(token);
                        list.add(new XlsxData(null, cell3.toString(), xslxChargenumber ,cell2.toString(), userid));
                    }

                }
            }
            int i = xlsxDataMapper.insertBatchSomeColumn(list); //插入数据
            System.out.println(i);
            System.out.println(list);
            return list;
        }
    }

6.最后分享一个创建网络url的方法

           //协议 :// ip地址 :端口号 / 文件目录(/images/2020/03/15/xxx.jpg
            String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + '/' + "static/bookletsImges/" + directory + newFileName;
            log.info("图片上传,访问URL:" + url);
            map.put("url", url);

 谢谢大家,有问题可以私信与我

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值