| Автор | SHA1 | Сообщение | Дата |
|---|---|---|---|
|
|
b46040c855 | fix bug | 4 лет назад |
|
|
09f323cc30 | 支持前缀 | 6 лет назад |
|
|
202aa3fe42 | 发布4.2.0版本 | 6 лет назад |
|
|
0ceb3ed0b4 |
!67 修复 SAX SheetHandler 特殊情境下导致列错位
Merge pull request !67 from imzhs/master |
6 лет назад |
|
|
42e8287156 | fix SheetHandler 完善空单元格错位处理 | 6 лет назад |
|
|
fad3c77070 | 访问路径加上前缀 | 6 лет назад |
|
|
69a337e3cd | 中文编码 | 6 лет назад |
|
|
f6e33e0768 | easypoi-wps模块,支持excel的预览以及编辑 | 6 лет назад |
|
|
6318b414dd | XLSX水印工具类 | 6 лет назад |
| @@ -134,22 +134,22 @@ https://oss.sonatype.org/content/groups/public/ | |||||
| <dependency> | <dependency> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi-spring-boot-starter</artifactId> | <artifactId>easypoi-spring-boot-starter</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0</version> | |||||
| </dependency> | </dependency> | ||||
| <dependency> | <dependency> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi-base</artifactId> | <artifactId>easypoi-base</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0</version> | |||||
| </dependency> | </dependency> | ||||
| <dependency> | <dependency> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi-web</artifactId> | <artifactId>easypoi-web</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0</version> | |||||
| </dependency> | </dependency> | ||||
| <dependency> | <dependency> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi-annotation</artifactId> | <artifactId>easypoi-annotation</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0</version> | |||||
| </dependency> | </dependency> | ||||
| ``` | ``` | ||||
| @@ -161,22 +161,22 @@ https://oss.sonatype.org/content/groups/public/ | |||||
| <dependency> | <dependency> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi-spring-boot-starter</artifactId> | <artifactId>easypoi-spring-boot-starter</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0</version> | |||||
| </dependency> | </dependency> | ||||
| <dependency> | <dependency> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi-base</artifactId> | <artifactId>easypoi-base</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0</version> | |||||
| </dependency> | </dependency> | ||||
| <dependency> | <dependency> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi-web</artifactId> | <artifactId>easypoi-web</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0</version> | |||||
| </dependency> | </dependency> | ||||
| <dependency> | <dependency> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi-annotation</artifactId> | <artifactId>easypoi-annotation</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0</version> | |||||
| </dependency> | </dependency> | ||||
| ``` | ``` | ||||
| @@ -4,7 +4,7 @@ | |||||
| <parent> | <parent> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi</artifactId> | <artifactId>easypoi</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0.A</version> | |||||
| </parent> | </parent> | ||||
| <artifactId>easypoi-annotation</artifactId> | <artifactId>easypoi-annotation</artifactId> | ||||
| <description>base annotation</description> | <description>base annotation</description> | ||||
| @@ -67,6 +67,11 @@ public @interface Excel { | |||||
| */ | */ | ||||
| public int imageType() default 1; | public int imageType() default 1; | ||||
| /** | |||||
| * 文字前缀,如1234567890112242335 变成`1234567890112242335 | |||||
| */ | |||||
| public String prefix() default ""; | |||||
| /** | /** | ||||
| * 文字后缀,如% 90 变成90% | * 文字后缀,如% 90 变成90% | ||||
| */ | */ | ||||
| @@ -4,7 +4,7 @@ | |||||
| <parent> | <parent> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi</artifactId> | <artifactId>easypoi</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0.A</version> | |||||
| </parent> | </parent> | ||||
| <artifactId>easypoi-base</artifactId> | <artifactId>easypoi-base</artifactId> | ||||
| <dependencies> | <dependencies> | ||||
| @@ -106,5 +106,9 @@ | |||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi-annotation</artifactId> | <artifactId>easypoi-annotation</artifactId> | ||||
| </dependency> | </dependency> | ||||
| </dependencies> | |||||
| <dependency> | |||||
| <groupId>org.apache.poi</groupId> | |||||
| <artifactId>poi-ooxml</artifactId> | |||||
| </dependency> | |||||
| </dependencies> | |||||
| </project> | </project> | ||||
| @@ -84,6 +84,10 @@ public class ExcelExportEntity extends ExcelBaseEntity implements Comparable<Exc | |||||
| * 合并依赖` | * 合并依赖` | ||||
| */ | */ | ||||
| private int[] mergeRely; | private int[] mergeRely; | ||||
| /** | |||||
| * 前缀 | |||||
| */ | |||||
| private String prefix; | |||||
| /** | /** | ||||
| * 后缀 | * 后缀 | ||||
| */ | */ | ||||
| @@ -44,6 +44,10 @@ public class ExcelImportEntity extends ExcelBaseEntity { | |||||
| * 对应exportType | * 对应exportType | ||||
| */ | */ | ||||
| private String classType; | private String classType; | ||||
| /** | |||||
| * 前缀 | |||||
| */ | |||||
| private String prefix; | |||||
| /** | /** | ||||
| * 后缀 | * 后缀 | ||||
| */ | */ | ||||
| @@ -223,6 +223,9 @@ public class ExportCommonService { | |||||
| if (needHandlerList != null && needHandlerList.contains(entity.getName())) { | if (needHandlerList != null && needHandlerList.contains(entity.getName())) { | ||||
| value = dataHandler.exportHandler(obj, entity.getName(), value); | value = dataHandler.exportHandler(obj, entity.getName(), value); | ||||
| } | } | ||||
| if (StringUtils.isNotBlank(entity.getPrefix()) && value != null) { | |||||
| value = entity.getPrefix() + value; | |||||
| } | |||||
| if (StringUtils.isNotEmpty(entity.getSuffix()) && value != null) { | if (StringUtils.isNotEmpty(entity.getSuffix()) && value != null) { | ||||
| value = value + entity.getSuffix(); | value = value + entity.getSuffix(); | ||||
| } | } | ||||
| @@ -262,6 +265,7 @@ public class ExportCommonService { | |||||
| Integer.valueOf(PoiPublicUtil.getValueByTargetId(excel.orderNum(), targetId, "0"))); | Integer.valueOf(PoiPublicUtil.getValueByTargetId(excel.orderNum(), targetId, "0"))); | ||||
| excelEntity.setWrap(excel.isWrap()); | excelEntity.setWrap(excel.isWrap()); | ||||
| excelEntity.setExportImageType(excel.imageType()); | excelEntity.setExportImageType(excel.imageType()); | ||||
| excelEntity.setPrefix(excel.prefix()); | |||||
| excelEntity.setSuffix(excel.suffix()); | excelEntity.setSuffix(excel.suffix()); | ||||
| excelEntity.setDatabaseFormat(excel.databaseFormat()); | excelEntity.setDatabaseFormat(excel.databaseFormat()); | ||||
| excelEntity.setFormat( | excelEntity.setFormat( | ||||
| @@ -175,7 +175,7 @@ public final class ExcelExportOfTemplateUtil extends BaseExportService { | |||||
| private ExcelForEachParams getIndexColumn(List<ExcelForEachParams> columns) { | private ExcelForEachParams getIndexColumn(List<ExcelForEachParams> columns) { | ||||
| for (int i = 0; i < columns.size(); i++) { | for (int i = 0; i < columns.size(); i++) { | ||||
| if (INDEX.equals(columns.get(i).getConstValue())) { | |||||
| if (columns.get(i) != null && INDEX.equals(columns.get(i).getConstValue())) { | |||||
| columns.get(i).setConstValue("1"); | columns.get(i).setConstValue("1"); | ||||
| return columns.get(i); | return columns.get(i); | ||||
| } | } | ||||
| @@ -105,13 +105,6 @@ public class MergedRegionHelper { | |||||
| public void shiftRows(Sheet sheet, int rowIndex, int size, int shiftRows) { | public void shiftRows(Sheet sheet, int rowIndex, int size, int shiftRows) { | ||||
| Set<String> keys = new HashSet<String>(); | Set<String> keys = new HashSet<String>(); | ||||
| keys.addAll(mergedCache.keySet()); | keys.addAll(mergedCache.keySet()); | ||||
| //删除掉原始的缓存KEY | |||||
| for (String key : keys) { | |||||
| String[] temp = key.split("_"); | |||||
| if (Integer.parseInt(temp[0]) >= rowIndex + size && Integer.parseInt(temp[0]) <= rowIndex + size + shiftRows) { | |||||
| mergedCache.remove(key); | |||||
| } | |||||
| } | |||||
| for (String key : keys) { | for (String key : keys) { | ||||
| String[] temp = key.split("_"); | String[] temp = key.split("_"); | ||||
| if (Integer.parseInt(temp[0]) >= rowIndex) { | if (Integer.parseInt(temp[0]) >= rowIndex) { | ||||
| @@ -132,6 +125,13 @@ public class MergedRegionHelper { | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| //删除掉原始的缓存KEY | |||||
| for (String key : keys) { | |||||
| String[] temp = key.split("_"); | |||||
| if (Integer.parseInt(temp[0]) >= rowIndex + size && Integer.parseInt(temp[0]) <= rowIndex + size + shiftRows) { | |||||
| mergedCache.remove(key); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -227,6 +227,7 @@ public class CellValueService { | |||||
| result = cell; | result = cell; | ||||
| } | } | ||||
| if (entity != null) { | if (entity != null) { | ||||
| result = handlerPrefix(entity.getPrefix(), result); | |||||
| result = handlerSuffix(entity.getSuffix(), result); | result = handlerSuffix(entity.getSuffix(), result); | ||||
| result = replaceValue(entity.getReplace(), result); | result = replaceValue(entity.getReplace(), result); | ||||
| result = replaceValue(entity.getReplace(), result); | result = replaceValue(entity.getReplace(), result); | ||||
| @@ -257,12 +258,29 @@ public class CellValueService { | |||||
| Type[] ts = setMethod.getGenericParameterTypes(); | Type[] ts = setMethod.getGenericParameterTypes(); | ||||
| String classFullName = ts[0].toString(); | String classFullName = ts[0].toString(); | ||||
| Object result = cellEntity.getValue(); | Object result = cellEntity.getValue(); | ||||
| result = handlerPrefix(entity.getPrefix(), result); | |||||
| result = handlerSuffix(entity.getSuffix(), result); | result = handlerSuffix(entity.getSuffix(), result); | ||||
| result = replaceValue(entity.getReplace(), result); | result = replaceValue(entity.getReplace(), result); | ||||
| result = handlerValue(dataHandler, object, result, titleString); | result = handlerValue(dataHandler, object, result, titleString); | ||||
| return getValueByType(classFullName, result, entity, (Class) ts[0]); | return getValueByType(classFullName, result, entity, (Class) ts[0]); | ||||
| } | } | ||||
| /** | |||||
| * 把前缀删除掉 | |||||
| * | |||||
| * @param result | |||||
| * @param prefix | |||||
| * @return | |||||
| */ | |||||
| private Object handlerPrefix(String prefix, Object result) { | |||||
| if (StringUtils.isNotEmpty(prefix) && result != null | |||||
| && result.toString().startsWith(prefix)) { | |||||
| String temp = result.toString(); | |||||
| return temp.substring(prefix.length(), temp.length()); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| /** | /** | ||||
| * 把后缀删除掉 | * 把后缀删除掉 | ||||
| * | * | ||||
| @@ -156,8 +156,8 @@ public class ExcelImportService extends ImportBaseService { | |||||
| ImportParams params, | ImportParams params, | ||||
| Map<String, PictureData> pictures) throws Exception { | Map<String, PictureData> pictures) throws Exception { | ||||
| List collection = new ArrayList(); | List collection = new ArrayList(); | ||||
| Map<String, ExcelImportEntity> excelParams = new HashMap<String, ExcelImportEntity>(); | |||||
| List<ExcelCollectionParams> excelCollection = new ArrayList<ExcelCollectionParams>(); | |||||
| Map<String, ExcelImportEntity> excelParams = new HashMap<>(); | |||||
| List<ExcelCollectionParams> excelCollection = new ArrayList<>(); | |||||
| String targetId = null; | String targetId = null; | ||||
| i18nHandler = params.getI18nHandler(); | i18nHandler = params.getI18nHandler(); | ||||
| boolean isMap = Map.class.equals(pojoClass); | boolean isMap = Map.class.equals(pojoClass); | ||||
| @@ -482,7 +482,7 @@ public class ExcelImportService extends ImportBaseService { | |||||
| importResult.setWorkbook(removeSuperfluousRows(successBook, failRow, params)); | importResult.setWorkbook(removeSuperfluousRows(successBook, failRow, params)); | ||||
| importResult.setFailWorkbook(removeSuperfluousRows(book, successRow, params)); | importResult.setFailWorkbook(removeSuperfluousRows(book, successRow, params)); | ||||
| } else { | } else { | ||||
| importResult.setWorkbook(successBook); | |||||
| importResult.setWorkbook(book); | |||||
| } | } | ||||
| importResult.setFailList(failCollection); | importResult.setFailList(failCollection); | ||||
| importResult.setVerifyFail(verifyFail); | importResult.setVerifyFail(verifyFail); | ||||
| @@ -70,6 +70,7 @@ public class ImportBaseService { | |||||
| excelEntity.setSaveType(excel.imageType()); | excelEntity.setSaveType(excel.imageType()); | ||||
| excelEntity.setReplace(excel.replace()); | excelEntity.setReplace(excel.replace()); | ||||
| excelEntity.setDatabaseFormat(excel.databaseFormat()); | excelEntity.setDatabaseFormat(excel.databaseFormat()); | ||||
| excelEntity.setPrefix(excel.prefix()); | |||||
| excelEntity.setSuffix(excel.suffix()); | excelEntity.setSuffix(excel.suffix()); | ||||
| excelEntity.setImportField(Boolean | excelEntity.setImportField(Boolean | ||||
| .valueOf(PoiPublicUtil.getValueByTargetId(excel.isImportField(), targetId, "false"))); | .valueOf(PoiPublicUtil.getValueByTargetId(excel.isImportField(), targetId, "false"))); | ||||
| @@ -55,7 +55,7 @@ public class SheetHandler extends DefaultHandler { | |||||
| private int curCol = 0; | private int curCol = 0; | ||||
| private CellValueType type; | private CellValueType type; | ||||
| private String currentLocation, prevLocation; | |||||
| private String currentLocation = "A_", prevLocation; | |||||
| private ISaxRowRead read; | private ISaxRowRead read; | ||||
| @@ -74,8 +74,13 @@ public class SheetHandler extends DefaultHandler { | |||||
| lastContents = ""; | lastContents = ""; | ||||
| if (COL.equals(name)) { | if (COL.equals(name)) { | ||||
| String cellType = attributes.getValue(TYPE); | String cellType = attributes.getValue(TYPE); | ||||
| prevLocation = currentLocation; | |||||
| currentLocation = attributes.getValue(ROW_COL); | |||||
| if ("A_".equalsIgnoreCase(currentLocation)) { | |||||
| currentLocation = attributes.getValue(ROW_COL); | |||||
| prevLocation = "A" + getRowCell(currentLocation)[1]; | |||||
| } else { | |||||
| prevLocation = currentLocation; | |||||
| currentLocation = attributes.getValue(ROW_COL); | |||||
| } | |||||
| if (STRING.equals(cellType)) { | if (STRING.equals(cellType)) { | ||||
| type = CellValueType.String; | type = CellValueType.String; | ||||
| return; | return; | ||||
| @@ -135,8 +140,9 @@ public class SheetHandler extends DefaultHandler { | |||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| } | } | ||||
| } | } | ||||
| if (VALUE.equals(name) && StringUtils.isNotEmpty(prevLocation)) { | |||||
| if ((COL.equals(name) || VALUE.equals(name)) && StringUtils.isNotEmpty(prevLocation)) { | |||||
| addNullCell(prevLocation, currentLocation); | addNullCell(prevLocation, currentLocation); | ||||
| prevLocation = currentLocation; | |||||
| } | } | ||||
| //t元素也包含字符串 | //t元素也包含字符串 | ||||
| if (CellValueType.TElement.equals(type)) { | if (CellValueType.TElement.equals(type)) { | ||||
| @@ -168,6 +174,7 @@ public class SheetHandler extends DefaultHandler { | |||||
| rowList.clear(); | rowList.clear(); | ||||
| curRow++; | curRow++; | ||||
| curCol = 0; | curCol = 0; | ||||
| currentLocation = "A_"; | |||||
| } | } | ||||
| } | } | ||||
| @@ -8,8 +8,8 @@ import java.util.HashMap; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| /** | /** | ||||
| * poi 4.0 07版本在 shift操作下有bug,不移动了单元格以及单元格样式,没有移动cell | |||||
| * cell还是复用的原理的cell,导致wb输出的时候没有输出值 | |||||
| * poi 4.0 07版本在 shift操作下有bug,只移动了单元格以及单元格样式,没有移动cell | |||||
| * cell还是复用的原来的cell,导致wb输出的时候没有输出值 | |||||
| * 等待修复的时候删除这个问题 | * 等待修复的时候删除这个问题 | ||||
| * | * | ||||
| * @author by jueyue on 19-6-17. | * @author by jueyue on 19-6-17. | ||||
| @@ -0,0 +1,193 @@ | |||||
| package cn.afterturn.easypoi.util; | |||||
| import cn.afterturn.easypoi.cache.manager.POICacheManager; | |||||
| import cn.afterturn.easypoi.exception.excel.ExcelExportException; | |||||
| import org.apache.poi.ooxml.POIXMLDocumentPart; | |||||
| import org.apache.poi.openxml4j.opc.OPCPackage; | |||||
| import org.apache.poi.openxml4j.opc.PackagePart; | |||||
| import org.apache.poi.openxml4j.opc.PackagePartName; | |||||
| import org.apache.poi.openxml4j.opc.PackagingURIHelper; | |||||
| import org.apache.poi.ss.usermodel.Footer; | |||||
| import org.apache.poi.ss.usermodel.Header; | |||||
| import org.apache.poi.ss.usermodel.Sheet; | |||||
| import org.apache.poi.ss.usermodel.Workbook; | |||||
| import org.apache.poi.ss.util.ImageUtils; | |||||
| import org.apache.poi.util.IOUtils; | |||||
| import org.apache.poi.xssf.usermodel.XSSFPictureData; | |||||
| import org.apache.poi.xssf.usermodel.XSSFRelation; | |||||
| import org.apache.poi.xssf.usermodel.XSSFSheet; | |||||
| import org.apache.poi.xssf.usermodel.XSSFWorkbook; | |||||
| import org.apache.xmlbeans.XmlObject; | |||||
| import java.io.ByteArrayInputStream; | |||||
| import java.io.IOException; | |||||
| import java.io.OutputStream; | |||||
| import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; | |||||
| /** | |||||
| * 水印工具类,WPS仅支持打印水印 | |||||
| * 参考 https://jingyan.baidu.com/article/6d704a137cd29d28db51ca87.html | |||||
| * | |||||
| * @author jueyue on 20-4-29. | |||||
| */ | |||||
| public class PoiWatermarkUtil { | |||||
| /** | |||||
| * 为Excel打上水印工具函数仅支持XLSX格式 | |||||
| * @param sheet 需要打水印的Excel | |||||
| * @param waterRemarkPath 水印地址,classPath,目前只支持png格式的图片, | |||||
| * <p> 因为非png格式的图片打到Excel上后可能会有图片变红的问题,且不容易做出透明效果。 <p> | |||||
| * @param position 位置 LEFT,CENTER,RIGHT | |||||
| * @throws IOException | |||||
| */ | |||||
| public static void putWaterRemarkToExcel(Sheet sheet, String waterRemarkPath, String position) throws Exception { | |||||
| int pictureIdx = sheet.getWorkbook().addPicture(IOUtils.toByteArray(POICacheManager.getFile(waterRemarkPath)), Workbook.PICTURE_TYPE_PNG); | |||||
| OPCPackage opcpackage = ((XSSFWorkbook) sheet.getWorkbook()).getPackage(); | |||||
| PackagePartName partname = PackagingURIHelper.createPartName("/xl/drawings/vmlDrawing" + pictureIdx + ".vml"); | |||||
| PackagePart part = opcpackage.createPart(partname, "application/vnd.openxmlformats-officedocument.vmlDrawing"); | |||||
| VmlDrawing vmldrawing = new VmlDrawing(part); | |||||
| //创建页眉,位置LEFT,下面headerPos填写对应的 | |||||
| Header header = sheet.getHeader(); | |||||
| switch (position){ | |||||
| case "LEFT": | |||||
| header.setLeft("&G"); | |||||
| vmldrawing.setHeaderPos("LH"); | |||||
| break; | |||||
| case "CENTER": | |||||
| header.setCenter("&G"); | |||||
| vmldrawing.setHeaderPos("CH"); | |||||
| break; | |||||
| case "RIGHT": | |||||
| header.setRight("&G"); | |||||
| vmldrawing.setHeaderPos("RH"); | |||||
| break; | |||||
| default: | |||||
| throw new ExcelExportException("输入的position参数不合法"); | |||||
| } | |||||
| XSSFPictureData picData = (XSSFPictureData) sheet.getWorkbook().getAllPictures().get(pictureIdx); | |||||
| String rIdPic = vmldrawing.addRelation(null, XSSFRelation.IMAGES, picData).getRelationship().getId(); | |||||
| ByteArrayInputStream is = new ByteArrayInputStream(picData.getData()); | |||||
| java.awt.Dimension imageDimension = ImageUtils.getImageDimension(is, picData.getPictureType()); | |||||
| IOUtils.closeQuietly(is); | |||||
| vmldrawing.setRIdPic(rIdPic); | |||||
| vmldrawing.setPictureTitle(waterRemarkPath); | |||||
| vmldrawing.setImageDimension(imageDimension); | |||||
| String rIdExtLink = ((XSSFSheet) sheet).addRelation(null, XSSFRelation.VML_DRAWINGS, vmldrawing).getRelationship().getId(); | |||||
| ((XSSFSheet) sheet).getCTWorksheet().addNewLegacyDrawingHF().setId(rIdExtLink); | |||||
| } | |||||
| /** | |||||
| * 为Excel打上水印工具函数仅支持XLSX格式 | |||||
| * @param sheet 需要打水印的Excel | |||||
| * @param waterRemarkPath 水印地址,classPath,目前只支持png格式的图片, | |||||
| * <p> 因为非png格式的图片打到Excel上后可能会有图片变红的问题,且不容易做出透明效果。 <p> | |||||
| * @throws IOException | |||||
| */ | |||||
| public static void putWaterRemarkToExcel(Sheet sheet, String waterRemarkPath) throws Exception { | |||||
| putWaterRemarkToExcel(sheet,waterRemarkPath,"LEFT"); | |||||
| } | |||||
| static class VmlDrawing extends POIXMLDocumentPart { | |||||
| String rIdPic = ""; | |||||
| String pictureTitle = ""; | |||||
| java.awt.Dimension imageDimension = null; | |||||
| String headerPos = ""; | |||||
| VmlDrawing(PackagePart part) { | |||||
| super(part); | |||||
| } | |||||
| void setRIdPic(String rIdPic) { | |||||
| this.rIdPic = rIdPic; | |||||
| } | |||||
| void setPictureTitle(String pictureTitle) { | |||||
| this.pictureTitle = pictureTitle; | |||||
| } | |||||
| void setHeaderPos(String headerPos) { | |||||
| this.headerPos = headerPos; | |||||
| } | |||||
| void setImageDimension(java.awt.Dimension imageDimension) { | |||||
| this.imageDimension = imageDimension; | |||||
| } | |||||
| @Override | |||||
| protected void commit() throws IOException { | |||||
| PackagePart part = getPackagePart(); | |||||
| OutputStream out = part.getOutputStream(); | |||||
| try { | |||||
| // WPS测试通过版本 | |||||
| /*XmlObject doc = XmlObject.Factory.parse( | |||||
| "<xml xmlns:oa=\"urn:schemas-microsoft-com:office:activation\"" + | |||||
| " xmlns:p=\"urn:schemas-microsoft-com:office:powerpoint\"" + | |||||
| " xmlns:x=\"urn:schemas-microsoft-com:office:excel\"" + | |||||
| " xmlns:o=\"urn:schemas-microsoft-com:office:office\"" + | |||||
| " xmlns:v=\"urn:schemas-microsoft-com:vml\">" + | |||||
| " <o:shapelayout v:ext=\"edit\">" + | |||||
| " <o:idmap v:ext=\"edit\" data=\"1\"/>" + | |||||
| " </o:shapelayout>" + | |||||
| " <v:shape id=\""+headerPos+"\" " + | |||||
| " o:spid=\"_x0000_s1028\" o:spt=\"75\" alt=\"" + pictureTitle + "\"" + | |||||
| " type=\"#_x0000_t75\"" + | |||||
| " style=\"position:absolute;left:0pt;top:0pt;margin-left:0pt;margin-top:0pt;height:" + (int) imageDimension.getHeight() + "pt;width:" + (int) imageDimension.getWidth() + "pt;\"" + | |||||
| " filled=\"f\" o:preferrelative=\"t\" stroked=\"f\" coordsize=\"21600,21600\">" + | |||||
| " <v:path/>" + | |||||
| " <v:fill on=\"f\" focussize=\"0,0\"/>" + | |||||
| " <v:stroke on=\"f\"/>" + | |||||
| " <v:imagedata o:relid=\"" + rIdPic + "\" o:title=\"" + pictureTitle + "\"/>" + | |||||
| " <o:lock v:ext=\"edit\" rotation=\"t\" aspectratio=\"t\"/>" + | |||||
| " </v:shape>" + | |||||
| "</xml>" | |||||
| );*/ | |||||
| XmlObject doc = XmlObject.Factory.parse( | |||||
| "<xml xmlns:v=\"urn:schemas-microsoft-com:vml\"" | |||||
| + " xmlns:o=\"urn:schemas-microsoft-com:office:office\"" | |||||
| + " xmlns:x=\"urn:schemas-microsoft-com:office:excel\">" | |||||
| + " <o:shapelayout v:ext=\"edit\">" | |||||
| + " <o:idmap v:ext=\"edit\" data=\"1\"/>" | |||||
| + " </o:shapelayout><v:shapetype id=\"_x0000_t75\" coordsize=\"21600,21600\" o:spt=\"75\"" | |||||
| + " o:preferrelative=\"t\" path=\"m@4@5l@4@11@9@11@9@5xe\" filled=\"f\" stroked=\"f\">" | |||||
| + " <v:stroke joinstyle=\"miter\"/>" | |||||
| + " <v:formulas>" | |||||
| + " <v:f eqn=\"if lineDrawn pixelLineWidth 0\"/>" | |||||
| + " <v:f eqn=\"sum @0 1 0\"/>" | |||||
| + " <v:f eqn=\"sum 0 0 @1\"/>" | |||||
| + " <v:f eqn=\"prod @2 1 2\"/>" | |||||
| + " <v:f eqn=\"prod @3 21600 pixelWidth\"/>" | |||||
| + " <v:f eqn=\"prod @3 21600 pixelHeight\"/>" | |||||
| + " <v:f eqn=\"sum @0 0 1\"/>" | |||||
| + " <v:f eqn=\"prod @6 1 2\"/>" | |||||
| + " <v:f eqn=\"prod @7 21600 pixelWidth\"/>" | |||||
| + " <v:f eqn=\"sum @8 21600 0\"/>" | |||||
| + " <v:f eqn=\"prod @7 21600 pixelHeight\"/>" | |||||
| + " <v:f eqn=\"sum @10 21600 0\"/>" | |||||
| + " </v:formulas>" | |||||
| + " <v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\"/>" | |||||
| + " <o:lock v:ext=\"edit\" aspectratio=\"t\"/>" | |||||
| + " </v:shapetype><v:shape id=\"" + headerPos + "\" o:spid=\"_x0000_s1025\" type=\"#_x0000_t75\"" | |||||
| + " style='position:absolute;margin-left:0;margin-top:0;" | |||||
| + "width:" + (int) imageDimension.getWidth() + "px;height:" + (int) imageDimension.getHeight() + "px;" | |||||
| + "z-index:1'>" | |||||
| + " <v:imagedata o:relid=\"" + rIdPic + "\" o:title=\"" + pictureTitle + "\"/>" | |||||
| + " <o:lock v:ext=\"edit\" rotation=\"t\"/>" | |||||
| + " </v:shape></xml>" | |||||
| ); | |||||
| doc.save(out, DEFAULT_XML_OPTIONS); | |||||
| out.close(); | |||||
| } catch (Exception ex) { | |||||
| ex.printStackTrace(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -4,7 +4,7 @@ | |||||
| <parent> | <parent> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi</artifactId> | <artifactId>easypoi</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0.A</version> | |||||
| </parent> | </parent> | ||||
| <artifactId>easypoi-web</artifactId> | <artifactId>easypoi-web</artifactId> | ||||
| <dependencies> | <dependencies> | ||||
| @@ -0,0 +1,54 @@ | |||||
| <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||||
| <modelVersion>4.0.0</modelVersion> | |||||
| <parent> | |||||
| <groupId>cn.afterturn</groupId> | |||||
| <artifactId>easypoi</artifactId> | |||||
| <version>4.2.0</version> | |||||
| </parent> | |||||
| <artifactId>easypoi-wps</artifactId> | |||||
| <dependencies> | |||||
| <!--spring --> | |||||
| <dependency> | |||||
| <groupId>org.springframework</groupId> | |||||
| <artifactId>spring-web</artifactId> | |||||
| <scope>compile</scope> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>org.springframework</groupId> | |||||
| <artifactId>spring-webmvc</artifactId> | |||||
| <scope>compile</scope> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>org.springframework</groupId> | |||||
| <artifactId>spring-context</artifactId> | |||||
| <scope>compile</scope> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>org.springframework</groupId> | |||||
| <artifactId>spring-core</artifactId> | |||||
| <scope>compile</scope> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>org.springframework</groupId> | |||||
| <artifactId>spring-beans</artifactId> | |||||
| <scope>compile</scope> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>javax.servlet</groupId> | |||||
| <artifactId>servlet-api</artifactId> | |||||
| <scope>provided</scope> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>cn.afterturn</groupId> | |||||
| <artifactId>easypoi-base</artifactId> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>org.projectlombok</groupId> | |||||
| <artifactId>lombok</artifactId> | |||||
| <version>1.16.20</version> | |||||
| <scope>provided</scope> | |||||
| </dependency> | |||||
| </dependencies> | |||||
| </project> | |||||
| @@ -0,0 +1,136 @@ | |||||
| package cn.afterturn.easypoi.wps.controller; | |||||
| import cn.afterturn.easypoi.wps.entity.WpsToken; | |||||
| import cn.afterturn.easypoi.wps.entity.resreq.*; | |||||
| import cn.afterturn.easypoi.wps.service.IEasyPoiWpsService; | |||||
| import org.slf4j.Logger; | |||||
| import org.slf4j.LoggerFactory; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | |||||
| import org.springframework.web.bind.annotation.*; | |||||
| import org.springframework.web.multipart.MultipartFile; | |||||
| import javax.servlet.http.HttpServletRequest; | |||||
| import java.io.UnsupportedEncodingException; | |||||
| import java.net.URLDecoder; | |||||
| import java.util.Map; | |||||
| /** | |||||
| * @author jueyue on 20-5-7. | |||||
| */ | |||||
| @RestController | |||||
| @RequestMapping("easypoi/wps/v1/3rd/file") | |||||
| public class EasyPoiFileController { | |||||
| private static final Logger LOGGER = LoggerFactory.getLogger(EasyPoiFileController.class); | |||||
| @Autowired(required = false) | |||||
| private IEasyPoiWpsService easyPoiWpsService; | |||||
| /** | |||||
| * 获取网络文件预览URL | |||||
| * | |||||
| * @param filePath | |||||
| * @return t | |||||
| */ | |||||
| @GetMapping("getViewUrl") | |||||
| public WpsToken getViewUrl(String filePath) { | |||||
| LOGGER.info("getViewUrlWebPath:filePath={}", filePath); | |||||
| WpsToken token = easyPoiWpsService.getViewUrl(decode(filePath)); | |||||
| return token; | |||||
| } | |||||
| /** | |||||
| * 获取文件元数据 | |||||
| */ | |||||
| @GetMapping("info") | |||||
| public WpsFileResponse getFileInfo(HttpServletRequest request, @RequestParam(value = "_w_userid", required = false) String userId, | |||||
| @RequestParam("_w_filepath") String filePath) { | |||||
| LOGGER.info("获取文件元数据userId:{},path:{}", userId, filePath); | |||||
| String fileId = request.getHeader("x-weboffice-file-id"); | |||||
| WpsFileResponse fileResponse = easyPoiWpsService.getFileInfo(userId, decode(filePath), fileId); | |||||
| return fileResponse; | |||||
| } | |||||
| /** | |||||
| * 通知此文件目前有哪些人正在协作 | |||||
| */ | |||||
| @PostMapping("online") | |||||
| public WpsResponse fileOnline(HttpServletRequest request, @RequestBody WpsUserRequest list) { | |||||
| LOGGER.info("通知此文件目前有哪些人正在协作param:{}", list); | |||||
| String fileId = request.getHeader("x-weboffice-file-id"); | |||||
| easyPoiWpsService.fileOnline(fileId, list); | |||||
| return WpsResponse.success(); | |||||
| } | |||||
| /** | |||||
| * 上传文件新版本 | |||||
| */ | |||||
| @PostMapping("save") | |||||
| public WpsFileSaveResponse fileSave(HttpServletRequest request, | |||||
| @RequestParam(value = "_w_userid", required = false) String userId, | |||||
| @RequestBody MultipartFile file) { | |||||
| LOGGER.info("上传文件新版本"); | |||||
| String fileId = request.getHeader("x-weboffice-file-id"); | |||||
| return new WpsFileSaveResponse(easyPoiWpsService.fileSave(fileId, userId, file)); | |||||
| } | |||||
| /** | |||||
| * 获取特定版本的文件信息 | |||||
| */ | |||||
| @GetMapping("version/{version}") | |||||
| public WpsFileSaveResponse fileVersion(HttpServletRequest request, @PathVariable Integer version, | |||||
| @RequestParam("_w_filepath") String filePath) { | |||||
| LOGGER.info("获取特定版本的文件信息version:{}", version); | |||||
| String fileId = request.getHeader("x-weboffice-file-id"); | |||||
| return new WpsFileSaveResponse(easyPoiWpsService.getFileInfoOfVersion(fileId, decode(filePath), version)); | |||||
| } | |||||
| /** | |||||
| * 文件重命名 | |||||
| */ | |||||
| @PutMapping("rename") | |||||
| public WpsResponse fileRename(HttpServletRequest request, @RequestBody WpsRenameRequest req, | |||||
| @RequestParam(value = "_w_userid", required = false) String userId) { | |||||
| LOGGER.info("文件重命名param:{},userId:{}", req, userId); | |||||
| String fileId = request.getHeader("x-weboffice-file-id"); | |||||
| easyPoiWpsService.rename(fileId, userId, req.getName()); | |||||
| return WpsResponse.success(); | |||||
| } | |||||
| /** | |||||
| * 获取所有历史版本文件信息 | |||||
| */ | |||||
| @PostMapping("history") | |||||
| public WpsFileHistoryResponse fileHistory(@RequestBody WpsFileHistoryRequest req) { | |||||
| LOGGER.info("获取所有历史版本文件信息param:{}", req); | |||||
| return easyPoiWpsService.getHistory(req); | |||||
| } | |||||
| /** | |||||
| * 新建文件 | |||||
| */ | |||||
| @PostMapping("new") | |||||
| public WpsResponse fileNew(@RequestBody MultipartFile file, @RequestParam(value = "_w_userid", required = false) String userId) { | |||||
| LOGGER.info("新建文件,只打印不实现,userid:{}", userId); | |||||
| return WpsResponse.success(); | |||||
| } | |||||
| /** | |||||
| * 回调通知 | |||||
| */ | |||||
| @PostMapping("onnotify") | |||||
| public WpsResponse onNotify(@RequestBody Map obj) { | |||||
| LOGGER.info("回调通知,只打印不实现,param:{}", obj); | |||||
| return WpsResponse.success(); | |||||
| } | |||||
| public String decode(String filePath) { | |||||
| try { | |||||
| filePath = URLDecoder.decode(filePath, "UTF-8"); | |||||
| } catch (UnsupportedEncodingException e) { | |||||
| LOGGER.error(e.getMessage(), e); | |||||
| } | |||||
| return filePath; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,43 @@ | |||||
| package cn.afterturn.easypoi.wps.controller; | |||||
| import cn.afterturn.easypoi.wps.entity.WpsUserEntity; | |||||
| import cn.afterturn.easypoi.wps.entity.resreq.WpsUserRequest; | |||||
| import cn.afterturn.easypoi.wps.entity.resreq.WpsUserResponse; | |||||
| import cn.afterturn.easypoi.wps.service.IEasyPoiWpsUserService; | |||||
| import org.slf4j.Logger; | |||||
| import org.slf4j.LoggerFactory; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | |||||
| import org.springframework.web.bind.annotation.PostMapping; | |||||
| import org.springframework.web.bind.annotation.RequestBody; | |||||
| import org.springframework.web.bind.annotation.RequestMapping; | |||||
| import org.springframework.web.bind.annotation.RestController; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @RestController | |||||
| @RequestMapping("easypoi/wps/v1/3rd/file") | |||||
| public class EasyPoiUserController { | |||||
| private static final Logger LOGGER = LoggerFactory.getLogger(EasyPoiUserController.class); | |||||
| @Autowired(required = false) | |||||
| private IEasyPoiWpsUserService userService; | |||||
| /** | |||||
| * 获取用户信息 | |||||
| */ | |||||
| @PostMapping("info") | |||||
| public WpsUserResponse userInfo(@RequestBody WpsUserRequest list) { | |||||
| LOGGER.info("获取用户信息param:{}", list); | |||||
| WpsUserResponse response = new WpsUserResponse(); | |||||
| for (int i = 0; i < list.getIds().size(); i++) { | |||||
| if (userService != null) { | |||||
| response.getUsers().add(userService.getUser(list.getIds().get(i))); | |||||
| } else { | |||||
| response.getUsers().add(new WpsUserEntity()); | |||||
| } | |||||
| } | |||||
| return response; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,48 @@ | |||||
| package cn.afterturn.easypoi.wps.entity; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsFileEntity implements Serializable { | |||||
| /** | |||||
| * 文件id,字符串长度小于40 | |||||
| */ | |||||
| private String id; | |||||
| /** | |||||
| * 文件名 | |||||
| */ | |||||
| private String name; | |||||
| /** | |||||
| * 当前版本号,位数小于11 | |||||
| */ | |||||
| private int version = 1; | |||||
| /** | |||||
| * 文件大小,单位为kb | |||||
| */ | |||||
| private int size; | |||||
| /** | |||||
| * 创建者id,字符串长度小于40 | |||||
| */ | |||||
| private String creator = "0"; | |||||
| /** | |||||
| * 修改者id,字符串长度小于40 | |||||
| */ | |||||
| private String modifier; | |||||
| /** | |||||
| * 创建时间,时间戳,单位为秒 | |||||
| */ | |||||
| private long create_time = System.currentTimeMillis(); | |||||
| /** | |||||
| * 修改时间,时间戳,单位为秒 | |||||
| */ | |||||
| private long modify_time; | |||||
| private String download_url; | |||||
| private WpsUserAclEntity user_acl = new WpsUserAclEntity(); | |||||
| private WpsWatermarkEntity watermark = new WpsWatermarkEntity(); | |||||
| } | |||||
| @@ -0,0 +1,40 @@ | |||||
| package cn.afterturn.easypoi.wps.entity; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsFileHistoryEntity implements Serializable { | |||||
| /** | |||||
| * 文件id,字符串长度小于40 | |||||
| */ | |||||
| private String id; | |||||
| /** | |||||
| * 文件名 | |||||
| */ | |||||
| private String name; | |||||
| /** | |||||
| * 当前版本号,位数小于11 | |||||
| */ | |||||
| private int version = 1; | |||||
| /** | |||||
| * 文件大小,单位为kb | |||||
| */ | |||||
| private int size; | |||||
| /** | |||||
| * 创建时间,时间戳,单位为秒 | |||||
| */ | |||||
| private long create_time; | |||||
| /** | |||||
| * 修改时间,时间戳,单位为秒 | |||||
| */ | |||||
| private long modify_time; | |||||
| private WpsUserEntity creator; | |||||
| private WpsUserEntity modifier; | |||||
| } | |||||
| @@ -0,0 +1,19 @@ | |||||
| package cn.afterturn.easypoi.wps.entity; | |||||
| import cn.afterturn.easypoi.wps.entity.resreq.WpsResponse; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * @author JueYue | |||||
| * 界面的Token数据,默认不使用 | |||||
| */ | |||||
| @Data | |||||
| public class WpsToken extends WpsResponse implements Serializable { | |||||
| private int expires_in; | |||||
| private String token; | |||||
| private String wpsUrl; | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| package cn.afterturn.easypoi.wps.entity; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsUserAclEntity implements Serializable { | |||||
| /** | |||||
| * 重命名权限,1为打开该权限,0为关闭该权限,默认为0 | |||||
| */ | |||||
| private Integer rename = 0; | |||||
| /** | |||||
| * 历史版本权限,1为打开该权限,0为关闭该权限,默认为1 | |||||
| */ | |||||
| private Integer history = 0; | |||||
| /** | |||||
| * 复制 | |||||
| */ | |||||
| private Integer copy = 1; | |||||
| /** | |||||
| * 导出PDF | |||||
| */ | |||||
| private Integer export = 1; | |||||
| private Integer print = 1; | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| package cn.afterturn.easypoi.wps.entity; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * @author jueyue on 20-5-7. | |||||
| */ | |||||
| @Data | |||||
| public class WpsUserEntity implements Serializable { | |||||
| /** | |||||
| * 用户id,长度小于40 | |||||
| */ | |||||
| private String id = "0"; | |||||
| /** | |||||
| * 用户名称 | |||||
| */ | |||||
| private String name = "悟耘-EasyPoi"; | |||||
| /** | |||||
| * 用户操作权限,write:可编辑,read:预览 | |||||
| */ | |||||
| private String permission = "read"; | |||||
| /** | |||||
| * 用户头像地址 | |||||
| */ | |||||
| private String avatar_url = "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=50688014,2596832035&fm=11&gp=0.jpg"; | |||||
| } | |||||
| @@ -0,0 +1,45 @@ | |||||
| package cn.afterturn.easypoi.wps.entity; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * 水印配置 | |||||
| * | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsWatermarkEntity implements Serializable { | |||||
| /** | |||||
| * 水印类型, 0为无水印; 1为文字水印 | |||||
| */ | |||||
| private Integer type = 0; | |||||
| /** | |||||
| * 文字水印的文字,当type为1时此字段必选 | |||||
| */ | |||||
| private Integer value; | |||||
| /** | |||||
| * 水印的透明度,非必选,有默认值 | |||||
| * "rgba( 192, 192, 192, 0.6 )" | |||||
| */ | |||||
| private Integer fillstyle; | |||||
| /** | |||||
| * 水印的字体,非必选,有默认值 | |||||
| * "bold 20px Serif" | |||||
| */ | |||||
| private Integer font; | |||||
| /** | |||||
| * 水印的旋转度,非必选,有默认值 | |||||
| * -0.7853982 | |||||
| */ | |||||
| private String rotate; | |||||
| /** | |||||
| * 水印水平间距,非必选,有默认值 | |||||
| */ | |||||
| private Integer horizontal; | |||||
| /** | |||||
| * 水印垂直间距,非必选,有默认值 | |||||
| */ | |||||
| private Integer vertical; | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| package cn.afterturn.easypoi.wps.entity.resreq; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsFileHistoryRequest extends WpsResponse implements Serializable { | |||||
| private String id; | |||||
| private int offset; | |||||
| private int count; | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| package cn.afterturn.easypoi.wps.entity.resreq; | |||||
| import cn.afterturn.easypoi.wps.entity.WpsFileHistoryEntity; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| import java.util.List; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsFileHistoryResponse extends WpsResponse implements Serializable { | |||||
| private List<WpsFileHistoryEntity> histories; | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| package cn.afterturn.easypoi.wps.entity.resreq; | |||||
| import cn.afterturn.easypoi.wps.entity.WpsFileEntity; | |||||
| import cn.afterturn.easypoi.wps.entity.WpsUserEntity; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * 获取文件返回对象 | |||||
| * | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsFileResponse extends WpsResponse implements Serializable { | |||||
| private WpsFileEntity file; | |||||
| private WpsUserEntity user = new WpsUserEntity(); | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| package cn.afterturn.easypoi.wps.entity.resreq; | |||||
| import cn.afterturn.easypoi.wps.entity.WpsFileEntity; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsFileSaveResponse extends WpsResponse implements Serializable { | |||||
| public WpsFileSaveResponse() { | |||||
| } | |||||
| public WpsFileSaveResponse(WpsFileEntity file) { | |||||
| this.file = file; | |||||
| } | |||||
| private WpsFileEntity file; | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| package cn.afterturn.easypoi.wps.entity.resreq; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsRenameRequest extends WpsResponse implements Serializable { | |||||
| private String name; | |||||
| } | |||||
| @@ -0,0 +1,21 @@ | |||||
| package cn.afterturn.easypoi.wps.entity.resreq; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsResponse implements Serializable { | |||||
| private int code = 200; | |||||
| private String msg; | |||||
| private String status = "success"; | |||||
| public static WpsResponse success() { | |||||
| return new WpsResponse(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| package cn.afterturn.easypoi.wps.entity.resreq; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| import java.util.List; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsUserRequest implements Serializable { | |||||
| List<String> ids; | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| package cn.afterturn.easypoi.wps.entity.resreq; | |||||
| import cn.afterturn.easypoi.wps.entity.WpsUserEntity; | |||||
| import lombok.Data; | |||||
| import java.io.Serializable; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| @Data | |||||
| public class WpsUserResponse extends WpsResponse implements Serializable { | |||||
| private List<WpsUserEntity> users = new ArrayList<>(); | |||||
| } | |||||
| @@ -0,0 +1,85 @@ | |||||
| package cn.afterturn.easypoi.wps.service; | |||||
| /** | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| public class EasyPoiWpsFileUtil { | |||||
| private static String[] OFFICE = {"word", "excel", "ppt"}; | |||||
| private static String[] EXCEL_EXTS = {"et", "xls", "xlt", "xlsx", "xlsm", "xltx", "xltm", "csv"}; | |||||
| private static String[] WORD_EXTS = {"doc", "docx", "txt", "dot", "wps", "wpt", "dotx", "docm", "dotm"}; | |||||
| private static String[] PPT_EXTS = {"ppt", "pptx", "pptm", "pptm", "ppsm", "pps", "potx", "potm", "dpt", "dps"}; | |||||
| private static String[] PDF_EXTS = {"pdf"}; | |||||
| public static String getFileTypeCode(String fileType) { | |||||
| for (String et : EXCEL_EXTS) { | |||||
| if (et.equalsIgnoreCase(fileType)) { | |||||
| return "s"; | |||||
| } | |||||
| } | |||||
| for (String et : WORD_EXTS) { | |||||
| if (et.equalsIgnoreCase(fileType)) { | |||||
| return "w"; | |||||
| } | |||||
| } | |||||
| for (String et : PPT_EXTS) { | |||||
| if (et.equalsIgnoreCase(fileType)) { | |||||
| return "p"; | |||||
| } | |||||
| } | |||||
| for (String et : PDF_EXTS) { | |||||
| if (et.equalsIgnoreCase(fileType)) { | |||||
| return "f"; | |||||
| } | |||||
| } | |||||
| return null; | |||||
| } | |||||
| public static boolean checkCode(String fileType) { | |||||
| for (String et : OFFICE) { | |||||
| if (et.equalsIgnoreCase(fileType)) { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| public static String getTypeCode(String fileType) { | |||||
| if ("word".equalsIgnoreCase(fileType)) { | |||||
| return "w"; | |||||
| } | |||||
| if ("excel".equalsIgnoreCase(fileType)) { | |||||
| return "s"; | |||||
| } | |||||
| if ("ppt".equalsIgnoreCase(fileType)) { | |||||
| return "p"; | |||||
| } | |||||
| return null; | |||||
| } | |||||
| public static String getFileName(String filePath) { | |||||
| String[] pathArr = filePath.split("/"); | |||||
| String fileName; | |||||
| if (pathArr.length > 1) { | |||||
| fileName = pathArr[pathArr.length - 1]; | |||||
| } else { | |||||
| fileName = filePath; | |||||
| } | |||||
| return fileName; | |||||
| } | |||||
| public static String getFileTypeByPath(String filePath) { | |||||
| String fileName = getFileName(filePath); | |||||
| String[] arr = fileName.split("\\."); | |||||
| return arr[arr.length - 1]; | |||||
| } | |||||
| public static String getFileTypeByName(String fileName) { | |||||
| String[] arr = fileName.split("\\."); | |||||
| return arr[arr.length - 1]; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,92 @@ | |||||
| package cn.afterturn.easypoi.wps.service; | |||||
| import org.apache.commons.codec.digest.HmacUtils; | |||||
| import java.io.UnsupportedEncodingException; | |||||
| import java.net.URLEncoder; | |||||
| import java.util.ArrayList; | |||||
| import java.util.HashMap; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import static org.apache.commons.codec.binary.Base64.encodeBase64String; | |||||
| /** | |||||
| * Wps相关的工具类 | |||||
| * | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| public class EasyPoiWpsUtil { | |||||
| public static String getKeyValueStr(Map<String, String> params) { | |||||
| List<String> keys = new ArrayList<String>() { | |||||
| { | |||||
| for (Map.Entry<String, String> entry : params.entrySet()) { | |||||
| add(entry.getKey()); | |||||
| } | |||||
| } | |||||
| }; | |||||
| StringBuilder sb = new StringBuilder(); | |||||
| for (String key : keys) { | |||||
| String value = params.get(key) + "&"; | |||||
| sb.append(key).append("=").append(value); | |||||
| } | |||||
| return sb.toString(); | |||||
| } | |||||
| public static String getSignature(Map<String, String> params, String appSecret) { | |||||
| List<String> keys = new ArrayList<String>() { | |||||
| { | |||||
| for (Map.Entry<String, String> entry : params.entrySet()) { | |||||
| add(entry.getKey()); | |||||
| } | |||||
| } | |||||
| }; | |||||
| // 将所有参数按key的升序排序 | |||||
| keys.sort(String::compareTo); | |||||
| // 构造签名的源字符串 | |||||
| StringBuilder contents = new StringBuilder(); | |||||
| for (String key : keys) { | |||||
| if (key.equals("_w_signature")) { | |||||
| continue; | |||||
| } | |||||
| contents.append(key).append("=").append(params.get(key)); | |||||
| } | |||||
| contents.append("_w_secretkey=").append(appSecret); | |||||
| // 进行hmac sha1 签名 | |||||
| byte[] bytes = HmacUtils.hmacSha1(appSecret.getBytes(), contents.toString().getBytes()); | |||||
| //字符串经过Base64编码 | |||||
| String sign = encodeBase64String(bytes); | |||||
| try { | |||||
| return URLEncoder.encode(sign, "UTF-8"); | |||||
| } catch (UnsupportedEncodingException e) { | |||||
| e.printStackTrace(); | |||||
| return null; | |||||
| } | |||||
| } | |||||
| public Map<String, String> paramToMap(String paramStr) { | |||||
| String[] params = paramStr.split("&"); | |||||
| return new HashMap<String, String>() { | |||||
| { | |||||
| for (String param1 : params) { | |||||
| String[] param = param1.split("="); | |||||
| if (param.length >= 2) { | |||||
| String key = param[0]; | |||||
| StringBuilder value = new StringBuilder(param[1]); | |||||
| for (int j = 2; j < param.length; j++) { | |||||
| value.append("=").append(param[j]); | |||||
| } | |||||
| put(key, value.toString()); | |||||
| } | |||||
| } | |||||
| } | |||||
| }; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,216 @@ | |||||
| package cn.afterturn.easypoi.wps.service; | |||||
| import cn.afterturn.easypoi.wps.entity.WpsFileEntity; | |||||
| import cn.afterturn.easypoi.wps.entity.WpsToken; | |||||
| import cn.afterturn.easypoi.wps.entity.resreq.WpsFileHistoryRequest; | |||||
| import cn.afterturn.easypoi.wps.entity.resreq.WpsFileHistoryResponse; | |||||
| import cn.afterturn.easypoi.wps.entity.resreq.WpsFileResponse; | |||||
| import cn.afterturn.easypoi.wps.entity.resreq.WpsUserRequest; | |||||
| import org.springframework.web.multipart.MultipartFile; | |||||
| import sun.reflect.generics.reflectiveObjects.NotImplementedException; | |||||
| import java.util.HashMap; | |||||
| import java.util.Map; | |||||
| import java.util.UUID; | |||||
| /** | |||||
| * 获取 | |||||
| * | |||||
| * @author jueyue on 20-5-7. | |||||
| */ | |||||
| public interface IEasyPoiWpsService { | |||||
| /** | |||||
| * 获取Wps的地址 | |||||
| * | |||||
| * @param filePath | |||||
| * @return | |||||
| */ | |||||
| default WpsToken getViewUrl(String filePath) { | |||||
| WpsToken t = new WpsToken(); | |||||
| Map<String, String> values = new HashMap<String, String>() { | |||||
| { | |||||
| put("_w_appid", getAppId()); | |||||
| put("_w_userid", getUserId()); | |||||
| put("_w_filepath", filePath); | |||||
| } | |||||
| }; | |||||
| String keyValueStr = EasyPoiWpsUtil.getKeyValueStr(values); | |||||
| String signature = EasyPoiWpsUtil.getSignature(values, getAppSecret()); | |||||
| String fileTypeCode = EasyPoiWpsFileUtil.getFileTypeCode(EasyPoiWpsFileUtil.getFileTypeByPath(filePath)); | |||||
| String wpsUrl = getDomain() + fileTypeCode + "/" + getFileId(filePath) + "?" | |||||
| + keyValueStr + "_w_signature=" + signature; | |||||
| t.setToken(getToken()); | |||||
| t.setExpires_in(600); | |||||
| t.setWpsUrl(wpsUrl); | |||||
| return t; | |||||
| } | |||||
| /** | |||||
| * 获取用户Token有必要可以带上 | |||||
| * | |||||
| * @return | |||||
| */ | |||||
| default String getToken() { | |||||
| return UUID.randomUUID().toString().replace("-", ""); | |||||
| } | |||||
| /** | |||||
| * 获取文件ID,如果filePath可以现实没必要,如果使用ID请实现 | |||||
| * | |||||
| * @param filePath | |||||
| * @return | |||||
| */ | |||||
| default String getFileId(String filePath) { | |||||
| return UUID.randomUUID().toString().replace("-", ""); | |||||
| } | |||||
| /** | |||||
| * WPS路径 | |||||
| * | |||||
| * @return | |||||
| */ | |||||
| default String getDomain() { | |||||
| return "https://wwo.wps.cn/office/"; | |||||
| } | |||||
| /** | |||||
| * APP秘钥 | |||||
| * | |||||
| * @return | |||||
| */ | |||||
| String getAppSecret(); | |||||
| /** | |||||
| * 获取WPS配置的AppId | |||||
| * | |||||
| * @return | |||||
| */ | |||||
| String getAppId(); | |||||
| /** | |||||
| * 获取当前用户ID,如果不权限校验可以不实现 | |||||
| * | |||||
| * @return | |||||
| */ | |||||
| default String getUserId() { | |||||
| return "0"; | |||||
| } | |||||
| /** | |||||
| * 获取文件信息 | |||||
| * | |||||
| * @param userId | |||||
| * @param filepath | |||||
| * @param fileId | |||||
| * @return 返回文件信息 | |||||
| */ | |||||
| default WpsFileResponse getFileInfo(String userId, String filepath, String fileId) { | |||||
| WpsFileResponse response = new WpsFileResponse(); | |||||
| WpsFileEntity fileEntity = new WpsFileEntity(); | |||||
| fileEntity.setId(fileId); | |||||
| fileEntity.setName(getFileName(filepath)); | |||||
| fileEntity.setSize(getFileSize(filepath)); | |||||
| fileEntity.setDownload_url(getDownLoadUrl(filepath)); | |||||
| response.setFile(fileEntity); | |||||
| return response; | |||||
| } | |||||
| /** | |||||
| * 单位为B | |||||
| * | |||||
| * @param filepath | |||||
| * @return | |||||
| */ | |||||
| int getFileSize(String filepath); | |||||
| /** | |||||
| * 获取文件的下载路径 | |||||
| * | |||||
| * @param filepath | |||||
| * @return | |||||
| */ | |||||
| String getDownLoadUrl(String filepath); | |||||
| /** | |||||
| * 获取文件名称 -中文或者英文 | |||||
| * | |||||
| * @param filepath | |||||
| * @return | |||||
| */ | |||||
| default String getFileName(String filepath) { | |||||
| return EasyPoiWpsFileUtil.getFileName(filepath); | |||||
| } | |||||
| /** | |||||
| * 文件被那些客户协作 | |||||
| * | |||||
| * @param fileId | |||||
| * @param list | |||||
| */ | |||||
| default void fileOnline(String fileId, WpsUserRequest list) { | |||||
| } | |||||
| /** | |||||
| * 保存文件 | |||||
| * | |||||
| * @param fileId | |||||
| * @param userId | |||||
| * @param file | |||||
| * @return | |||||
| */ | |||||
| default WpsFileEntity fileSave(String fileId, String userId, MultipartFile file) { | |||||
| throw new NotImplementedException(); | |||||
| } | |||||
| /** | |||||
| * 获取特定版本的文件 | |||||
| * | |||||
| * @param fileId | |||||
| * @param filepath | |||||
| * @param version | |||||
| * @return | |||||
| */ | |||||
| default WpsFileEntity getFileInfoOfVersion(String fileId, String filepath, Integer version) { | |||||
| WpsFileEntity fileEntity = new WpsFileEntity(); | |||||
| fileEntity.setId(fileId); | |||||
| fileEntity.setName(getFileName(filepath)); | |||||
| fileEntity.setDownload_url(getDownLoadUrl(filepath, version)); | |||||
| fileEntity.setModifier(fileEntity.getModifier()); | |||||
| fileEntity.setModify_time(System.currentTimeMillis()); | |||||
| return fileEntity; | |||||
| } | |||||
| /** | |||||
| * 获取特定版本的URL | |||||
| * | |||||
| * @param filepath | |||||
| * @param version | |||||
| * @return | |||||
| */ | |||||
| default String getDownLoadUrl(String filepath, Integer version) { | |||||
| throw new NotImplementedException(); | |||||
| } | |||||
| /** | |||||
| * 文件重命名 | |||||
| * | |||||
| * @param fileId | |||||
| * @param userId | |||||
| * @param name | |||||
| */ | |||||
| default void rename(String fileId, String userId, String name) { | |||||
| throw new NotImplementedException(); | |||||
| } | |||||
| /** | |||||
| * 获取文件历史版本 | |||||
| * | |||||
| * @param req | |||||
| * @return | |||||
| */ | |||||
| default WpsFileHistoryResponse getHistory(WpsFileHistoryRequest req) { | |||||
| throw new NotImplementedException(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,19 @@ | |||||
| package cn.afterturn.easypoi.wps.service; | |||||
| import cn.afterturn.easypoi.wps.entity.WpsUserEntity; | |||||
| /** | |||||
| * 用户服务 | |||||
| * | |||||
| * @author jueyue on 20-5-8. | |||||
| */ | |||||
| public interface IEasyPoiWpsUserService { | |||||
| /** | |||||
| * 获取用户信息 | |||||
| * | |||||
| * @param userId | |||||
| * @return | |||||
| */ | |||||
| WpsUserEntity getUser(String userId); | |||||
| } | |||||
| @@ -0,0 +1,38 @@ | |||||
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>预览</title> | |||||
| <script src="/easypoijs/jquery-1.9.1.min.js"></script> | |||||
| <script src="/easypoijs/polyfill.min.js"></script> | |||||
| <script src="/easypoijs/web-office-sdk-v1.1.2.umd.js"></script> | |||||
| <script> | |||||
| $(document).ready(function () { | |||||
| let filePath = getUrlParam('filePath'); | |||||
| $.get('v1/3rd/file/getViewUrl?filePath=' + filePath, function (data) { | |||||
| let easyWps = WebOfficeSDK.config({ | |||||
| mode: 'simple', | |||||
| url: data.wpsUrl, // 如果需要通过js-sdk传递token方式鉴权,则需要包含_w_tokentype=1参数 | |||||
| //mount: document.querySelector('#easypoi-wps-mount') | |||||
| }) | |||||
| easyWps.setToken({token: data.token}) | |||||
| // 如果需要对iframe进行特殊的处理,可以通过以下方式拿到iframe的dom对象 | |||||
| //console.log(easyWps.iframe) | |||||
| // 打开文档结果 | |||||
| easyWps.on('fileOpen', function (data) { | |||||
| console.log(data.success) | |||||
| }) | |||||
| }) | |||||
| }); | |||||
| function getUrlParam(name) { | |||||
| var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象 | |||||
| var r = window.location.search.substr(1).match(reg); //匹配目标参数 | |||||
| if (r != null) return decodeURI(r[2]); | |||||
| return null; //返回参数值 | |||||
| } | |||||
| </script> | |||||
| </head> | |||||
| <body> | |||||
| </body> | |||||
| </html> | |||||
| @@ -0,0 +1 @@ | |||||
| !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n():"function"==typeof define&&define.amd?define(n):n()}(0,function(){"use strict";function e(e){var n=this.constructor;return this.then(function(t){return n.resolve(e()).then(function(){return t})},function(t){return n.resolve(e()).then(function(){return n.reject(t)})})}function n(e){return!(!e||"undefined"==typeof e.length)}function t(){}function o(e){if(!(this instanceof o))throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=undefined,this._deferreds=[],c(e,this)}function r(e,n){for(;3===e._state;)e=e._value;0!==e._state?(e._handled=!0,o._immediateFn(function(){var t=1===e._state?n.onFulfilled:n.onRejected;if(null!==t){var o;try{o=t(e._value)}catch(r){return void f(n.promise,r)}i(n.promise,o)}else(1===e._state?i:f)(n.promise,e._value)})):e._deferreds.push(n)}function i(e,n){try{if(n===e)throw new TypeError("A promise cannot be resolved with itself.");if(n&&("object"==typeof n||"function"==typeof n)){var t=n.then;if(n instanceof o)return e._state=3,e._value=n,void u(e);if("function"==typeof t)return void c(function(e,n){return function(){e.apply(n,arguments)}}(t,n),e)}e._state=1,e._value=n,u(e)}catch(r){f(e,r)}}function f(e,n){e._state=2,e._value=n,u(e)}function u(e){2===e._state&&0===e._deferreds.length&&o._immediateFn(function(){e._handled||o._unhandledRejectionFn(e._value)});for(var n=0,t=e._deferreds.length;t>n;n++)r(e,e._deferreds[n]);e._deferreds=null}function c(e,n){var t=!1;try{e(function(e){t||(t=!0,i(n,e))},function(e){t||(t=!0,f(n,e))})}catch(o){if(t)return;t=!0,f(n,o)}}var a=setTimeout;o.prototype["catch"]=function(e){return this.then(null,e)},o.prototype.then=function(e,n){var o=new this.constructor(t);return r(this,new function(e,n,t){this.onFulfilled="function"==typeof e?e:null,this.onRejected="function"==typeof n?n:null,this.promise=t}(e,n,o)),o},o.prototype["finally"]=e,o.all=function(e){return new o(function(t,o){function r(e,n){try{if(n&&("object"==typeof n||"function"==typeof n)){var u=n.then;if("function"==typeof u)return void u.call(n,function(n){r(e,n)},o)}i[e]=n,0==--f&&t(i)}catch(c){o(c)}}if(!n(e))return o(new TypeError("Promise.all accepts an array"));var i=Array.prototype.slice.call(e);if(0===i.length)return t([]);for(var f=i.length,u=0;i.length>u;u++)r(u,i[u])})},o.resolve=function(e){return e&&"object"==typeof e&&e.constructor===o?e:new o(function(n){n(e)})},o.reject=function(e){return new o(function(n,t){t(e)})},o.race=function(e){return new o(function(t,r){if(!n(e))return r(new TypeError("Promise.race accepts an array"));for(var i=0,f=e.length;f>i;i++)o.resolve(e[i]).then(t,r)})},o._immediateFn="function"==typeof setImmediate&&function(e){setImmediate(e)}||function(e){a(e,0)},o._unhandledRejectionFn=function(e){void 0!==console&&console&&console.warn("Possible Unhandled Promise Rejection:",e)};var l=function(){if("undefined"!=typeof self)return self;if("undefined"!=typeof window)return window;if("undefined"!=typeof global)return global;throw Error("unable to locate global object")}();"Promise"in l?l.Promise.prototype["finally"]||(l.Promise.prototype["finally"]=e):l.Promise=o}); | |||||
| @@ -2,7 +2,15 @@ | |||||
| -------------------------- | -------------------------- | ||||
| 版本修改 | 版本修改 | ||||
| -------------------------- | -------------------------- | ||||
| - 4.1.3 | |||||
| - 4.2.0 | |||||
| - 增加wps模块 | |||||
| - 模板添加了index常量列 | |||||
| - 修复横向迭代的时候,合并问题 | |||||
| - 添加XLSX水印工具类 | |||||
| - 修复 SAX SheetHandler 特殊情境下导致列错位 | |||||
| - 横向循环的时候同步宽度设置 | |||||
| - 注解支持生成下拉选择 | |||||
| - 4.1.3 | |||||
| - csv导出模式修改为write | - csv导出模式修改为write | ||||
| - 4.1.2 | - 4.1.2 | ||||
| - 修复shift时候最后一行问题 | - 修复shift时候最后一行问题 | ||||
| @@ -3,13 +3,14 @@ | |||||
| <modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
| <groupId>cn.afterturn</groupId> | <groupId>cn.afterturn</groupId> | ||||
| <artifactId>easypoi</artifactId> | <artifactId>easypoi</artifactId> | ||||
| <version>4.1.3</version> | |||||
| <version>4.2.0.A</version> | |||||
| <packaging>pom</packaging> | <packaging>pom</packaging> | ||||
| <name>easypoi</name> | <name>easypoi</name> | ||||
| <modules> | <modules> | ||||
| <module>easypoi-annotation</module> | |||||
| <module>easypoi-base</module> | <module>easypoi-base</module> | ||||
| <module>easypoi-web</module> | <module>easypoi-web</module> | ||||
| <module>easypoi-annotation</module> | |||||
| <module>easypoi-wps</module> | |||||
| </modules> | </modules> | ||||
| <url>http://opensource.afterturn.cn/</url> | <url>http://opensource.afterturn.cn/</url> | ||||
| @@ -45,12 +46,12 @@ | |||||
| </organization> | </organization> | ||||
| <properties> | <properties> | ||||
| <sub.version>4.1.3</sub.version> | |||||
| <sub.version>4.2.0</sub.version> | |||||
| <poi.version>4.1.1</poi.version> | <poi.version>4.1.1</poi.version> | ||||
| <xerces.version>2.9.1</xerces.version> | <xerces.version>2.9.1</xerces.version> | ||||
| <guava.version>16.0.1</guava.version> | <guava.version>16.0.1</guava.version> | ||||
| <commons-lang.version>3.2.1</commons-lang.version> | <commons-lang.version>3.2.1</commons-lang.version> | ||||
| <slf4j.version>1.6.1</slf4j.version> | |||||
| <slf4j.version>1.7.26</slf4j.version> | |||||
| <spring.version>5.1.7.RELEASE</spring.version> | <spring.version>5.1.7.RELEASE</spring.version> | ||||
| </properties> | </properties> | ||||
| <dependencyManagement> | <dependencyManagement> | ||||