Java带图片的excel数据导入

您所在的位置:网站首页 an中如何导入图片 Java带图片的excel数据导入

Java带图片的excel数据导入

2024-07-10 12:43| 来源: 网络整理| 查看: 265

这篇文章有一些弊端,图片丢失和速度慢的情况,长期使用后发现了问题,并作了优化,优化后可查看下面这个链接的文章,代码量更少,更便于学习理解 导入带图片的excel,可查看文章:Java 通过POI快速导入带图片的excel并且图片不会丢失 带图片的EXCEL数据导入

这里使用的是POI,所以这里使用的很杂,不过方便对它们的了解。模板下载与图片导出到excel都不一样。 下面会把对应连接贴上。 带入依赖:不要使用3.17的版本,直接上代码:

org.apache.poi poi-ooxml 4.1.2

接口:

@PostMapping("/import") public CommonResult importRoadsAndBridgesData(@RequestParam("file") MultipartFile[] files){ MultipartFile file = files[0]; String fileName = file.getOriginalFilename(); // 上传文件为空 if (StringUtils.isEmpty(fileName)) { throw new ServiceException("没有导入文件"); } // 上传文件名格式不正确 if (fileName.lastIndexOf(".") != -1 && !".xlsx".equals(fileName.substring(fileName.lastIndexOf(".")))) { throw new ServiceException( "文件名格式不正确, 请使用后缀名为.xlsx的文件"); } urbanManageDataService.importRoadsAndBridgesData(file); return CommonResult.success(); } @Override public void importRoadsAndBridgesData(MultipartFile file) { ExcelUtil util = new ExcelUtil(DetailsOfRoadMaintainDto.class); List detailsOfRoadDtos = null; try { //文件,sheet名称,标题占用行数 detailsOfRoadDtos = util.importExcel(file, "附表1维护情况明细表", 3); } catch (Exception e) { log.error("导入数据解析流失败:{}", e.getMessage()); throw new ServiceException("导入数据文件解析失败!"); } //封装实体数据和文件上传 List list = new ArrayList(); //道路数据 Map dtoMap = dataConversion(detailsOfRoadDtos, 1, list); //数据保存,替换成你自己的 if(!CollectionUtils.isEmpty(list)){ detailsOfRoadMaintainMapper.insertList(list); } } //下面都是图片上传和数据存取,就不过多贴上了,主要看excel图片的获取方式 private Map dataConversion(List dtos, Integer type, List list){ Map dtoMap = new HashMap(); if(!CollectionUtils.isEmpty(dtos)){ dtos.forEach(dto ->{ DetailsOfRoadMaintainEntity entity = new DetailsOfRoadMaintainEntity(); //基础数据转换 BeanUtils.copyProperties(dto, entity); entity.setId(IdUtil.simpleUUID()); entity.setMaintainType(type); //上传的图片信息 entity.setBeforeimg(uploadFile(dto.getBeforeimg())); entity.setCreateTime(new Date()); //存入entity list.add(entity); }); } return dtoMap; } //这里就是已经获取到图片后的正常上传而已,获取到的图片信息为PictureData,转为MultipartFile进行的文件上传 private String uploadFile(PictureData pictureData){ if(null != pictureData && pictureData.getData().length > 0){ InputStream inputStream = new ByteArrayInputStream(pictureData.getData()); SysFile sysFile = null; try { MultipartFile multipartFile = new MockMultipartFile(getFileName(pictureData), null, ContentType.IMAGE_JPEG.toString(), inputStream); sysFile = attachmentService.getUploadFileInfo(multipartFile); } catch (IOException e) { log.error("字节流转文件失败:{}", e.getMessage()); throw new ServiceException("字节流转文件失败!"); } if(Objects.isNull(sysFile) || StringUtils.isEmpty(sysFile.getUrl())){ throw new ServiceException("未获取到上传文件的信息!"); } return sysFile.getUrl(); } return null; }

上面都是一些图片上传和下面要获取到后的信息进行存储,主要看图片怎么从excel获取的,下面先看参数映射:

@Data public class DetailsOfRoadMaintainDto implements Serializable { /** * 序号 */ @Excel(name = "序号") private String no; @Excel(name = "维护前照片", getPicture = true) private PictureData beforeimg; public interface ExcelHandlerAdapter { /** * 格式化 * * @param value 单元格数据值 * @param args excel注解args参数组 * * @return 处理后的值 */ Object format(Object value, String[] args); } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Excels { Excel[] value(); } package com.goktech.common.core.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.math.BigDecimal; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.IndexedColors; /** * 自定义导出Excel数据注解 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Excel { /** * 导出时在excel中排序 */ public int sort() default Integer.MAX_VALUE; /** * 导出到Excel中的名字. */ public String name() default ""; /** * 日期格式, 如: yyyy-MM-dd */ public String dateFormat() default ""; /** * 读取内容转表达式 (如: 0=男,1=女,2=未知) */ public String readConverterExp() default ""; /** * 读取图片 true=是,false=否) */ public boolean getPicture() default false; /** * 分隔符,读取字符串组内容 */ public String separator() default ","; /** * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化) */ public int scale() default -1; /** * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN */ public int roundingMode() default BigDecimal.ROUND_HALF_EVEN; /** * 导出时在excel中每个列的高度 单位为字符 */ public double height() default 14; /** * 导出时在excel中每个列的宽 单位为字符 */ public double width() default 16; /** * 文字后缀,如% 90 变成90% */ public String suffix() default ""; /** * 当值为空时,字段的默认值 */ public String defaultValue() default ""; /** * 提示信息 */ public String prompt() default ""; /** * 设置只能选择不能输入的列内容. */ public String[] combo() default {}; /** * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. */ public boolean isExport() default true; /** * 另一个类中的属性名称,支持多级获取,以小数点隔开 */ public String targetAttr() default ""; /** * 是否自动统计数据,在最后追加一行统计数据总和 */ public boolean isStatistics() default false; /** * 导出类型(0数字 1字符串) */ public ColumnType cellType() default ColumnType.STRING; /** * 导出字体颜色 */ public IndexedColors color() default IndexedColors.BLACK; /** * 导出字段对齐方式 */ public HorizontalAlignment align() default HorizontalAlignment.CENTER; /** * 自定义数据处理器 */ public Class handler() default ExcelHandlerAdapter.class; /** * 自定义数据处理器参数 */ public String[] args() default {}; /** * 字段类型(0:导出导入;1:仅导出;2:仅导入) */ Type type() default Type.ALL; public enum Type { ALL(0), EXPORT(1), IMPORT(2); private final int value; Type(int value) { this.value = value; } public int value() { return this.value; } } public enum ColumnType { NUMERIC(0), STRING(1), IMAGE(2); private final int value; ColumnType(int value) { this.value = value; } public int value() { return this.value; } } }

导入的工具类:

package com.goktech.common.core.utils.poi; import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; import java.rmi.ServerException; import java.text.DecimalFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; import com.common.core.annotation.Excel; import com.common.core.annotation.Excels; import com.common.core.exception.ServiceException; import com.common.core.text.Convert; import com.common.core.utils.DateUtils; import com.common.core.utils.StringUtils; import com.common.core.utils.file.ImageUtils; import com.common.core.utils.reflect.ReflectUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.RegExUtils; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ooxml.POIXMLDocumentPart; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.usermodel.*; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.goktech.common.core.utils.file.FileTypeUtils; import org.springframework.util.ResourceUtils; import org.springframework.web.multipart.MultipartFile; /** * Excel相关处理 * * @author ruoyi */ public class ExcelUtil { private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); public static final String FORMULA_REGEX_STR = "=|-|\\+|@"; public static final String[] FORMULA_STR = { "=", "-", "+", "@" }; /** * Excel sheet最大行数,默认65536 */ public static final int SHEET_SIZE = 65536; /** * 工作表名称 */ private String sheetName; /** * 导出类型(EXPORT:导出数据;IMPORT:导入模板) */ private Excel.Type type; /** * 工作薄对象 */ private Workbook wb; /** * 工作表对象 */ private Sheet sheet; /** * 样式列表 */ private Map styles; /** * 导入导出数据列表 */ private List list; /** * 注解列表 */ private List fields; /** * 当前行号 */ private int rownum; /** * 标题 */ private String title; /** * 最大高度 */ private short maxHeight; /** * 统计列表 */ private Map statistics = new HashMap(); /** * 数字格式 */ private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); /** * 实体对象 */ public Class clazz; public ExcelUtil(Class clazz) { this.clazz = clazz; } public void init(List list, String sheetName, String title, Excel.Type type) { if (list == null) { list = new ArrayList(); } this.list = list; this.sheetName = sheetName; this.type = type; this.title = title; createExcelField(); createWorkbook(); createTitle(); } /** * 创建excel第一行标题 */ public void createTitle() { if (StringUtils.isNotEmpty(title)) { Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0); titleRow.setHeightInPoints(30); Cell titleCell = titleRow.createCell(0); titleCell.setCellStyle(styles.get("title")); titleCell.setCellValue(title); sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), this.fields.size() - 1)); } } /** * 对excel表单默认第一个索引名转换成list * * @param is 输入流 * @return 转换后集合 */ public List importExcel(InputStream is) throws Exception { return importExcel(is, 0); } /** * 对excel表单默认第一个索引名转换成list * * @param is 输入流 * @param titleNum 标题占用行数 * @return 转换后集合 */ public List importExcel(InputStream is, int titleNum) throws Exception { return importExcel(StringUtils.EMPTY, is, titleNum, null); } /** * @description: 导入带有图片的excel * @param: [sheetName, file] * @return: java.util.List * @date: 2022/8/19 15:46 * @version: 1.0 **/ public List importExcel(MultipartFile file, String sheetName, int ttitleNum) throws Exception { Map pictures = getPictures(file, sheetName, file.getInputStream()); return importExcel(sheetName, file.getInputStream(), ttitleNum, pictures); } /** * 对excel表单指定表格索引名转换成list * * @param sheetName 表格索引名 * @param titleNum 标题占用行数 * @param is 输入流 * @return 转换后集合 */ public List importExcel(String sheetName, InputStream is, int titleNum, Map pictures) throws Exception { this.type = Excel.Type.IMPORT; this.wb = WorkbookFactory.create(is); List list = new ArrayList(); // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0); if (sheet == null) { throw new IOException("文件sheet不存在"); } // 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1 int rows = sheet.getLastRowNum(); if (rows > 0) { // 定义一个map用于存放excel列的序号和field. Map cellMap = new HashMap(); // 获取表头 Row heard = sheet.getRow(titleNum); for (int i = 0; i 0) { Row row = sheet.createRow(sheet.getLastRowNum() + 1); Set keys = statistics.keySet(); Cell cell = row.createCell(0); cell.setCellStyle(styles.get("total")); cell.setCellValue("合计"); for (Integer key : keys) { cell = row.createCell(key); cell.setCellStyle(styles.get("total")); cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); } statistics.clear(); } } /** * 获取bean中的属性值 * * @param vo 实体对象 * @param field 字段 * @param excel 注解 * @return 最终的属性值 * @throws Exception */ private Object getTargetValue(T vo, Field field, Excel excel) throws Exception { Object o = field.get(vo); if (StringUtils.isNotEmpty(excel.targetAttr())) { String target = excel.targetAttr(); if (target.contains(".")) { String[] targets = target.split("[.]"); for (String name : targets) { o = getValue(o, name); } } else { o = getValue(o, target); } } return o; } /** * 以类的属性的get方法方法形式获取值 * * @param o * @param name * @return value * @throws Exception */ private Object getValue(Object o, String name) throws Exception { if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) { Class clazz = o.getClass(); Field field = clazz.getDeclaredField(name); field.setAccessible(true); o = field.get(o); } return o; } /** * 得到所有定义字段 */ private void createExcelField() { this.fields = getFields(); this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); this.maxHeight = getRowHeight(); } /** * 获取字段注解信息 */ public List getFields() { List fields = new ArrayList(); List tempFields = new ArrayList(); tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); for (Field field : tempFields) { // 单注解 if (field.isAnnotationPresent(Excel.class)) { Excel attr = field.getAnnotation(Excel.class); if (attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type)) { field.setAccessible(true); fields.add(new Object[] { field, attr }); } } // 多注解 if (field.isAnnotationPresent(Excels.class)) { Excels attrs = field.getAnnotation(Excels.class); Excel[] excels = attrs.value(); for (Excel attr : excels) { if (attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type)) { field.setAccessible(true); fields.add(new Object[] { field, attr }); } } } } return fields; } /** * 根据注解获取最大行高 */ public short getRowHeight() { double maxHeight = 0; for (Object[] os : this.fields) { Excel excel = (Excel) os[1]; maxHeight = Math.max(maxHeight, excel.height()); } return (short) (maxHeight * 20); } /** * 创建一个工作簿 */ public void createWorkbook() { this.wb = new SXSSFWorkbook(500); this.sheet = wb.createSheet(); wb.setSheetName(0, sheetName); this.styles = createStyles(wb); } /** * 创建工作表 * * @param sheetNo sheet数量 * @param index 序号 */ public void createSheet(int sheetNo, int index) { // 设置工作表的名称. if (sheetNo > 1 && index > 0) { this.sheet = wb.createSheet(); this.createTitle(); wb.setSheetName(index, sheetName + index); } } /** * 获取单元格值 * * @param row 获取的行 * @param column 获取单元格列号 * @return 单元格值 */ public Object getCellValue(Row row, int column) { if (row == null) { return row; } Object val = ""; try { Cell cell = row.getCell(column); if (StringUtils.isNotNull(cell)) { if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) { val = cell.getNumericCellValue(); if (DateUtil.isCellDateFormatted(cell)) { val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 } else { if ((Double) val % 1 != 0) { val = new BigDecimal(val.toString()); } else { val = new DecimalFormat("0").format(val); } } } else if (cell.getCellType() == CellType.STRING) { val = cell.getStringCellValue(); } else if (cell.getCellType() == CellType.BOOLEAN) { val = cell.getBooleanCellValue(); } else if (cell.getCellType() == CellType.ERROR) { val = cell.getErrorCellValue(); } } } catch (Exception e) { return val; } return val; } /** * 判断是否是空行 * * @param row 判断的行 * @return */ private boolean isRowEmpty(Row row) { if (row == null) { return true; } for (int i = row.getFirstCellNum(); i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3