导入\导出.xlsx表格 - EasyExcel

导入\导出.xlsx表格 - EasyExcel

EaseyExcel官网

使用版本 - 3.3.2

java: 8 这个影响不大😃

已知问题:@ColumnWidth无法达到指定列宽,会少0.62,@HeadRowHeight也无法达到指定行高,少多少看情况,已提交Issues。问题不大~


先定义所需要的实体类并加上注解:

@Data // Lombok注解
@HeadRowHeight(20) // 表头行高
@ContentRowHeight(20) // 表内容行高
@ColumnWidth(10) // 列宽
@HeadFontStyle(fontName = "微软雅黑") // 表头字体
@ContentFontStyle(fontName = "微软雅黑") // 表内容字体
public class SchoolNo {

    /**
     * ID
     */
    @ExcelIgnore // 忽略该变量
    private String id;

    /**
     * 学校ID
     */
    @ExcelIgnore
    private String schoolId;

    /**
     * 学生姓名
     */
    @ExcelProperty("学生姓名") // 导出/导入解析名
    @ColumnWidth(12) // 单独设置列宽
    private String studentName;

    /**
     * 学号
     */
    @ExcelProperty("学号")
    private String studentNo;

    /**
     * 年级
     */
    @ExcelProperty("年级")
    private String grade;
}

导入/导出工具类(核心)

@Slf4j
public class TableUtils {

    /**
     * 上传路径
     */
    private static final String UPLOAD_PATH = "/data/upload/";

    /**
     * 时间格式化格式
     */
    private static final String DATE_PATTERN = "yyyy-MM-dd";

    /**
     * 最大上传次数
     */
    private static final int MAX_UPLOAD_TIMES = 5;

    /**
     * 导出表格
     *
     * @param list      数据集合
     * @param response  HttpServletResponse响应
     * @param clazz     表头
     * @param sheetName 表名
     * @param <T>       类对象
     */
    public static <T> void exportToTable(List<T> list, HttpServletResponse response, Class<T> clazz, String sheetName) {
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            response.setContentType("multipart/form-data");
            response.setCharacterEncoding(String.valueOf(StandardCharsets.UTF_8));
            response.setHeader("Content-Disposition",
                    "attachment;filename*=utf-8'zh-cn'" + URLEncoder.encode(sheetName + ".xlsx", String.valueOf(StandardCharsets.UTF_8)));
            // 表头数据样式
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            // 表内数据样式
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
            EasyExcel.write(outputStream, clazz)
                    .registerWriteHandler(horizontalCellStyleStrategy)
                    .sheet(sheetName)
                    .doWrite(list);
        } catch (IOException e) {
            log.error("导出失败", e);
            throw new RuntimeException(e.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 通过文件路径读取数据
     *
     * @param request 请求
     * @param clazz   表头
     * @param <T>     类
     * @return List
     */
    public static <T> List<T> importFromTable(HttpServletRequest request, Class<T> clazz) {
        return importFromTableBeginInRow(request, clazz, 1);
    }

    /**
     * 指定从第row行为表头开始读取
     *
     * @param request 请求
     * @param clazz   表头
     * @param row     第row行为表头
     * @param <T>     类
     * @return List
     */
    public static <T> List<T> importFromTableBeginInRow(HttpServletRequest request, Class<T> clazz, int row) {
        List<T> analyzeList = new ArrayList<>();
        try {
            // 按照日期分目录
            String uploadPath = UPLOAD_PATH + LocalDate.now().format(DateTimeFormatter.ofPattern(DATE_PATTERN));
            createDirectories(uploadPath);
            // 获取上传的文件
            Part filePart = request.getPart("file");
            // 获取文件名
            String fileName = String.valueOf(Paths.get(filePart.getSubmittedFileName()).getFileName());
            if (StringUtils.isEmpty(fileName)) {
                log.error("文件名为空");
                throw new RuntimeException("文件名为空");
            }
            String extension = fileName.substring(fileName.lastIndexOf('.'));
            if (!".xlsx".equalsIgnoreCase(extension)) {
                log.error("后缀名错误");
                throw new RuntimeException("后缀名错误");
            }

            try (InputStream fileContent = filePart.getInputStream()) {
                // 开始读取表格内容
                EasyExcel.read(fileContent, clazz, new PageReadListener<T>(analyzeList::addAll))
                        .excelType(ExcelTypeEnum.XLSX)
                        .sheet()
                        .headRowNumber(row)
                        .doRead();
            }

            // 构建文件输出路径
            String filePath = generateUniqueFilePath(uploadPath, fileName);
            Path path = Paths.get(filePath);
            // 将文件写入指定目录
            try (InputStream fileContent = filePart.getInputStream()) {
                // 写入文件
                Files.copy(fileContent, path, StandardCopyOption.REPLACE_EXISTING);
            }
            return analyzeList;
        } catch (ServletException e) {
            log.error("文件未上传", e);
            throw new ServiceException("文件未上传");
        } catch (IOException e) {
            log.error("读取失败", e);
            throw new ServiceException("读取失败");
        } catch (Exception e) {
            log.error("导入失败", e);
            throw new ServiceException("导入失败");
        }
    }

    /**
     * 创建目录
     *
     * @param directory 目录
     * @throws IOException IO异常
     */
    private static void createDirectories(String directory) throws IOException {
        Path path = Paths.get(directory);
        if (!Files.exists(path)) {
            Files.createDirectories(path);
        }
    }

    /**
     * 生成唯一文件名
     *
     * @param directory 目录
     * @param fileName  文件名
     * @return String
     */
    private static String generateUniqueFilePath(String directory, String fileName) {
        Path filePath = Paths.get(directory, fileName);
        int count = 1;
        while (Files.exists(filePath)) {
            String baseName = fileName.substring(0, fileName.lastIndexOf('.'));
            String extension = fileName.substring(fileName.lastIndexOf('.'));
            String newFileName = baseName + "(" + count + ")" + extension;
            filePath = Paths.get(directory, newFileName);
            count++;
            if (count > MAX_UPLOAD_TIMES) {
                throw new RuntimeException("文件重复次数过多,请重新上传");
            }
        }
        return filePath.toString();
    }

}

上面这个可以直接用,除了路径最大上传次数,其他的可以不用变

导入/导出前端HTML

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
	<title>导入导出</title>    
</head>
<body>
    
    <script th:inline="javascript">
        const schoolList = [[${schoolList}]];
    </script>
    
	<div class="col-xs-8">
		<input class="form-control" id="fileInput" type="file" name="file" accept=".xlsx">
	</div>
    
    <label for="schoolId">
        <select id="schoolId" name="schoolId" required>
            <option value="">请选择学校</option>
            <!-- 这里是Thymeleaf框架,用其他框架的换成其他框架就行 -->
            <span th:each="school:${schoolList}">
                <option th:value="${school.id}" th:text="${school.schoolName}"></option>
            </span>
            <!-- 这里是Thymeleaf框架,用其他框架的换成其他框架就行 -->
        </select>
    </label>
    
    <button type="button" class="btn btn-primary" onclick="importFile()">
		<i class="fa fa-upload" aria-hidden="true"></i> 导入
	</button>
	<button type="button" class="btn btn-primary" onclick="exportFile()">
		<i class="fa fa-external-link" aria-hidden="true"></i> 导出模板
	</button>
</body>
<script type="text/javascript" src="/js/file.js"></script>

这里指定为.xlsx文件,由于时代的原因,这里放弃支持.xls文件。

样式没有的话可以直接删了,只是为了好看,实现功能可以不需要,按需添加就行了。

导入/导出前端JS file.js

const prefix = "/manage/schoolNo"

/**
 文件上传
 */
async function importFile() {
    const fileInput = document.getElementById('fileInput');
    const file = fileInput.files[0];
    const schoolId = $("#schoolId>option:selected").val().trim();

    if (!file) {
        showMessage("导入失败", "请选择至少一个文件!");
        return;
    }

    if (!schoolId) {
        showMessage("导入失败", "请选择学校!");
        return;
    }

    const formData = new FormData();
    formData.append('file', file);
    formData.append('schoolId', schoolId);
    fetch(`${prefix}/importFile`, {
        method: 'POST',
        body: formData
    })
        .then(response => {
            if (!response.ok) {
                throw new Error('网络异常!');
            }
            return response.json();
        })
        .then(data => {
            if (data.code === 0) {
                parent.layer.msg('导入成功');
                window.location.reload();
                // 获取窗口索引
                const index = parent.layer.getFrameIndex(window.name);
                parent.layer.close(index);
            } else {
                showMessage("导入失败", data.msg);
            }
        })
        .catch(error => {
            showMessage("导入失败", "操作失败;返回信息:" + error.message);
        })
}

function showMessage(title, content) {
    parent.layer.open({
        title: title,
        content: content
    });
}

/**
 * 导出模板
 */
function exportFile() {
    const xhr = new XMLHttpRequest();
    const formData = new FormData();
    const filename = "学号导入模板.xlsx";

    xhr.open('GET', `${prefix}/exportFile`);
    xhr.setRequestHeader("access-token", sessionStorage.getItem('access-token'));
    xhr.responseType = 'blob';

    xhr.onload = () => { // 这里可以加个event,但是不知道干啥用,所以就没加,知道的可以加
        if (this.status === 200) {
            const blob = xhr.response;
            if (window.navigator.msSaveOrOpenBlob) {
                navigator.msSaveBlob(blob, filename);
            } else {
                downloadBlob(blob, filename);
            }
            layer.msg("导出成功");
            layer.close(index);
        } else {
            layer.msg("导出失败");
            layer.close(index);
        }
    };
    xhr.send(formData);
}

function downloadBlob(blob, filename) {
    const url = createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    a.style.display = 'none';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url);
}

function createObjectURL(object) {
    return (window.URL || window.webkitURL).createObjectURL(object);
}

后端接口Controller

@Slf4j
@RestController
@RequestMapping("/manage/schoolNo")
public class SchoolNoController {

    @Resource
    private SchoolNoService schoolNoService;

    @Resource
    private SchoolService schoolService;

    @PostMapping("/importFile")
    public R importFile(HttpServletRequest request, String schoolId) {
        log.info("后台导入学号");
        try {
            // 读取文件
            List<SchoolNo> schoolNoList = TableUtils.importFromTable(request, SchoolNo.class);
            log.debug("文件内容, {}", JSON.toJSONString(schoolNoList));
            if (!checkAndSaveList(schoolNoList, schoolId)) {
                log.error("导入失败");
                return R.error("导入失败");
            }
            return R.ok("导入成功");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return R.error("系统异常,请按照模板文件格式导入数据");
        }
    }

    /**
     * 导入数据
     *
     * @param schoolNoList
     * @return
     * @throws ServiceException
     */
    private boolean checkAndSaveList(List<SchoolNo> schoolNoList, String schoolId) throws ServiceException {
        try {
            List<SchoolNo> schoolNos = schoolNoService.batchSelect(schoolNoList, schoolId);
            if (CollectionUtils.isEmpty(schoolNos)) {
                for (SchoolNo schoolNo : schoolNoList) {
                    schoolNo.setSchoolId(schoolId);
                }
                int result = schoolNoService.batchInsert(schoolNoList);
                return result == schoolNoList.size();
            } else {
                String studentNo = schoolNos.get(0).getStudentNo();
                int index = 2;
                for (SchoolNo schoolNo : schoolNoList) {
                    if (Objects.equals(schoolNo.getStudentNo(), studentNo)) {
                        log.error("第{}行学号已存在", index);
                        break;
                    }
                    index++;
                }
                return false;
            }
        } catch (Exception e) {
            log.error("导入数据失败", e);
            throw new RuntimeException("导入数据异常!");
        }
    }

    /**
     * 导出模板
     *
     * @param response HttpServletResponse
     */
    @GetMapping("/exportFile")
    public void exportFile(HttpServletResponse response) {
        TableUtils.exportToTable(new ArrayList<>(0), response, SchoolNo.class, "导入模板");
    }
}

好了,到这里就完成了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于 EasyExcel导入导出功能,你可以使用 EasyExcel 库来实现。下面是一个简单的示例代码,用于演示如何使用 EasyExcel 进行导入导出操作: ```java import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Table; import com.alibaba.excel.support.ExcelTypeEnum; import java.util.ArrayList; import java.util.List; public class ExcelUtils { public static void main(String[] args) { // 导出Excel文件 exportExcel(); // 导入Excel文件 importExcel(); } public static void exportExcel() { // 准备数据 List<User> userList = new ArrayList<>(); userList.add(new User("张三", 20)); userList.add(new User("李四", 25)); // 设置表格标题 String[] headers = {"姓名", "年龄"}; // 创建表格对象 Table table = new Table(0); table.setTableStyle(createTableStyle()); table.setHead(headers); // 设置写入Excel的文件路径和文件名 String fileName = "user.xlsx"; // 写入Excel文件 ExcelWriter excelWriter = EasyExcel.write(fileName).withWriterSheet().build(); Sheet sheet = new Sheet(1, 0, User.class); sheet.setTableStyle(createTableStyle()); excelWriter.write(userList, sheet); excelWriter.finish(); } public static void importExcel() { // 读取Excel文件 String fileName = "user.xlsx"; List<User> userList = EasyExcel.read(fileName).head(User.class).sheet().doReadSync(); // 处理导入的数据 for (User user : userList) { System.out.println("姓名: " + user.getName() + ", 年龄: " + user.getAge()); } } private static TableStyle createTableStyle() { // 创建表格样式对象 TableStyle tableStyle = new TableStyle(); tableStyle.setTableContentBackGroundColor(IndexedColors.WHITE); tableStyle.setTableContentFontName("宋体"); tableStyle.setTableContentFontSize((short) 9); return tableStyle; } // 用户类 public static class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } // getter 和 setter 方法 // ... } } ``` 在上面的代码中,`exportExcel` 方法用于导出 Excel 文件,将用户列表数据写入 Excel 中。`importExcel` 方法用于导入 Excel 文件,读取 Excel 中的数据并进行处理。你可以根据自己的需求进行修改和扩展。在使用 EasyExcel 进行导入导出操作时,需要引入相应的库依赖。如果使用 Maven 进行项目管理,可以在 `pom.xml` 文件中添加以下依赖: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.10</version> </dependency> ``` 这样就可以使用 EasyExcel导入导出功能了。希望对你有所帮助!如果有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值