mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-20 18:15:56 +08:00
Pre Merge pull request !222 from 孤舟烟雨/auto-494979-dev-094ab998
This commit is contained in:
commit
4bef092c0e
@ -0,0 +1,33 @@
|
||||
package com.ruoyi.common.excel.builder;
|
||||
|
||||
import com.ruoyi.common.excel.common.SheetModel;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 单元格信息构建器
|
||||
*
|
||||
* @author liyang
|
||||
**/
|
||||
@Getter
|
||||
public abstract class CellModelBuilder extends SheetModelBuilder {
|
||||
/**
|
||||
* 列索引
|
||||
*/
|
||||
protected final int colIndex;
|
||||
/**
|
||||
* 行索引
|
||||
*/
|
||||
protected final int rowIndex;
|
||||
|
||||
protected CellModelBuilder(String sheetName, int rowIndex, int colIndex) {
|
||||
super(sheetName);
|
||||
this.rowIndex = rowIndex;
|
||||
this.colIndex = colIndex;
|
||||
}
|
||||
/**
|
||||
* 具体构建方法
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
abstract protected SheetModel build() ;
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.ruoyi.common.excel.builder;
|
||||
|
||||
|
||||
import com.ruoyi.common.excel.common.SheetModel;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* sheet页信息构建器
|
||||
*
|
||||
* @author liyang
|
||||
**/
|
||||
@Getter
|
||||
public abstract class SheetModelBuilder {
|
||||
/**
|
||||
* sheet名称
|
||||
*/
|
||||
protected final String sheetName;
|
||||
protected SheetModelBuilder(String sheetName) {
|
||||
this.sheetName = sheetName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体构建方法
|
||||
* @return
|
||||
*/
|
||||
abstract protected SheetModel build() ;
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.ruoyi.common.excel.common;
|
||||
|
||||
import com.ruoyi.common.excel.builder.CellModelBuilder;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 单元格信息
|
||||
*
|
||||
* @author liyang
|
||||
*/
|
||||
@Getter
|
||||
public class SheetCellModel extends SheetModel {
|
||||
/**
|
||||
* 列索引
|
||||
*/
|
||||
protected int colIndex;
|
||||
/**
|
||||
* 行索引
|
||||
*/
|
||||
protected int rowIndex;
|
||||
|
||||
public SheetCellModel(CellModelBuilder cellModelBuilder) {
|
||||
super(cellModelBuilder);
|
||||
this.rowIndex = cellModelBuilder.getRowIndex();
|
||||
this.colIndex = cellModelBuilder.getColIndex();
|
||||
}
|
||||
protected SheetCellModel(){
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.ruoyi.common.excel.common;
|
||||
|
||||
import com.ruoyi.common.excel.builder.SheetModelBuilder;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* sheet页信息
|
||||
*
|
||||
* @author liyang
|
||||
*/
|
||||
@Getter
|
||||
public class SheetModel {
|
||||
/**
|
||||
* sheet名称
|
||||
*/
|
||||
protected String sheetName;
|
||||
|
||||
public SheetModel(SheetModelBuilder sheetModelBuilder) {
|
||||
this.sheetName = sheetModelBuilder.getSheetName();
|
||||
}
|
||||
|
||||
protected SheetModel() {
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package com.ruoyi.common.excel.handler;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.excel.write.handler.RowWriteHandler;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
|
||||
import com.ruoyi.common.excel.model.CommentModel;
|
||||
import com.ruoyi.common.utils.poi.PoiExcelUtil;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 自定义批注处理器
|
||||
*
|
||||
* @author liyang
|
||||
*/
|
||||
public class CustomCommentWriteHandler implements RowWriteHandler {
|
||||
/**
|
||||
* sheet页名称列表
|
||||
*/
|
||||
private List<String> sheetNameList;
|
||||
List<CommentModel> commentList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 自定义批注适配器构造方法
|
||||
*
|
||||
* @param commentList 批注信息
|
||||
* @param extension 文件后缀(xlsx、xls)
|
||||
*/
|
||||
public CustomCommentWriteHandler(List<CommentModel> commentList, String extension) {
|
||||
if (CollUtil.isEmpty(commentList)) {
|
||||
return;
|
||||
}
|
||||
//文件不为指定的格式时,默认为Xlsx
|
||||
if (StrUtil.equals(extension, "xlsx") == false && StrUtil.equals(extension, "xls") == false) {
|
||||
extension = "xlsx";
|
||||
}
|
||||
this.commentList = commentList.stream().filter(x ->
|
||||
StrUtil.isNotBlank(x.getSheetName()) && x.getColIndex() >=0 && x.getRowIndex() >= 0 && StrUtil.isNotBlank(x.getCommentContent())
|
||||
).collect(Collectors.toList());
|
||||
sheetNameList = this.commentList.stream().map(x -> x.getSheetName()).distinct().collect(Collectors.toList());
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档后缀名
|
||||
*/
|
||||
private String extension;
|
||||
|
||||
@Override
|
||||
public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
|
||||
Integer relativeRowIndex, Boolean isHead) {
|
||||
Sheet sheet = writeSheetHolder.getSheet();
|
||||
//不需要添加批注,或者当前sheet页不需要添加批注
|
||||
if (CollUtil.isEmpty(commentList) || sheetNameList.contains(sheet.getSheetName()) == false) {
|
||||
return;
|
||||
}
|
||||
//获取当前行的批注信息
|
||||
List<CommentModel> rowCommentList = commentList.stream().filter(x ->
|
||||
StrUtil.equals(x.getSheetName(), sheet.getSheetName())
|
||||
&& StrUtil.equals(String.valueOf(relativeRowIndex), String.valueOf(x.getRowIndex()))).collect(Collectors.toList());
|
||||
//当前行没有批注信息
|
||||
if (CollUtil.isEmpty(rowCommentList)) {
|
||||
return;
|
||||
}
|
||||
List<Integer> colIndexList = rowCommentList.stream().map(x -> x.getColIndex()).distinct().collect(Collectors.toList());
|
||||
for (Integer colIndex : colIndexList) {
|
||||
//同一单元格的批注信息
|
||||
List<CommentModel> cellCommentList = rowCommentList.stream().filter(x ->
|
||||
StrUtil.equals(String.valueOf(colIndex), String.valueOf(x.getColIndex()))).collect(Collectors.toList());
|
||||
if (CollUtil.isEmpty(cellCommentList)) {
|
||||
continue;
|
||||
}
|
||||
//批注内容拼成一条
|
||||
String commentContent = cellCommentList.stream().map(x -> x.getCommentContent()).collect(Collectors.joining());
|
||||
Cell cell = row.getCell(colIndex);
|
||||
PoiExcelUtil.addComment(cell, commentContent, extension);
|
||||
}
|
||||
//删除批注信息
|
||||
commentList.remove(rowCommentList);
|
||||
//重新获取要添加的sheet页姓名
|
||||
sheetNameList = commentList.stream().map(x -> x.getSheetName()).distinct().collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.ruoyi.common.excel.model;
|
||||
|
||||
import com.ruoyi.common.excel.common.SheetCellModel;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 批注信息类
|
||||
*
|
||||
* @author liyang
|
||||
*/
|
||||
@Getter
|
||||
public class CommentModel extends SheetCellModel {
|
||||
/**
|
||||
* 批注内容
|
||||
*/
|
||||
private String commentContent;
|
||||
|
||||
private CommentModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成批注信息
|
||||
*
|
||||
* @param sheetName sheet页名称
|
||||
* @param rowIndex 行号
|
||||
* @param columnIndex 列号
|
||||
* @param commentContent 批注内容
|
||||
* @return
|
||||
*/
|
||||
public static CommentModel createCommentModel(String sheetName, int rowIndex, int columnIndex, String commentContent) {
|
||||
CommentModel commentModel = new CommentModel();
|
||||
//sheet页名称
|
||||
commentModel.sheetName = sheetName;
|
||||
//行号
|
||||
commentModel.rowIndex = rowIndex;
|
||||
//列号
|
||||
commentModel.colIndex = columnIndex;
|
||||
//批注内容
|
||||
commentModel.commentContent = commentContent;
|
||||
return commentModel;
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,8 @@ import com.ruoyi.common.excel.CellMergeStrategy;
|
||||
import com.ruoyi.common.excel.DefaultExcelListener;
|
||||
import com.ruoyi.common.excel.ExcelListener;
|
||||
import com.ruoyi.common.excel.ExcelResult;
|
||||
import com.ruoyi.common.excel.handler.CustomCommentWriteHandler;
|
||||
import com.ruoyi.common.excel.model.CommentModel;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.file.FileUtils;
|
||||
import lombok.AccessLevel;
|
||||
@ -116,7 +118,49 @@ public class ExcelUtil {
|
||||
throw new RuntimeException("导出Excel异常");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出excel模板
|
||||
*
|
||||
* @param list 导出数据集合
|
||||
* @param sheetName 工作表的名称
|
||||
* @param clazz 实体类
|
||||
* @param commentList 批注
|
||||
* @param response 响应体
|
||||
*/
|
||||
public static <T> void exportExcelCommentTemplate(List<T> list, List<CommentModel> commentList, String sheetName, Class<T> clazz, HttpServletResponse response) {
|
||||
exportExcelCommentTemplate(list,commentList, sheetName, clazz, false, response);
|
||||
}
|
||||
/**
|
||||
* 导出excel模板
|
||||
*
|
||||
* @param list 导出数据集合
|
||||
* @param sheetName 工作表的名称
|
||||
* @param clazz 实体类
|
||||
* @param merge 是否合并单元格
|
||||
* @param commentList 批注
|
||||
* @param response 响应体
|
||||
*/
|
||||
public static <T> void exportExcelCommentTemplate(List<T> list, List<CommentModel> commentList, String sheetName, Class<T> clazz, boolean merge, HttpServletResponse response) {
|
||||
try {
|
||||
resetResponse(sheetName, response);
|
||||
ServletOutputStream os = response.getOutputStream();
|
||||
ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz)
|
||||
.autoCloseStream(false)
|
||||
// 自动适配
|
||||
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
|
||||
.registerWriteHandler(new CustomCommentWriteHandler(commentList, "xlsx"))
|
||||
// 大数值自动转换 防止失真
|
||||
.registerConverter(new ExcelBigNumberConvert())
|
||||
.sheet(sheetName);
|
||||
if (merge) {
|
||||
// 合并处理器
|
||||
builder.registerWriteHandler(new CellMergeStrategy(list, true));
|
||||
}
|
||||
builder.doWrite(list);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("导出Excel异常");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 单表多数据模板导出 模板格式为 {.属性}
|
||||
*
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
package com.ruoyi.common.utils.poi;
|
||||
|
||||
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
|
||||
|
||||
/**
|
||||
* POI Excel工具类
|
||||
*
|
||||
* @author liyang
|
||||
*/
|
||||
public class PoiExcelUtil {
|
||||
/**
|
||||
* 给Cell添加批注
|
||||
*
|
||||
* @param cell 单元格
|
||||
* @param value 批注内容
|
||||
* @param extension 扩展名
|
||||
*/
|
||||
public static void addComment(Cell cell, String value, String extension) {
|
||||
Sheet sheet = cell.getSheet();
|
||||
cell.removeCellComment();
|
||||
if ("xls".equals(extension)) {
|
||||
ClientAnchor anchor = new HSSFClientAnchor();
|
||||
// 关键修改
|
||||
anchor.setDx1(0);
|
||||
anchor.setDx2(0);
|
||||
anchor.setDy1(0);
|
||||
anchor.setDy2(0);
|
||||
anchor.setCol1(cell.getColumnIndex());
|
||||
anchor.setRow1(cell.getRowIndex());
|
||||
anchor.setCol2(cell.getColumnIndex() + 5);
|
||||
anchor.setRow2(cell.getRowIndex() + 6);
|
||||
// 结束
|
||||
Drawing drawing = sheet.getDrawingPatriarch();
|
||||
if (drawing == null) {
|
||||
drawing = sheet.createDrawingPatriarch();
|
||||
}
|
||||
Comment comment = drawing.createCellComment(anchor);
|
||||
// 输入批注信息
|
||||
comment.setString(new HSSFRichTextString(value));
|
||||
// 将批注添加到单元格对象中
|
||||
cell.setCellComment(comment);
|
||||
} else if ("xlsx".equals(extension)) {
|
||||
ClientAnchor anchor = new XSSFClientAnchor();
|
||||
// 关键修改
|
||||
anchor.setDx1(0);
|
||||
anchor.setDx2(0);
|
||||
anchor.setDy1(0);
|
||||
anchor.setDy2(0);
|
||||
anchor.setCol1(cell.getColumnIndex());
|
||||
anchor.setRow1(cell.getRowIndex());
|
||||
anchor.setCol2(cell.getColumnIndex() + 5);
|
||||
anchor.setRow2(cell.getRowIndex() + 6);
|
||||
// 结束
|
||||
Drawing drawing = sheet.getDrawingPatriarch();
|
||||
if (drawing == null) {
|
||||
drawing = sheet.createDrawingPatriarch();
|
||||
}
|
||||
Comment comment = drawing.createCellComment(anchor);
|
||||
// 输入批注信息
|
||||
comment.setString(new XSSFRichTextString(value));
|
||||
// 将批注添加到单元格对象中
|
||||
cell.setCellComment(comment);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,6 +13,7 @@ import com.ruoyi.common.core.validate.EditGroup;
|
||||
import com.ruoyi.common.core.validate.QueryGroup;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.excel.ExcelResult;
|
||||
import com.ruoyi.common.excel.model.CommentModel;
|
||||
import com.ruoyi.common.utils.ValidatorUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.demo.domain.TestDemo;
|
||||
@ -29,6 +30,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -145,4 +147,17 @@ public class TestDemoController extends BaseController {
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(iTestDemoService.deleteWithValidByIds(Arrays.asList(ids), true) ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导入模板
|
||||
*/
|
||||
@PostMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response) {
|
||||
List<CommentModel> commentList = new ArrayList<>();
|
||||
String sheetName = "组织机构";
|
||||
commentList.add(CommentModel.createCommentModel(sheetName, 0, 0, "部门id不能为空\n换行文本"));
|
||||
commentList.add(CommentModel.createCommentModel(sheetName, 0, 1, "用户id不能为空\n换行文本"));
|
||||
commentList.add(CommentModel.createCommentModel(sheetName, 0, 2, "排序好不能为空\n换行文本"));
|
||||
ExcelUtil.exportExcelCommentTemplate(new ArrayList<>(),commentList, sheetName, TestDemoImportVo.class, response);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1 +1 @@
|
||||
如果使用的是RuoYi-Vue3前端,那么需要覆盖一下此目录的模板index.vue.vm、index-tree.vue.vm文件到上级vue目录。
|
||||
如果使用的是Vue3前端,那么需要覆盖一下此目录的模板index.vue.vm、index-tree.vue.vm文件到上级vue目录。
|
||||
|
||||
@ -190,6 +190,10 @@
|
||||
>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<div class="el-upload__tip text-center" slot="tip">
|
||||
<span>仅允许导入xls、xlsx格式文件。</span>
|
||||
<el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importTemplate">下载模板</el-link>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitFileForm">确 定</el-button>
|
||||
@ -425,7 +429,12 @@ export default {
|
||||
// 提交上传文件
|
||||
submitFileForm() {
|
||||
this.$refs.upload.submit();
|
||||
}
|
||||
},
|
||||
/** 下载模板操作 */
|
||||
importTemplate() {
|
||||
this.download('/demo/demo/importTemplate', {
|
||||
}, `unit_template_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user