springboot的poi导入和导出

2023年1月1日10:29:59

1.pom.xml

<!--poi.start -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>${org-apache-poi.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-excelant</artifactId>
			<version>${org-apache-poi.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.15</version>
		</dependency>
	<!--poi.end -->

2.读取工具类

package com.common.utils;

import lombok.Data;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 读取excel工具类
 */
public class ExcelReadUtils {

    private XSSFWorkbook workbook;
    private XSSFSheet sheet;

    /**
     * 工作表下标
     */
    private int sheetIndex = 0;

    public ExcelReadUtils(){}
    public ExcelReadUtils(File file) throws IOException {
        FileInputStream inputStream = new FileInputStream(file);
        this.workbook = new XSSFWorkbook(inputStream);
        inputStream.close();

        this.changeSheet();
    }
    public ExcelReadUtils(File file, int sheetIndex) throws IOException {
        FileInputStream inputStream = new FileInputStream(file);
        this.workbook = new XSSFWorkbook(inputStream);
        inputStream.close();

        this.sheetIndex = sheetIndex;
        this.changeSheet();
    }

    /**
     * 获取某行的单元格的值-字符串数组
     * @param rowIndex
     * @return
     */
    public List<String> getRowStrArr(int rowIndex){
        List<String> res = new ArrayList<>();
        XSSFRow row = this.sheet.getRow(rowIndex);
        for (int j = 0; j < row.getLastCellNum(); j++) {
            XSSFCell dataCell = row.getCell(j);
            String cellValue = this.convertCellValueToString(dataCell);
            res.add(cellValue);
        }
        return res;
    }

    /**
     * 获取某行的单元格的值-根据keyArr列顺序拼接成map
     * @param rowIndex
     * @param keyArr
     * @return
     */
    public Map<String, String> getRowStrMap(int rowIndex, List<String> keyArr){
        List<String> list = this.getRowStrArr(rowIndex);

        Map<String, String> res = new HashMap<>();
        if( CollectionUtils.isNotEmpty(list) ){
            for(int i=0; i<list.size(); i++){
                String key = "column_"+i;
                if(CollectionUtils.isNotEmpty(keyArr) && i<keyArr.size()) {
                    key = keyArr.get(i);
                }
                res.put(key, list.get(i));
            }
        }
        return res;
    }

    /**
     * 获取所有行的数据-根据keyArr列顺序拼接成map
     * @param keyArr
     * @return
     */
    public List<Map<String, String>> getAllDataMap(List<String> keyArr){
        List<Map<String, String>> res = new ArrayList<>();
        for (int i = 0; i <= this.sheet.getLastRowNum(); i++) {
            Map<String, String> item = this.getRowStrMap(i, keyArr);
            res.add(item);
        }
        return res;
    }

    /**
     * 更换工作表
     * @return
     */
    private void changeSheet(){
        this.sheet = this.workbook.getSheetAt(this.sheetIndex);
    }

    /**
     * 将单元格内容转化为字符串
     */
    private String convertCellValueToString(Cell cell) {
        if (null == cell) {
            return null;
        }
        String returnValue = null;
        switch (cell.getCellTypeEnum()) {
            //字符串
            case STRING:
                returnValue = cell.getStringCellValue();
                break;
            //数字
            case NUMERIC:
                double numericCellValue = cell.getNumericCellValue();
                boolean isInteger = isIntegerForDouble(numericCellValue);
                if (isInteger) {
                    DecimalFormat df = new DecimalFormat("0");
                    returnValue = df.format(numericCellValue);
                } else {
                    returnValue = Double.toString(numericCellValue);
                }
                break;
            //布尔
            case BOOLEAN:
                boolean booleanCellValue = cell.getBooleanCellValue();
                returnValue = Boolean.toString(booleanCellValue);
                break;
            //空值
            case BLANK:
                break;
            //公式
            case FORMULA:
                cell.getCellFormula();
                break;
            //故障
            case ERROR:
                break;
            default:
                break;
        }
        return returnValue;
    }
    /**
     * 判断是否为整数,是返回true,否则返回false.
     */
    public static boolean isIntegerForDouble(Double num) {
        double eqs = 1e-10; //精度范围
        return num - Math.floor(num) < eqs;
    }

    /**
     * 使用完要关闭流
     */
    public void close() throws IOException {
        this.workbook.close();
    }

    public int getSheetIndex() {
        return sheetIndex;
    }

    public ExcelReadUtils setSheetIndex(int sheetIndex) {
        this.sheetIndex = sheetIndex;
        this.changeSheet();
        return this;
    }
}

3.写入工具类

package com.common.utils;

import com.common.exceptions.BaseException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;

/**
 * 写excel工具类
 */
public class ExcelWriteUtils {

    private XSSFWorkbook workbook;

    private List<XSSFSheet> sheetArr;
    private List<String> sheetNameArr;

    private int currSheetIndex = 0;
    private int currRowIndex = 0;

    public ExcelWriteUtils(){
        this.sheetNameArr = Arrays.asList("sheet1");
        this.initSheetArr();
    }
    public ExcelWriteUtils(String sheetName) {
        this.sheetNameArr = Arrays.asList(sheetName);
        this.initSheetArr();
    }
    public ExcelWriteUtils(List<String> sheetNameArr) {
        this.sheetNameArr = sheetNameArr;
        this.initSheetArr();
    }

    /**
     * 初始化sheet
     * @throws Exception
     */
    private void initSheetArr() {
        if( CollectionUtils.isEmpty(this.sheetNameArr) ){
            throw BaseException.logicException("sheet没有设置名称");
        }
        //XSSFWorkbook:07版本的xlsx
        this.workbook = new XSSFWorkbook();
        //构造sheet
        this.sheetArr = new ArrayList<>();
        this.sheetNameArr.forEach(sheetName->{
            XSSFSheet sheet = this.workbook.createSheet(sheetName);
            this.sheetArr.add(sheet);
        });
    }

    /**
     * 获取当前sheet
     * @return
     */
    private XSSFSheet getCurrSheet(){
        return this.sheetArr.get(this.currSheetIndex);
    }

    /**
     * 写入数据到某行
     * @param valueArr
     */
    public void writeRow(int rowIndex, List<String> valueArr){
        XSSFRow row = this.getCurrSheet().getRow(rowIndex);
        if( row==null ){
            row = this.getCurrSheet().createRow(rowIndex);
        }
        if( CollectionUtils.isNotEmpty(valueArr) ){
            for(int i=0; i<valueArr.size(); i++){
                XSSFCell cell = row.createCell(i);
                cell.setCellValue(valueArr.get(i));
            }
        }
    }

    /**
     * 写入数据到当前行
     * @param valueArr
     */
    public void writeCurrRow(List<String> valueArr){
        this.writeRow(this.currRowIndex, valueArr);
    }

    /**
     * 批量写入数据到多行
     * @param valueArrArr
     */
    public void writeBatchRow(List<List<String>> valueArrArr){
        if( CollectionUtils.isNotEmpty(valueArrArr) ){
            valueArrArr.forEach(valueArr->{
                if( CollectionUtils.isNotEmpty(valueArr) ){
                    this.writeCurrRow(valueArr);
                }
                this.currRowIndex++;
            });
        }
    }

    public int getCurrSheetIndex() {
        return currSheetIndex;
    }

    public void setCurrSheetIndex(int currSheetIndex) {
        this.currSheetIndex = currSheetIndex;
    }

    public int getCurrRowIndex() {
        return currRowIndex;
    }

    public void setCurrRowIndex(int currRowIndex) {
        this.currRowIndex = currRowIndex;
    }

    public XSSFWorkbook getWorkbook() {
        return workbook;
    }
}

4.测试

上传文件,读取excel内容,log打印,然后生成新的excel,最后下载这个excel文件

4.1 控制器

package com.demo.mydemo.controller;


import com.common.utils.AjaxResult;
import com.common.utils.StringUtils;
import com.demo.mydemo.entity.dto.ExcelParamDTO;
import com.demo.mydemo.service.IExcelService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;

/**
 * <p>
 *  excel
 * </p>
 *
 * @author szy
 * @since 2022-05-06
 */
@Controller
@RequestMapping("/excel")
public class ExcelController {

    @Autowired
    private IExcelService excelService;

    /**
     *  http://localhost:20001/szy-tools/excel/index
     * @return
     */
    @RequestMapping("/index")
    public String index() {
        return "excel_index";
    }

    /**
     * http://localhost:20001/szy-tools/excel/upload
     */
    //限制只能post访问
    @RequestMapping(value="/upload", method= RequestMethod.POST)
    @ResponseBody
    public AjaxResult uploadData(
            @ApiParam(value = "参数") ExcelParamDTO param) {
        String filePath = excelService.upload(param);
        return AjaxResult.success("成功", filePath);
    }

    @RequestMapping("/download")
    @ApiOperation(value = "下载文件")
    public void download(
            HttpServletResponse response,
            @ApiParam(value = "文件路径") @RequestParam(value="filePath", required = true) String filePath
    ) throws IOException {
        File fileUpload = new File(filePath);
        String fileName = fileUpload.getName();
        //encode后替换  解决空格问题
        fileName = URLEncoder.encode(fileName, "UTF-8");
        fileName = fileName.replace("+", "%20");
        // 读到流中
//        URL url = new URL(fileUpload.getFileUrl());
//        URLConnection conn = url.openConnection();
//        InputStream inputStream = conn.getInputStream();
        InputStream inputStream = new FileInputStream(fileUpload);
        response.reset();
        response.setContentType("application/octet-stream");
        response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
        ServletOutputStream outputStream = response.getOutputStream();
        byte[] b = new byte[1024];
        int len;
        //从输入流中读取一定数量的字节,并将其存储在缓冲区字节数组中,读到末尾返回-1
        while ((len = inputStream.read(b)) > 0) {
            outputStream.write(b, 0, len);
        }
        inputStream.close();
    }

}

4.2 服务类/业务类

接口类

package com.demo.mydemo.service;


import com.demo.mydemo.entity.dto.ExcelParamDTO;
import com.demo.mydemo.entity.dto.SmbParamDTO;

import java.io.File;

public interface IExcelService {

    String upload(ExcelParamDTO param);
}

实现类

package com.demo.mydemo.service.impl;

import com.common.exceptions.BaseException;
import com.common.utils.*;
import com.demo.mydemo.entity.dto.*;
import com.demo.mydemo.service.IExcelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;

import static java.util.regex.Pattern.compile;

@Service
@Slf4j
public class ExcelServiceImpl implements IExcelService {
    @Override
    public String upload(ExcelParamDTO param){
        File uploadFile = null;
        try {
            //上传文件
            uploadFile = this._uploadFile(param.getFiles(), "");
            //读取excel
            ExcelReadUtils readUtils = new ExcelReadUtils(uploadFile);
            List<String> keyArr = Arrays.asList("10-19", "20-29", "30-39", "40-49", "50-59", "60-69");
            List<Map<String, String>> data = readUtils.getAllDataMap(keyArr);
            if( CollectionUtils.isNotEmpty(data) ){
                final int[] i = {1};
                data.forEach(item->{
                    log.info("第"+ i[0] +"行:{}", JSONUtils.toJsonString(item));
                    i[0]++;
                });
            }
            readUtils.close();
            //写入excel
            ExcelWriteUtils writeUtils = new ExcelWriteUtils("测试1");
            if( CollectionUtils.isNotEmpty(data) ){
                final int[] rowIndex = {0};
                data.forEach(item->{
                    List<String> valueArr = new ArrayList<>();
                    keyArr.forEach(key->{
                        valueArr.add( item.get(key) );
                    });
                    writeUtils.writeRow(rowIndex[0], valueArr);
                    rowIndex[0]++;
                });
            }
            File targetFile = this._buildExcelFile(writeUtils.getWorkbook(), "");
            return targetFile.getAbsolutePath();
        } catch (Exception e) {
            e.printStackTrace();
            throw BaseException.logicException(e.getMessage());
        } finally {
            //删除上传的文件
            if( uploadFile!=null && uploadFile.exists() ){
//                uploadFile.delete();
            }
        }
    }
    private File _uploadFile(MultipartFile srcFile, String dir) throws Exception{
        // 根路径,在 resources/static/upload
        String folderPath = ResourceUtils.getURL("classpath:").getPath() + "upload/" + (StringUtils.isNotBlank(dir) ? (dir + "/") : "");
        File folder = new File(folderPath);
        if( !folder.exists() ){
            folder.mkdirs();
        }
        UUID uuid = UUID.randomUUID();
        File targetFile = new File(folder.getAbsolutePath(), uuid+"_"+srcFile.getOriginalFilename());
        srcFile.transferTo(targetFile);
        return targetFile;
    }

    private File _buildExcelFile(XSSFWorkbook workbook, String dir) throws IOException {
        // 根路径,在 resources/static/upload
        String folderPath = ResourceUtils.getURL("classpath:").getPath() + "upload/" + (StringUtils.isNotBlank(dir) ? (dir + "/") : "");
        File folder = new File(folderPath);
        if( !folder.exists() ){
            folder.mkdirs();
        }
        UUID uuid = UUID.randomUUID();
        File targetFile = new File(folder.getAbsolutePath(), uuid+"_build_.xlsx");
        OutputStream out = new FileOutputStream(targetFile);
        workbook.write(out);
        workbook.close();
        out.close();
        return targetFile;
    }
}

4.3 页面

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>excel测试</title>
    <script src="./../scripts/jquery-3.3.1.min.js"></script>
    <script src="./../scripts/jquery.form.js"></script>
</head>
<body>
<form id="form" method="post" enctype="multipart/form-data">
    <table>
        <tr>
            <td>文件</td>
            <td>
                <input type="file" name="files"/>
            </td>
        </tr>
    </table>
    <input type="submit" value="上传" id="btnUpload"/>
</form>
<div id="result"></div>
<script>
$(function(){
    var url = window.location.origin+"/szy-tools/excel/upload";
    var download_url = window.location.origin+"/szy-tools/excel/download";
    $("#form").ajaxForm({
        url			: 	url,
        type		: 	"POST",
        dataType	: 	"json",
        beforeSubmit: 	function(){
            return true;
        },
        success: function(res){
            if( res.state=="success" ){
                $("#result").text("成功:"+res.data);
                var t_url = download_url+"?filePath="+urlencode(res.data);
                window.open(t_url);
            }else{
                $("#result").text("失败:"+res.message);
            }
        },
        fail: function(res){
            $("#result").text("失败:"+res);
        }
    });
});
function urlencode (str) {
    str = (str + '').toString();

    return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
}
</script>
</body>
</html>

5.补充所有pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.7</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>szy-tools</name>
	<description>My tools project for Spring Boot</description>
	<!-- 打包配置 -->
	<packaging>jar</packaging>

	<properties>
		<java.version>1.8</java.version>
		<!-- 分布式RPC框架Motan-->
		<motan.version>1.1.6</motan.version>
		<org-apache-poi.version>3.17</org-apache-poi.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- 热部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- thymeleaf,for html,jsp... -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<!-- json.start -->
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-mapper-asl</artifactId>
			<version>1.9.13</version>
		</dependency>
		<!-- jackson默认不支持java8的时间类型,需要添加一个时间模块 -->
		<dependency>
			<groupId>com.fasterxml.jackson.datatype</groupId>
			<artifactId>jackson-datatype-jsr310</artifactId>
		</dependency>
		<!-- json.end -->

		<!--lombok用来简化实体类-->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.8.1</version>
		</dependency>

		<!-- Knife4j在线API文档的依赖 -->
		<dependency>
			<groupId>com.github.xiaoymin</groupId>
			<artifactId>knife4j-spring-boot-starter</artifactId>
			<version>3.0.3</version>
		</dependency>

	<!-- httpclient.start -->
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
		</dependency>
	<!-- httpclient.end -->

	<!-- smb.start -->
		<!--支持文件共享SMB1协议-->
		<dependency>
			<groupId>org.samba.jcifs</groupId>
			<artifactId>jcifs</artifactId>
			<version>1.3.3</version>
		</dependency>
		<!--支持文件共享SMB2/3协议-->
		<dependency>
			<groupId>com.hierynomus</groupId>
			<artifactId>smbj</artifactId>
			<version>0.10.0</version>
		</dependency>
	<!-- smb.end -->

	<!-- user-agent工具类.start -->
		<dependency>
			<groupId>eu.bitwalker</groupId>
			<artifactId>UserAgentUtils</artifactId>
			<version>1.21</version>
		</dependency>
	<!-- user-agent工具类.end -->

	<!--poi.start -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>${org-apache-poi.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-excelant</artifactId>
			<version>${org-apache-poi.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.15</version>
		</dependency>
	<!--poi.end -->

	</dependencies>

	<build>
		<!-- 指定生成的jar包名称 -->
		<finalName>szy-tools</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

  • 作者:hyszy
  • 原文链接:https://blog.csdn.net/study_zy/article/details/126168378
    更新时间:2023年1月1日10:29:59 ,共 15782 字。