update
This commit is contained in:
@@ -1,43 +0,0 @@
|
|||||||
<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>org.jeecgframework.boot3</groupId>
|
|
||||||
<artifactId>autopoi-parent</artifactId>
|
|
||||||
<version>3.7.0</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>autopoi-web</artifactId>
|
|
||||||
<dependencies>
|
|
||||||
<!-- autopoi -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jeecgframework.boot3</groupId>
|
|
||||||
<artifactId>autopoi</artifactId>
|
|
||||||
<version>${autopoi.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--spring -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-webmvc</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- servlet -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.servlet</groupId>
|
|
||||||
<artifactId>jakarta.servlet-api</artifactId>
|
|
||||||
<version>6.0.0</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
|
||||||
<artifactId>log4j-to-slf4j</artifactId>
|
|
||||||
<version>2.11.2</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
<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>org.jeecgframework.boot3</groupId>
|
|
||||||
<artifactId>autopoi-parent</artifactId>
|
|
||||||
<version>3.7.0</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>autopoi</artifactId>
|
|
||||||
<dependencies>
|
|
||||||
<!-- poi -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi-ooxml</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>xml-apis</artifactId>
|
|
||||||
<groupId>xml-apis</groupId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi-ooxml-full</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>org.apache.poi</groupId>-->
|
|
||||||
<!-- <artifactId>poi-ooxml-schemas</artifactId>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
<!-- Sax 读入的时候使用 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>xerces</groupId>
|
|
||||||
<artifactId>xercesImpl</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!-- Word 时候用到 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi-scratchpad</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- google 工具类 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.guava</groupId>
|
|
||||||
<artifactId>guava</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-lang3</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--日志 -->
|
|
||||||
<!-- slf4j -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--spring -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-webmvc</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
||||||
@@ -1,457 +0,0 @@
|
|||||||
package org.jeecgframework.poi.excel;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
||||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
|
||||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
|
||||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
|
||||||
import org.apache.poi.ss.usermodel.*;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
||||||
import org.jeecgframework.core.util.ApplicationContextUtil;
|
|
||||||
import org.jeecgframework.dict.service.AutoPoiDictServiceI;
|
|
||||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
|
||||||
import org.jeecgframework.poi.excel.annotation.ExcelCollection;
|
|
||||||
import org.jeecgframework.poi.excel.annotation.ExcelTarget;
|
|
||||||
import org.jeecgframework.poi.excel.annotation.ExcelVerify;
|
|
||||||
import org.jeecgframework.poi.excel.entity.ImportParams;
|
|
||||||
import org.jeecgframework.poi.excel.entity.params.ExcelCollectionParams;
|
|
||||||
import org.jeecgframework.poi.excel.entity.params.ExcelImportEntity;
|
|
||||||
import org.jeecgframework.poi.excel.entity.params.ExcelVerifyEntity;
|
|
||||||
import org.jeecgframework.poi.excel.imports.ExcelImportServer;
|
|
||||||
import org.jeecgframework.poi.exception.excel.ExcelImportException;
|
|
||||||
import org.jeecgframework.poi.exception.excel.enums.ExcelImportEnum;
|
|
||||||
import org.jeecgframework.poi.util.ExcelUtil;
|
|
||||||
import org.jeecgframework.poi.util.PoiPublicUtil;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.PushbackInputStream;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EXCEL INCLUE CHECK
|
|
||||||
* 验证excel标题是否存在,当前默认有0.8(80%)即可通过验证
|
|
||||||
*/
|
|
||||||
public class ExcelImportCheckUtil {
|
|
||||||
private final static Logger LOGGER = LoggerFactory.getLogger(ExcelImportCheckUtil.class);
|
|
||||||
|
|
||||||
/**当有标题到达多少可以通过验证*/
|
|
||||||
public static final Double defScreenRate = 0.8;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check inclue filed match rate
|
|
||||||
* @param inputstream
|
|
||||||
* @param pojoClass
|
|
||||||
* @param params
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static Boolean check(InputStream inputstream, Class<?> pojoClass, ImportParams params) {
|
|
||||||
return check(inputstream,pojoClass,params,defScreenRate);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* check inclue filed match rate
|
|
||||||
* @param inputstream
|
|
||||||
* @param pojoClass
|
|
||||||
* @param params
|
|
||||||
* @param screenRate field match rate (defalut:0.8)
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static Boolean check(InputStream inputstream, Class<?> pojoClass, ImportParams params, Double screenRate) {
|
|
||||||
Workbook book = null;
|
|
||||||
int errorNum = 0;
|
|
||||||
int successNum = 0;
|
|
||||||
if (!(inputstream.markSupported())) {
|
|
||||||
inputstream = new PushbackInputStream(inputstream, 8);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// if (POIFSFileSystem.hasPOIFSHeader(inputstream)) {
|
|
||||||
// book = new HSSFWorkbook(inputstream);
|
|
||||||
// } else if (POIXMLDocument.hasOOXMLHeader(inputstream)) {
|
|
||||||
// book = new XSSFWorkbook(OPCPackage.open(inputstream));
|
|
||||||
// }
|
|
||||||
book = WorkbookFactory.create(inputstream);
|
|
||||||
LOGGER.info(" >>> poi3升级到4兼容改造工作, pojoClass="+pojoClass);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < params.getSheetNum(); i++) {
|
|
||||||
Row row = null;
|
|
||||||
//跳过表头和标题行
|
|
||||||
Iterator<Row> rows;
|
|
||||||
try{
|
|
||||||
rows= book.getSheetAt(i).rowIterator();
|
|
||||||
}catch (Exception e){
|
|
||||||
//为空说明读取不到,故不是excel
|
|
||||||
throw new RuntimeException("请导入正确格式的excel文件!");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (int j = 0; j < params.getTitleRows() + params.getHeadRows(); j++) {
|
|
||||||
try{
|
|
||||||
row = rows.next();
|
|
||||||
}catch (NoSuchElementException e){
|
|
||||||
//为空说明标题不出在,excel格式错误
|
|
||||||
throw new RuntimeException("请填写内容标题!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Sheet sheet = book.getSheetAt(i);
|
|
||||||
Map<Integer, String> titlemap = null;
|
|
||||||
try {
|
|
||||||
titlemap = getTitleMap(sheet, params);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
Set<Integer> columnIndexSet = titlemap.keySet();
|
|
||||||
Integer maxColumnIndex = Collections.max(columnIndexSet);
|
|
||||||
Integer minColumnIndex = Collections.min(columnIndexSet);
|
|
||||||
while (rows.hasNext() && (row == null || sheet.getLastRowNum() - row.getRowNum() > params.getLastOfInvalidRow())) {
|
|
||||||
row = rows.next();
|
|
||||||
Map<String, ExcelImportEntity> excelParams = new HashMap<String, ExcelImportEntity>();
|
|
||||||
List<ExcelCollectionParams> excelCollection = new ArrayList<ExcelCollectionParams>();
|
|
||||||
String targetId = null;
|
|
||||||
if (!Map.class.equals(pojoClass)) {
|
|
||||||
Field fileds[] = PoiPublicUtil.getClassFields(pojoClass);
|
|
||||||
ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class);
|
|
||||||
if (etarget != null) {
|
|
||||||
targetId = etarget.value();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
getAllExcelField(targetId, fileds, excelParams, excelCollection, pojoClass, null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
int firstCellNum = row.getFirstCellNum();
|
|
||||||
if (firstCellNum > minColumnIndex) {
|
|
||||||
firstCellNum = minColumnIndex;
|
|
||||||
}
|
|
||||||
int lastCellNum = row.getLastCellNum();
|
|
||||||
if (lastCellNum < maxColumnIndex + 1) {
|
|
||||||
lastCellNum = maxColumnIndex + 1;
|
|
||||||
}
|
|
||||||
for (int j = firstCellNum, le = lastCellNum; j < le; j++) {
|
|
||||||
String titleString = (String) titlemap.get(j);
|
|
||||||
if (excelParams.containsKey(titleString) || Map.class.equals(pojoClass)) {
|
|
||||||
successNum+=1;
|
|
||||||
}else{
|
|
||||||
if(excelCollection.size()>0){
|
|
||||||
Iterator var33 = excelCollection.iterator();
|
|
||||||
ExcelCollectionParams param = (ExcelCollectionParams)var33.next();
|
|
||||||
if (param.getExcelParams().containsKey(titleString)) {
|
|
||||||
successNum+=1;
|
|
||||||
}else{
|
|
||||||
errorNum+=1;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
errorNum+=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(successNum<errorNum){
|
|
||||||
return false;
|
|
||||||
}else if(successNum>errorNum){
|
|
||||||
if(errorNum>0){
|
|
||||||
double newNumber = (double) successNum / (successNum + errorNum);
|
|
||||||
BigDecimal bg = new BigDecimal(newNumber);
|
|
||||||
double f1 = bg.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
|
|
||||||
if(f1<screenRate){
|
|
||||||
return false;
|
|
||||||
}else{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}else if(successNum==errorNum){
|
|
||||||
return false;
|
|
||||||
}else{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (ExcelImportException e) {
|
|
||||||
if (!e.getType().equals(ExcelImportEnum.VERIFY_ERROR)) {
|
|
||||||
throw new ExcelImportException(e.getType(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件名称标题
|
|
||||||
* @Author JEECG
|
|
||||||
* @date 20201023
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private static Map<Integer, String> getTitleMap(Sheet sheet, ImportParams params) throws Exception {
|
|
||||||
Map<Integer, String> titlemap = new HashMap<Integer, String>();
|
|
||||||
Iterator<Cell> cellTitle = null;
|
|
||||||
String collectionName = null;
|
|
||||||
Row headRow = null;
|
|
||||||
int headBegin = params.getTitleRows();
|
|
||||||
int allRowNum = sheet.getPhysicalNumberOfRows();
|
|
||||||
while(headRow == null && headBegin < allRowNum){
|
|
||||||
headRow = sheet.getRow(headBegin++);
|
|
||||||
}
|
|
||||||
if(headRow==null){
|
|
||||||
throw new Exception("不识别该文件");
|
|
||||||
}
|
|
||||||
if (ExcelUtil.isMergedRegion(sheet, headRow.getRowNum(), 0)) {
|
|
||||||
params.setHeadRows(2);
|
|
||||||
}else{
|
|
||||||
params.setHeadRows(1);
|
|
||||||
}
|
|
||||||
cellTitle = headRow.cellIterator();
|
|
||||||
while (cellTitle.hasNext()) {
|
|
||||||
Cell cell = cellTitle.next();
|
|
||||||
String value = getKeyValue(cell);
|
|
||||||
if (StringUtils.isNotEmpty(value)) {
|
|
||||||
titlemap.put(cell.getColumnIndex(), value);//加入表头列表
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//多行表头
|
|
||||||
for (int j = headBegin; j < headBegin + params.getHeadRows()-1; j++) {
|
|
||||||
headRow = sheet.getRow(j);
|
|
||||||
cellTitle = headRow.cellIterator();
|
|
||||||
while (cellTitle.hasNext()) {
|
|
||||||
Cell cell = cellTitle.next();
|
|
||||||
String value = getKeyValue(cell);
|
|
||||||
if (StringUtils.isNotEmpty(value)) {
|
|
||||||
int columnIndex = cell.getColumnIndex();
|
|
||||||
//当前cell的上一行是否为合并单元格
|
|
||||||
if(ExcelUtil.isMergedRegion(sheet, cell.getRowIndex()-1, columnIndex)){
|
|
||||||
collectionName = ExcelUtil.getMergedRegionValue(sheet, cell.getRowIndex()-1, columnIndex);
|
|
||||||
if(params.isIgnoreHeader(collectionName)){
|
|
||||||
titlemap.put(cell.getColumnIndex(), value);
|
|
||||||
}else{
|
|
||||||
titlemap.put(cell.getColumnIndex(), collectionName + "_" + value);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
titlemap.put(cell.getColumnIndex(), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return titlemap;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 获取key的值,针对不同类型获取不同的值
|
|
||||||
*
|
|
||||||
* @Author JEECG
|
|
||||||
* @date 20201023
|
|
||||||
* @param cell
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private static String getKeyValue(Cell cell) {
|
|
||||||
if(cell==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Object obj = null;
|
|
||||||
switch (cell.getCellType()) {
|
|
||||||
case STRING:
|
|
||||||
obj = cell.getStringCellValue();
|
|
||||||
break;
|
|
||||||
case BOOLEAN:
|
|
||||||
obj = cell.getBooleanCellValue();
|
|
||||||
break;
|
|
||||||
case NUMERIC:
|
|
||||||
obj = cell.getNumericCellValue();
|
|
||||||
break;
|
|
||||||
case FORMULA:
|
|
||||||
obj = cell.getCellFormula();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return obj == null ? null : obj.toString().trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取需要导出的全部字段
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param targetId
|
|
||||||
* 目标ID
|
|
||||||
* @param fields
|
|
||||||
* @param excelCollection
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public static void getAllExcelField(String targetId, Field[] fields, Map<String, ExcelImportEntity> excelParams, List<ExcelCollectionParams> excelCollection, Class<?> pojoClass, List<Method> getMethods) throws Exception {
|
|
||||||
ExcelImportEntity excelEntity = null;
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
|
||||||
Field field = fields[i];
|
|
||||||
if (PoiPublicUtil.isNotUserExcelUserThis(null, field, targetId)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (PoiPublicUtil.isCollection(field.getType())) {
|
|
||||||
// 集合对象设置属性
|
|
||||||
ExcelCollectionParams collection = new ExcelCollectionParams();
|
|
||||||
collection.setName(field.getName());
|
|
||||||
Map<String, ExcelImportEntity> temp = new HashMap();
|
|
||||||
ParameterizedType pt = (ParameterizedType)field.getGenericType();
|
|
||||||
Class<?> clz = (Class)pt.getActualTypeArguments()[0];
|
|
||||||
collection.setType(clz);
|
|
||||||
getExcelFieldList(targetId, PoiPublicUtil.getClassFields(clz), clz, temp, (List)null);
|
|
||||||
collection.setExcelParams(temp);
|
|
||||||
collection.setExcelName(((ExcelCollection)field.getAnnotation(ExcelCollection.class)).name());
|
|
||||||
additionalCollectionName(collection);
|
|
||||||
excelCollection.add(collection);
|
|
||||||
} else if (PoiPublicUtil.isJavaClass(field)) {
|
|
||||||
addEntityToMap(targetId, field, (ExcelImportEntity)excelEntity, pojoClass, getMethods, excelParams);
|
|
||||||
} else {
|
|
||||||
List<Method> newMethods = new ArrayList<Method>();
|
|
||||||
if (getMethods != null) {
|
|
||||||
newMethods.addAll(getMethods);
|
|
||||||
}
|
|
||||||
newMethods.add(PoiPublicUtil.getMethod(field.getName(), pojoClass));
|
|
||||||
getAllExcelField(targetId, PoiPublicUtil.getClassFields(field.getType()), excelParams, excelCollection, field.getType(), newMethods);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void getExcelFieldList(String targetId, Field[] fields, Class<?> pojoClass, Map<String, ExcelImportEntity> temp, List<Method> getMethods) throws Exception {
|
|
||||||
ExcelImportEntity excelEntity = null;
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
|
||||||
Field field = fields[i];
|
|
||||||
if (!PoiPublicUtil.isNotUserExcelUserThis((List)null, field, targetId)) {
|
|
||||||
if (PoiPublicUtil.isJavaClass(field)) {
|
|
||||||
addEntityToMap(targetId, field, (ExcelImportEntity)excelEntity, pojoClass, getMethods, temp);
|
|
||||||
} else {
|
|
||||||
List<Method> newMethods = new ArrayList();
|
|
||||||
if (getMethods != null) {
|
|
||||||
newMethods.addAll(getMethods);
|
|
||||||
}
|
|
||||||
|
|
||||||
newMethods.add(PoiPublicUtil.getMethod(field.getName(), pojoClass, field.getType()));
|
|
||||||
getExcelFieldList(targetId, PoiPublicUtil.getClassFields(field.getType()), field.getType(), temp, newMethods);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 追加集合名称到前面
|
|
||||||
*
|
|
||||||
* @param collection
|
|
||||||
*/
|
|
||||||
private static void additionalCollectionName(ExcelCollectionParams collection) {
|
|
||||||
Set<String> keys = new HashSet();
|
|
||||||
keys.addAll(collection.getExcelParams().keySet());
|
|
||||||
Iterator var3 = keys.iterator();
|
|
||||||
|
|
||||||
while(var3.hasNext()) {
|
|
||||||
String key = (String)var3.next();
|
|
||||||
collection.getExcelParams().put(collection.getExcelName() + "_" + key, collection.getExcelParams().get(key));
|
|
||||||
collection.getExcelParams().remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 把这个注解解析放到类型对象中
|
|
||||||
*
|
|
||||||
* @param targetId
|
|
||||||
* @param field
|
|
||||||
* @param excelEntity
|
|
||||||
* @param pojoClass
|
|
||||||
* @param getMethods
|
|
||||||
* @param temp
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public static void addEntityToMap(String targetId, Field field, ExcelImportEntity excelEntity, Class<?> pojoClass, List<Method> getMethods, Map<String, ExcelImportEntity> temp) throws Exception {
|
|
||||||
Excel excel = field.getAnnotation(Excel.class);
|
|
||||||
excelEntity = new ExcelImportEntity();
|
|
||||||
excelEntity.setType(excel.type());
|
|
||||||
excelEntity.setSaveUrl(excel.savePath());
|
|
||||||
excelEntity.setSaveType(excel.imageType());
|
|
||||||
excelEntity.setReplace(excel.replace());
|
|
||||||
excelEntity.setDatabaseFormat(excel.databaseFormat());
|
|
||||||
excelEntity.setVerify(getImportVerify(field));
|
|
||||||
excelEntity.setSuffix(excel.suffix());
|
|
||||||
excelEntity.setNumFormat(excel.numFormat());
|
|
||||||
excelEntity.setGroupName(excel.groupName());
|
|
||||||
//update-begin-author:taoYan date:20180202 for:TASK #2067 【bug excel 问题】excel导入字典文本翻译问题
|
|
||||||
excelEntity.setMultiReplace(excel.multiReplace());
|
|
||||||
if(StringUtils.isNotEmpty(excel.dicCode())){
|
|
||||||
AutoPoiDictServiceI jeecgDictService = null;
|
|
||||||
try {
|
|
||||||
jeecgDictService = ApplicationContextUtil.getContext().getBean(AutoPoiDictServiceI.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
}
|
|
||||||
if(jeecgDictService!=null){
|
|
||||||
String[] dictReplace = jeecgDictService.queryDict(excel.dictTable(), excel.dicCode(), excel.dicText());
|
|
||||||
if(excelEntity.getReplace()!=null && dictReplace!=null && dictReplace.length!=0){
|
|
||||||
excelEntity.setReplace(dictReplace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//update-end-author:taoYan date:20180202 for:TASK #2067 【bug excel 问题】excel导入字典文本翻译问题
|
|
||||||
getExcelField(targetId, field, excelEntity, excel, pojoClass);
|
|
||||||
if (getMethods != null) {
|
|
||||||
List<Method> newMethods = new ArrayList<Method>();
|
|
||||||
newMethods.addAll(getMethods);
|
|
||||||
newMethods.add(excelEntity.getMethod());
|
|
||||||
excelEntity.setMethods(newMethods);
|
|
||||||
}
|
|
||||||
temp.put(excelEntity.getName(), excelEntity);
|
|
||||||
|
|
||||||
}
|
|
||||||
public static void getExcelField(String targetId, Field field, ExcelImportEntity excelEntity, Excel excel, Class<?> pojoClass) throws Exception {
|
|
||||||
excelEntity.setName(getExcelName(excel.name(), targetId));
|
|
||||||
String fieldname = field.getName();
|
|
||||||
//update-begin-author:taoyan for:TASK #2798 【例子】导入扩展方法,支持自定义导入字段转换规则
|
|
||||||
excelEntity.setMethod(PoiPublicUtil.getMethod(fieldname, pojoClass, field.getType(),excel.importConvert()));
|
|
||||||
//update-end-author:taoyan for:TASK #2798 【例子】导入扩展方法,支持自定义导入字段转换规则
|
|
||||||
if (StringUtils.isNotEmpty(excel.importFormat())) {
|
|
||||||
excelEntity.setFormat(excel.importFormat());
|
|
||||||
} else {
|
|
||||||
excelEntity.setFormat(excel.format());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 判断在这个单元格显示的名称
|
|
||||||
*
|
|
||||||
* @param exportName
|
|
||||||
* @param targetId
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getExcelName(String exportName, String targetId) {
|
|
||||||
if (exportName.indexOf("_") < 0) {
|
|
||||||
return exportName;
|
|
||||||
}
|
|
||||||
String[] arr = exportName.split(",");
|
|
||||||
for (String str : arr) {
|
|
||||||
if (str.indexOf(targetId) != -1) {
|
|
||||||
return str.split("_")[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 获取导入校验参数
|
|
||||||
*
|
|
||||||
* @param field
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static ExcelVerifyEntity getImportVerify(Field field) {
|
|
||||||
ExcelVerify verify = field.getAnnotation(ExcelVerify.class);
|
|
||||||
if (verify != null) {
|
|
||||||
ExcelVerifyEntity entity = new ExcelVerifyEntity();
|
|
||||||
entity.setEmail(verify.isEmail());
|
|
||||||
entity.setInterHandler(verify.interHandler());
|
|
||||||
entity.setMaxLength(verify.maxLength());
|
|
||||||
entity.setMinLength(verify.minLength());
|
|
||||||
entity.setMobile(verify.isMobile());
|
|
||||||
entity.setNotNull(verify.notNull());
|
|
||||||
entity.setRegex(verify.regex());
|
|
||||||
entity.setRegexTip(verify.regexTip());
|
|
||||||
entity.setTel(verify.isTel());
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,263 +0,0 @@
|
|||||||
///**
|
|
||||||
// *
|
|
||||||
// */
|
|
||||||
//package org.jeecgframework.poi.excel.graph.builder;
|
|
||||||
//
|
|
||||||
//import java.util.ArrayList;
|
|
||||||
//import java.util.List;
|
|
||||||
//
|
|
||||||
//import org.apache.commons.lang3.StringUtils;
|
|
||||||
//import org.apache.poi.ss.usermodel.Chart;
|
|
||||||
//import org.apache.poi.ss.usermodel.ClientAnchor;
|
|
||||||
//import org.apache.poi.ss.usermodel.Drawing;
|
|
||||||
//import org.apache.poi.ss.usermodel.Sheet;
|
|
||||||
//import org.apache.poi.ss.usermodel.Workbook;
|
|
||||||
//import org.apache.poi.ss.usermodel.charts.AxisCrosses;
|
|
||||||
//import org.apache.poi.ss.usermodel.charts.AxisPosition;
|
|
||||||
//import org.apache.poi.ss.usermodel.charts.ChartAxis;
|
|
||||||
//import org.apache.poi.ss.usermodel.charts.ChartDataSource;
|
|
||||||
//import org.apache.poi.ss.usermodel.charts.ChartLegend;
|
|
||||||
//import org.apache.poi.ss.usermodel.charts.DataSources;
|
|
||||||
//import org.apache.poi.ss.usermodel.charts.LegendPosition;
|
|
||||||
//import org.apache.poi.ss.usermodel.charts.LineChartData;
|
|
||||||
//import org.apache.poi.ss.usermodel.charts.ScatterChartData;
|
|
||||||
//import org.apache.poi.ss.usermodel.charts.ValueAxis;
|
|
||||||
//import org.apache.poi.ss.util.CellRangeAddress;
|
|
||||||
//
|
|
||||||
//import org.jeecgframework.poi.excel.graph.constant.ExcelGraphElementType;
|
|
||||||
//import org.jeecgframework.poi.excel.graph.constant.ExcelGraphType;
|
|
||||||
//import org.jeecgframework.poi.excel.graph.entity.ExcelGraph;
|
|
||||||
//import org.jeecgframework.poi.excel.graph.entity.ExcelGraphElement;
|
|
||||||
//import org.jeecgframework.poi.excel.graph.entity.ExcelTitleCell;
|
|
||||||
//import org.jeecgframework.poi.util.PoiCellUtil;
|
|
||||||
//import org.jeecgframework.poi.util.PoiExcelGraphDataUtil;
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * @Description
|
|
||||||
// * @author liusq
|
|
||||||
// * @data 2022年1月4号
|
|
||||||
// */
|
|
||||||
//public class ExcelChartBuildService
|
|
||||||
//{
|
|
||||||
// /**
|
|
||||||
// *
|
|
||||||
// * @param workbook
|
|
||||||
// * @param graphList
|
|
||||||
// * @param build 通过实时数据行来重新计算图形定义
|
|
||||||
// * @param append
|
|
||||||
// */
|
|
||||||
// public static void createExcelChart(Workbook workbook, List<ExcelGraph> graphList, Boolean build, Boolean append)
|
|
||||||
// {
|
|
||||||
// if(workbook!=null&&graphList!=null){
|
|
||||||
// //设定默认第一个sheet为数据项
|
|
||||||
// Sheet dataSouce=workbook.getSheetAt(0);
|
|
||||||
// if(dataSouce!=null){
|
|
||||||
// buildTitle(dataSouce,graphList);
|
|
||||||
//
|
|
||||||
// if(build){
|
|
||||||
// PoiExcelGraphDataUtil.buildGraphData(dataSouce, graphList);
|
|
||||||
// }
|
|
||||||
// if(append){
|
|
||||||
// buildExcelChart(dataSouce, dataSouce, graphList);
|
|
||||||
// }else{
|
|
||||||
// Sheet sheet=workbook.createSheet("图形界面");
|
|
||||||
// buildExcelChart(dataSouce, sheet, graphList);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 构建基础图形
|
|
||||||
// * @param drawing
|
|
||||||
// * @param anchor
|
|
||||||
// * @param dataSourceSheet
|
|
||||||
// * @param graph
|
|
||||||
// */
|
|
||||||
// private static void buildExcelChart(Drawing drawing,ClientAnchor anchor,Sheet dataSourceSheet,ExcelGraph graph){
|
|
||||||
// Chart chart = null;
|
|
||||||
// // TODO 图表没有成功
|
|
||||||
// //drawing.createChart(anchor);
|
|
||||||
// ChartLegend legend = chart.getOrCreateLegend();
|
|
||||||
// legend.setPosition(LegendPosition.TOP_RIGHT);
|
|
||||||
//
|
|
||||||
// ChartAxis bottomAxis = chart.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM);
|
|
||||||
// ValueAxis leftAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT);
|
|
||||||
// leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
|
|
||||||
// ExcelGraphElement categoryElement=graph.getCategory();
|
|
||||||
//
|
|
||||||
// ChartDataSource categoryChart;
|
|
||||||
// if(categoryElement!=null&& categoryElement.getElementType().equals(ExcelGraphElementType.STRING_TYPE)){
|
|
||||||
// categoryChart=DataSources.fromStringCellRange(dataSourceSheet, new CellRangeAddress(categoryElement.getStartRowNum(),categoryElement.getEndRowNum(),categoryElement.getStartColNum(),categoryElement.getEndColNum()));
|
|
||||||
// }else{
|
|
||||||
// categoryChart=DataSources.fromNumericCellRange(dataSourceSheet, new CellRangeAddress(categoryElement.getStartRowNum(),categoryElement.getEndRowNum(),categoryElement.getStartColNum(),categoryElement.getEndColNum()));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// List<ExcelGraphElement> valueList=graph.getValueList();
|
|
||||||
// List<ChartDataSource<Number>> chartValueList= new ArrayList<>();
|
|
||||||
// if(valueList!=null&&valueList.size()>0){
|
|
||||||
// for(ExcelGraphElement ele:valueList){
|
|
||||||
// ChartDataSource<Number> source=DataSources.fromNumericCellRange(dataSourceSheet, new CellRangeAddress(ele.getStartRowNum(),ele.getEndRowNum(),ele.getStartColNum(),ele.getEndColNum()));
|
|
||||||
// chartValueList.add(source);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if(graph.getGraphType().equals(ExcelGraphType.LINE_CHART)){
|
|
||||||
// LineChartData data = chart.getChartDataFactory().createLineChartData();
|
|
||||||
// buildLineChartData(data, categoryChart, chartValueList, graph.getTitle());
|
|
||||||
// chart.plot(data, bottomAxis, leftAxis);
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// ScatterChartData data=chart.getChartDataFactory().createScatterChartData();
|
|
||||||
// buildScatterChartData(data, categoryChart, chartValueList,graph.getTitle());
|
|
||||||
// chart.plot(data, bottomAxis, leftAxis);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 构建多个图形对象
|
|
||||||
// * @param dataSourceSheet
|
|
||||||
// * @param tragetSheet
|
|
||||||
// * @param graphList
|
|
||||||
// */
|
|
||||||
// private static void buildExcelChart(Sheet dataSourceSheet,Sheet tragetSheet,List<ExcelGraph> graphList){
|
|
||||||
// int len=graphList.size();
|
|
||||||
// if(len==1)
|
|
||||||
// {
|
|
||||||
// buildExcelChart(dataSourceSheet, tragetSheet, graphList.get(0));
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// int drawStart=0;
|
|
||||||
// int drawEnd=20;
|
|
||||||
// Drawing drawing = PoiExcelGraphDataUtil.getDrawingPatriarch(tragetSheet);
|
|
||||||
// for(int i=0;i<len;i++){
|
|
||||||
// ExcelGraph graph=graphList.get(i);
|
|
||||||
// ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, drawStart, 15, drawEnd);
|
|
||||||
// buildExcelChart(drawing, anchor, dataSourceSheet, graph);
|
|
||||||
// drawStart=drawStart+drawEnd;
|
|
||||||
// drawEnd=drawEnd+drawEnd;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 构建图形对象
|
|
||||||
// * @param dataSourceSheet
|
|
||||||
// * @param tragetSheet
|
|
||||||
// * @param graph
|
|
||||||
// */
|
|
||||||
// private static void buildExcelChart(Sheet dataSourceSheet,Sheet tragetSheet,ExcelGraph graph){
|
|
||||||
// Drawing drawing = PoiExcelGraphDataUtil.getDrawingPatriarch(tragetSheet);
|
|
||||||
// ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 0, 15, 20);
|
|
||||||
// buildExcelChart(drawing, anchor, dataSourceSheet, graph);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 构建Title
|
|
||||||
// * @param sheet
|
|
||||||
// * @param graph
|
|
||||||
// */
|
|
||||||
// private static void buildTitle(Sheet sheet,ExcelGraph graph){
|
|
||||||
// int cellTitleLen=graph.getTitleCell().size();
|
|
||||||
// int titleLen=graph.getTitle().size();
|
|
||||||
// if(titleLen>0){
|
|
||||||
//
|
|
||||||
// }else{
|
|
||||||
// for(int i=0;i<cellTitleLen;i++){
|
|
||||||
// ExcelTitleCell titleCell=graph.getTitleCell().get(i);
|
|
||||||
// if(titleCell!=null){
|
|
||||||
// graph.getTitle().add(PoiCellUtil.getCellValue(sheet,titleCell.getRow(),titleCell.getCol()));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 构建Title
|
|
||||||
// * @param sheet
|
|
||||||
// * @param graphList
|
|
||||||
// */
|
|
||||||
// private static void buildTitle(Sheet sheet,List<ExcelGraph> graphList){
|
|
||||||
// if(graphList!=null&&graphList.size()>0){
|
|
||||||
// for(ExcelGraph graph:graphList){
|
|
||||||
// if(graph!=null)
|
|
||||||
// {
|
|
||||||
// buildTitle(sheet, graph);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// *
|
|
||||||
// * @param data
|
|
||||||
// * @param categoryChart
|
|
||||||
// * @param chartValueList
|
|
||||||
// * @param title
|
|
||||||
// */
|
|
||||||
// private static void buildLineChartData(LineChartData data,ChartDataSource categoryChart,List<ChartDataSource<Number>> chartValueList,List<String> title){
|
|
||||||
// if(chartValueList.size()==title.size())
|
|
||||||
// {
|
|
||||||
// int len=title.size();
|
|
||||||
// for(int i=0;i<len;i++){
|
|
||||||
// //TODO 更新版本
|
|
||||||
// //data.addSerie(categoryChart, chartValueList.get(i)).setTitle(title.get(i));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// int i=0;
|
|
||||||
// for(ChartDataSource<Number> source:chartValueList){
|
|
||||||
// String temp_title=title.get(i);
|
|
||||||
// if(StringUtils.isNotBlank(temp_title)){
|
|
||||||
// //data.addSerie(categoryChart, source).setTitle(_title);
|
|
||||||
// }else{
|
|
||||||
// //data.addSerie(categoryChart, source);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// *
|
|
||||||
// * @param data
|
|
||||||
// * @param categoryChart
|
|
||||||
// * @param chartValueList
|
|
||||||
// * @param title
|
|
||||||
// */
|
|
||||||
// private static void buildScatterChartData(ScatterChartData data,ChartDataSource categoryChart,List<ChartDataSource<Number>> chartValueList,List<String> title){
|
|
||||||
// if(chartValueList.size()==title.size())
|
|
||||||
// {
|
|
||||||
// int len=title.size();
|
|
||||||
// for(int i=0;i<len;i++){
|
|
||||||
// data.addSerie(categoryChart, chartValueList.get(i)).setTitle(title.get(i));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// int i=0;
|
|
||||||
// for(ChartDataSource<Number> source:chartValueList){
|
|
||||||
// String temp_title=title.get(i);
|
|
||||||
// if(StringUtils.isNotBlank(temp_title)){
|
|
||||||
// data.addSerie(categoryChart, source).setTitle(temp_title);
|
|
||||||
// }else{
|
|
||||||
// data.addSerie(categoryChart, source);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
package org.jeecgframework.poi.excel.html.helper;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
|
||||||
import org.apache.poi.ss.usermodel.Font;
|
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFFont;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
||||||
|
|
||||||
import com.google.common.xml.XmlEscapers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cell值帮助类
|
|
||||||
*
|
|
||||||
* @author JEECG
|
|
||||||
* @date 2015年5月9日 下午10:31:32
|
|
||||||
*/
|
|
||||||
public class CellValueHelper {
|
|
||||||
/**
|
|
||||||
* Excel 格式
|
|
||||||
*/
|
|
||||||
private boolean is07;
|
|
||||||
|
|
||||||
private int cssRandom;
|
|
||||||
|
|
||||||
private Map<String, String> fontCache = new HashMap<String, String>();
|
|
||||||
|
|
||||||
public CellValueHelper(Workbook wb, int cssRandom) {
|
|
||||||
this.cssRandom = cssRandom;
|
|
||||||
if (wb instanceof HSSFWorkbook)
|
|
||||||
is07 = false;
|
|
||||||
else if (wb instanceof XSSFWorkbook) {
|
|
||||||
is07 = true;
|
|
||||||
cacheFontInfo(wb);
|
|
||||||
} else
|
|
||||||
throw new IllegalArgumentException("unknown workbook type: " + wb.getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* O7 版本坑爹bug
|
|
||||||
*
|
|
||||||
* @param wb
|
|
||||||
*/
|
|
||||||
private void cacheFontInfo(Workbook wb) {
|
|
||||||
for (int i = 0, le = wb.getNumberOfFonts(); i < le; i++) {
|
|
||||||
Font font = wb.getFontAt(i);
|
|
||||||
fontCache.put(font.getBold() + "_" + font.getItalic() + "_" + font.getFontName() + "_" + font.getFontHeightInPoints() + "_" + font.getColor(), font.getIndex() + "");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getHtmlValue(Cell cell) {
|
|
||||||
if (CellType.BOOLEAN == cell.getCellType() || CellType.NUMERIC == cell.getCellType()) {
|
|
||||||
cell.setCellType( CellType.STRING);
|
|
||||||
return cell.getStringCellValue();
|
|
||||||
} else if ( CellType.STRING == cell.getCellType()) {
|
|
||||||
if (cell.getRichStringCellValue().numFormattingRuns() == 0) {
|
|
||||||
return XmlEscapers.xmlContentEscaper().escape(cell.getStringCellValue());
|
|
||||||
} else if (is07) {
|
|
||||||
return getXSSFRichString((XSSFRichTextString) cell.getRichStringCellValue());
|
|
||||||
} else {
|
|
||||||
return getHSSFRichString((HSSFRichTextString) cell.getRichStringCellValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 03版本复杂数据
|
|
||||||
*
|
|
||||||
* @param rich
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String getHSSFRichString(HSSFRichTextString rich) {
|
|
||||||
int nums = rich.numFormattingRuns();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
String text = rich.toString();
|
|
||||||
int currentIndex = 0;
|
|
||||||
sb.append(text.substring(0, rich.getIndexOfFormattingRun(0)));
|
|
||||||
for (int i = 0; i < nums; i++) {
|
|
||||||
sb.append("<span ");
|
|
||||||
sb.append("class='font_" + rich.getFontOfFormattingRun(i));
|
|
||||||
sb.append("_");
|
|
||||||
sb.append(cssRandom);
|
|
||||||
sb.append("'>");
|
|
||||||
currentIndex = rich.getIndexOfFormattingRun(i);
|
|
||||||
if (i < nums - 1) {
|
|
||||||
sb.append(XmlEscapers.xmlContentEscaper().escape(text.substring(currentIndex, rich.getIndexOfFormattingRun(i + 1))));
|
|
||||||
} else {
|
|
||||||
sb.append(XmlEscapers.xmlContentEscaper().escape(text.substring(currentIndex, text.length())));
|
|
||||||
}
|
|
||||||
sb.append("</span>");
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 07版本复杂数据
|
|
||||||
*
|
|
||||||
* @param rich
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String getXSSFRichString(XSSFRichTextString rich) {
|
|
||||||
int nums = rich.numFormattingRuns();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
String text = rich.toString();
|
|
||||||
int currentIndex = 0, lastIndex = 0;
|
|
||||||
for (int i = 1; i <= nums; i++) {
|
|
||||||
sb.append("<span ");
|
|
||||||
try {
|
|
||||||
sb.append("class='font_" + getFontIndex(rich.getFontOfFormattingRun(i - 1)));
|
|
||||||
sb.append("_");
|
|
||||||
sb.append(cssRandom);
|
|
||||||
sb.append("'");
|
|
||||||
} catch (Exception e) {
|
|
||||||
}
|
|
||||||
sb.append(">");
|
|
||||||
currentIndex = rich.getIndexOfFormattingRun(i) == -1 ? text.length() : rich.getIndexOfFormattingRun(i);
|
|
||||||
sb.append(XmlEscapers.xmlContentEscaper().escape(text.substring(lastIndex, currentIndex)));
|
|
||||||
sb.append("</span>");
|
|
||||||
lastIndex = currentIndex;
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getFontIndex(XSSFFont font) {
|
|
||||||
return fontCache.get(font.getBold() + "_" + font.getItalic() + "_" + font.getFontName() + "_" + font.getFontHeightInPoints() + "_" + font.getColor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,259 +0,0 @@
|
|||||||
package org.jeecgframework.poi.excel.html.helper;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.Formatter;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFPalette;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
||||||
import org.apache.poi.hssf.util.HSSFColor;
|
|
||||||
import org.apache.poi.ss.usermodel.*;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFColor;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFFont;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
||||||
import org.jeecgframework.poi.util.PoiPublicUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 样式帮助类
|
|
||||||
*
|
|
||||||
* @author JEECG
|
|
||||||
* @date 2015年5月9日 下午4:04:24
|
|
||||||
*/
|
|
||||||
public class StylerHelper {
|
|
||||||
|
|
||||||
private static String DEFAULTS_CLASS_CSS = ".excelDefaults {background-color: white;color: black;text-decoration: none;direction: ltr;text-transform: none;text-indent: 0;letter-spacing: 0;word-spacing: 0;white-space: normal;unicode-bidi: normal;vertical-align: 0;text-shadow: none;padding: 0;margin: 0;border-collapse: collapse;white-space: pre-wrap;word-wrap: break-word;word-break: break-all;}.excelDefaults td {padding: 1px 5px;border: 1px solid silver;border-color: #000000;text-align: center;vertical-align: middle;font-size: 12pt;}.excelDefaults .colHeader {background-color: silver;font-weight: bold;border: 1px solid black;text-align: center;padding: 1px 5px;}.excelDefaults .rowHeader {background-color: silver;font-weight: bold;border: 1px solid black;text-align: right;padding: 1px 5px;}";
|
|
||||||
|
|
||||||
private static final String DEFAULTS_CLASS = "excelDefaults";
|
|
||||||
|
|
||||||
private static final Map<Short, String> ALIGN = PoiPublicUtil.mapFor(HorizontalAlignment.LEFT.getCode(), "left",HorizontalAlignment.CENTER.getCode(), "center",HorizontalAlignment.RIGHT.getCode(), "right", HorizontalAlignment.FILL.getCode(), "left",HorizontalAlignment.JUSTIFY.getCode(), "left",HorizontalAlignment.CENTER_SELECTION.getCode(), "center");
|
|
||||||
|
|
||||||
private static final Map<Short, String> VERTICAL_ALIGN = PoiPublicUtil.mapFor(VerticalAlignment.BOTTOM.getCode(), "bottom", VerticalAlignment.CENTER.getCode(), "middle",VerticalAlignment.TOP.getCode(), "top");
|
|
||||||
|
|
||||||
private Formatter out;
|
|
||||||
|
|
||||||
private Sheet sheet;
|
|
||||||
|
|
||||||
private HtmlHelper helper;
|
|
||||||
|
|
||||||
private int sheetNum;
|
|
||||||
|
|
||||||
private int cssRandom;
|
|
||||||
|
|
||||||
public StylerHelper(Workbook wb, Formatter out, int sheetNum, int cssRandom) {
|
|
||||||
this.out = out;
|
|
||||||
this.sheetNum = sheetNum;
|
|
||||||
this.cssRandom = cssRandom;
|
|
||||||
if (wb instanceof HSSFWorkbook)
|
|
||||||
helper = new HSSFHtmlHelper((HSSFWorkbook) wb);
|
|
||||||
else if (wb instanceof XSSFWorkbook)
|
|
||||||
helper = new XSSFHtmlHelper((XSSFWorkbook) wb);
|
|
||||||
else
|
|
||||||
throw new IllegalArgumentException("unknown workbook type: " + wb.getClass().getSimpleName());
|
|
||||||
printInlineStyle(wb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void printInlineStyle(Workbook wb) {
|
|
||||||
out.format("<style type=\"text/css\">%n");
|
|
||||||
printStyles(wb);
|
|
||||||
prontFonts(wb);
|
|
||||||
out.format("</style>%n");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prontFonts(Workbook wb) {
|
|
||||||
//update-begin---author:liusq Date:20220228 for:[I4I3ZY]issue AutoPOi Workbook对象转HTML字符串 数组下标越界异常----
|
|
||||||
for (int i = 0, le = wb.getNumberOfFonts(); i < le; i++) {
|
|
||||||
Font font = wb.getFontAt(i);
|
|
||||||
out.format(".%s .%s {%n", DEFAULTS_CLASS, "font_" + i + "_" + cssRandom);
|
|
||||||
fontStyle(font);
|
|
||||||
out.format("}%n");
|
|
||||||
}
|
|
||||||
//update-end---author:liusq Date:20220228 for:[I4I3ZY]issue AutoPOi Workbook对象转HTML字符串 数组下标越界异常整----
|
|
||||||
}
|
|
||||||
|
|
||||||
public void printStyles(Workbook wb) {
|
|
||||||
if (DEFAULTS_CLASS_CSS == null) {
|
|
||||||
DEFAULTS_CLASS_CSS = getDefaultsClassCss();
|
|
||||||
}
|
|
||||||
out.format(DEFAULTS_CLASS_CSS);
|
|
||||||
Set<CellStyle> seen = new HashSet<CellStyle>();
|
|
||||||
sheet = wb.getSheetAt(sheetNum);
|
|
||||||
Iterator<Row> rows = sheet.rowIterator();
|
|
||||||
while (rows.hasNext()) {
|
|
||||||
Row row = rows.next();
|
|
||||||
for (Cell cell : row) {
|
|
||||||
CellStyle style = cell.getCellStyle();
|
|
||||||
if (!seen.contains(style)) {
|
|
||||||
printStyle(style);
|
|
||||||
seen.add(style);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDefaultsClassCss() {
|
|
||||||
BufferedReader in = null;
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
Formatter formatter = new Formatter(sb);
|
|
||||||
try {
|
|
||||||
in = new BufferedReader(new InputStreamReader(StylerHelper.class.getResourceAsStream("excelStyle.css")));
|
|
||||||
String line;
|
|
||||||
while ((line = in.readLine()) != null) {
|
|
||||||
formatter.format("%s%n", line);
|
|
||||||
}
|
|
||||||
return formatter.toString();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Reading standard css", e);
|
|
||||||
} finally {
|
|
||||||
if (in != null) {
|
|
||||||
try {
|
|
||||||
in.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Reading standard css", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
formatter.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void printStyle(CellStyle style) {
|
|
||||||
out.format(".%s .%s {%n", DEFAULTS_CLASS, styleName(style));
|
|
||||||
styleContents(style);
|
|
||||||
out.format("}%n");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void styleContents(CellStyle style) {
|
|
||||||
if (style.getAlignment().getCode() != 2) {
|
|
||||||
styleOut("text-align", style.getAlignment().getCode(), ALIGN);
|
|
||||||
styleOut("vertical-align", style.getAlignment().getCode(), VERTICAL_ALIGN);
|
|
||||||
}
|
|
||||||
helper.colorStyles(style, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fontStyle(Font font) {
|
|
||||||
if (font.getBold())
|
|
||||||
out.format(" font-weight: bold;%n");
|
|
||||||
if (font.getItalic())
|
|
||||||
out.format(" font-style: italic;%n");
|
|
||||||
out.format(" font-family: %s;%n", font.getFontName());
|
|
||||||
|
|
||||||
int fontheight = font.getFontHeightInPoints();
|
|
||||||
if (fontheight == 9) {
|
|
||||||
fontheight = 10;
|
|
||||||
}
|
|
||||||
out.format(" font-size: %dpt;%n", fontheight);
|
|
||||||
helper.styleColor(out, "color", getColor(font));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color getColor(Font font) {
|
|
||||||
if (helper instanceof HSSFHtmlHelper) {
|
|
||||||
return ((HSSFWorkbook) sheet.getWorkbook()).getCustomPalette().getColor(font.getColor());
|
|
||||||
} else {
|
|
||||||
return ((XSSFFont) font).getXSSFColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String styleName(CellStyle style) {
|
|
||||||
if (style == null)
|
|
||||||
return "";
|
|
||||||
return String.format("style_%02x_%s", style.getIndex(), cssRandom);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <K> void styleOut(String attr, K key, Map<K, String> mapping) {
|
|
||||||
String value = mapping.get(key);
|
|
||||||
if (value != null) {
|
|
||||||
out.format(" %s: %s;%n", attr, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private interface HtmlHelper {
|
|
||||||
/**
|
|
||||||
* Outputs the appropriate CSS style for the given cell style.
|
|
||||||
*
|
|
||||||
* @param style
|
|
||||||
* The cell style.
|
|
||||||
* @param out
|
|
||||||
* The place to write the output.
|
|
||||||
*/
|
|
||||||
void colorStyles(CellStyle style, Formatter out);
|
|
||||||
|
|
||||||
void styleColor(Formatter out, String attr, Color color);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class HSSFHtmlHelper implements HtmlHelper {
|
|
||||||
private final HSSFWorkbook wb;
|
|
||||||
private final HSSFPalette colors;
|
|
||||||
|
|
||||||
//-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】--------
|
|
||||||
private HSSFColor HSSF_AUTO = new HSSFColor(0x40, -1, java.awt.Color.black);
|
|
||||||
//-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】--------
|
|
||||||
|
|
||||||
public HSSFHtmlHelper(HSSFWorkbook wb) {
|
|
||||||
this.wb = wb;
|
|
||||||
colors = wb.getCustomPalette();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void colorStyles(CellStyle style, Formatter out) {
|
|
||||||
HSSFCellStyle cs = (HSSFCellStyle) style;
|
|
||||||
out.format(" /* fill pattern = %d */%n", cs.getFillPattern());
|
|
||||||
styleColor(out, "background-color", cs.getFillForegroundColor());
|
|
||||||
styleColor(out, "color", colors.getColor(cs.getFont(wb).getColor()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void styleColor(Formatter out, String attr, short index) {
|
|
||||||
HSSFColor color = colors.getColor(index);
|
|
||||||
if (index == HSSF_AUTO.getIndex() || color == null) {
|
|
||||||
out.format(" /* %s: index = %d */%n", attr, index);
|
|
||||||
} else {
|
|
||||||
short[] rgb = color.getTriplet();
|
|
||||||
out.format(" %s: #%02x%02x%02x; /* index = %d */%n", attr, rgb[0], rgb[1], rgb[2], index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void styleColor(Formatter out, String attr, Color color) {
|
|
||||||
if (color == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
HSSFColor hSSFColor = (HSSFColor) color;
|
|
||||||
short[] rgb = hSSFColor.getTriplet();
|
|
||||||
out.format(" %s: #%02x%02x%02x; %n", attr, rgb[0], rgb[1], rgb[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of {@link HtmlHelper} for XSSF files.
|
|
||||||
*
|
|
||||||
* @author Ken Arnold, Industrious Media LLC
|
|
||||||
*/
|
|
||||||
private class XSSFHtmlHelper implements HtmlHelper {
|
|
||||||
|
|
||||||
public XSSFHtmlHelper(XSSFWorkbook wb) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void colorStyles(CellStyle style, Formatter out) {
|
|
||||||
XSSFCellStyle cs = (XSSFCellStyle) style;
|
|
||||||
styleColor(out, "background-color", cs.getFillForegroundXSSFColor());
|
|
||||||
styleColor(out, "color", cs.getFont().getXSSFColor());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void styleColor(Formatter out, String attr, Color color) {
|
|
||||||
XSSFColor xSSFColor = (XSSFColor) color;
|
|
||||||
if (color == null || xSSFColor.isAuto())
|
|
||||||
return;
|
|
||||||
|
|
||||||
byte[] rgb = xSSFColor.getRGB();
|
|
||||||
if (rgb == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
out.format(" %s: #%02x%02x%02x;%n", attr, rgb[0], rgb[1], rgb[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,387 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2013-2015 JEECG (jeecgos@163.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jeecgframework.poi.excel.imports;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
|
||||||
import org.jeecgframework.poi.excel.entity.params.ExcelImportEntity;
|
|
||||||
import org.jeecgframework.poi.excel.entity.sax.SaxReadCellEntity;
|
|
||||||
import org.jeecgframework.poi.exception.excel.ExcelImportException;
|
|
||||||
import org.jeecgframework.poi.exception.excel.enums.ExcelImportEnum;
|
|
||||||
import org.jeecgframework.poi.handler.inter.IExcelDataHandler;
|
|
||||||
import org.jeecgframework.poi.util.ExcelUtil;
|
|
||||||
import org.jeecgframework.poi.util.PoiPublicUtil;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.sql.Time;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cell 取值服务 判断类型处理数据 1.判断Excel中的类型 2.根据replace替换值 3.handler处理数据 4.判断返回类型转化数据返回
|
|
||||||
*
|
|
||||||
* @author JEECG
|
|
||||||
* @date 2014年6月26日 下午10:42:28
|
|
||||||
*/
|
|
||||||
public class CellValueServer {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(CellValueServer.class);
|
|
||||||
|
|
||||||
private List<String> hanlderList = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取单元格内的值
|
|
||||||
*
|
|
||||||
* @param xclass
|
|
||||||
* @param cell
|
|
||||||
* @param entity
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Object getCellValue(String xclass, Cell cell, ExcelImportEntity entity) {
|
|
||||||
if (cell == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
Object result = null;
|
|
||||||
// 日期格式比较特殊,和cell格式不一致
|
|
||||||
if ("class java.util.Date".equals(xclass) || ("class java.sql.Time").equals(xclass)) {
|
|
||||||
if ( CellType.NUMERIC == cell.getCellType()) {
|
|
||||||
// 日期格式
|
|
||||||
result = cell.getDateCellValue();
|
|
||||||
} else {
|
|
||||||
cell.setCellType( CellType.STRING);
|
|
||||||
result = getDateData(entity, cell.getStringCellValue());
|
|
||||||
}
|
|
||||||
if (("class java.sql.Time").equals(xclass)) {
|
|
||||||
result = new Time(((Date) result).getTime());
|
|
||||||
}
|
|
||||||
} else if ( CellType.NUMERIC == cell.getCellType()) {
|
|
||||||
result = cell.getNumericCellValue();
|
|
||||||
} else if ( CellType.BOOLEAN == cell.getCellType()) {
|
|
||||||
result = cell.getBooleanCellValue();
|
|
||||||
} else if ( CellType.FORMULA == cell.getCellType() && PoiPublicUtil.isNumber(xclass)) {
|
|
||||||
//如果单元格是表达式 且 字段是数字类型
|
|
||||||
double cellValue = cell.getNumericCellValue();
|
|
||||||
//---author:liusq---date:20221102-----for: [issues/3369]Excel导入 带公式的时候精度丢失---
|
|
||||||
//setScale方法的第一个参数设置小数点保留位数,第二个参数设置进位方法、此处是四舍五入
|
|
||||||
BigDecimal bigDecimal= new BigDecimal(cellValue).setScale(4, RoundingMode.HALF_UP);
|
|
||||||
//stripTrailingZeros方法去除末尾的0,toPlainString避免输出科学计数法的字符串
|
|
||||||
result = bigDecimal.stripTrailingZeros().toPlainString();
|
|
||||||
//---author:liusq---date:20221102-----for:[issues/3369] Excel导入 带公式的时候精度丢失---
|
|
||||||
} else {
|
|
||||||
//设置单元格类型
|
|
||||||
cell.setCellType(CellType.STRING);
|
|
||||||
result = cell.getStringCellValue();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取日期类型数据
|
|
||||||
*
|
|
||||||
* @Author JEECG
|
|
||||||
* @date 2013年11月26日
|
|
||||||
* @param entity
|
|
||||||
* @param value
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Date getDateData(ExcelImportEntity entity, String value) {
|
|
||||||
if (StringUtils.isNotEmpty(entity.getFormat()) && StringUtils.isNotEmpty(value)) {
|
|
||||||
SimpleDateFormat format = new SimpleDateFormat(entity.getFormat());
|
|
||||||
try {
|
|
||||||
return format.parse(value);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
LOGGER.error("时间格式化失败,格式化:{},值:{}", entity.getFormat(), value);
|
|
||||||
throw new ExcelImportException(ExcelImportEnum.GET_VALUE_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取cell的值
|
|
||||||
*
|
|
||||||
* @param object
|
|
||||||
* @param excelParams
|
|
||||||
* @param cell
|
|
||||||
* @param titleString
|
|
||||||
*/
|
|
||||||
public Object getValue(IExcelDataHandler dataHanlder, Object object, Cell cell, Map<String, ExcelImportEntity> excelParams, String titleString) throws Exception {
|
|
||||||
ExcelImportEntity entity = excelParams.get(titleString);
|
|
||||||
String xclass = "class java.lang.Object";
|
|
||||||
if (!(object instanceof Map)) {
|
|
||||||
Method setMethod = entity.getMethods() != null && entity.getMethods().size() > 0 ? entity.getMethods().get(entity.getMethods().size() - 1) : entity.getMethod();
|
|
||||||
Type[] ts = setMethod.getGenericParameterTypes();
|
|
||||||
xclass = ts[0].toString();
|
|
||||||
}
|
|
||||||
Object result = getCellValue(xclass, cell, entity);
|
|
||||||
if (entity != null) {
|
|
||||||
result = hanlderSuffix(entity.getSuffix(), result);
|
|
||||||
//update-begin-author:taoYan date:20180807 for:多值替换
|
|
||||||
result = replaceValue(entity.getReplace(), result,entity.isMultiReplace());
|
|
||||||
//update-end-author:taoYan date:20180807 for:多值替换
|
|
||||||
}
|
|
||||||
result = hanlderValue(dataHanlder, object, result, titleString);
|
|
||||||
return getValueByType(xclass, result, entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取cell值
|
|
||||||
*
|
|
||||||
* @param dataHanlder
|
|
||||||
* @param object
|
|
||||||
* @param cellEntity
|
|
||||||
* @param excelParams
|
|
||||||
* @param titleString
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Object getValue(IExcelDataHandler dataHanlder, Object object, SaxReadCellEntity cellEntity, Map<String, ExcelImportEntity> excelParams, String titleString) {
|
|
||||||
ExcelImportEntity entity = excelParams.get(titleString);
|
|
||||||
Method setMethod = entity.getMethods() != null && entity.getMethods().size() > 0 ? entity.getMethods().get(entity.getMethods().size() - 1) : entity.getMethod();
|
|
||||||
Type[] ts = setMethod.getGenericParameterTypes();
|
|
||||||
String xclass = ts[0].toString();
|
|
||||||
Object result = cellEntity.getValue();
|
|
||||||
result = hanlderSuffix(entity.getSuffix(), result);
|
|
||||||
//update-begin-auhtor:taoyan date:20180807 for:多值替换
|
|
||||||
result = replaceValue(entity.getReplace(), result,entity.isMultiReplace());
|
|
||||||
//update-end-auhtor:taoyan date:20180807 for:多值替换
|
|
||||||
result = hanlderValue(dataHanlder, object, result, titleString);
|
|
||||||
return getValueByType(xclass, result, entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 把后缀删除掉
|
|
||||||
*
|
|
||||||
* @param result
|
|
||||||
* @param suffix
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Object hanlderSuffix(String suffix, Object result) {
|
|
||||||
if (StringUtils.isNotEmpty(suffix) && result != null && result.toString().endsWith(suffix)) {
|
|
||||||
String temp = result.toString();
|
|
||||||
return temp.substring(0, temp.length() - suffix.length());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据返回类型获取返回值
|
|
||||||
*
|
|
||||||
* @param xclass
|
|
||||||
* @param result
|
|
||||||
* @param entity
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Object getValueByType(String xclass, Object result, ExcelImportEntity entity) {
|
|
||||||
try {
|
|
||||||
//update-begin-author:scott date:20180711 for:TASK #2950 【bug】excel 导入报错,空指针问题
|
|
||||||
if(result==null || "".equals(String.valueOf(result))){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
//update-end-author:scott date:20180711 for:TASK #2950 【bug】excel 导入报错,空指针问题
|
|
||||||
if ("class java.util.Date".equals(xclass)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if ("class java.lang.Boolean".equals(xclass) || "boolean".equals(xclass)) {
|
|
||||||
//update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
Boolean temp = Boolean.valueOf(String.valueOf(result));
|
|
||||||
//if(StringUtils.isNotEmpty(entity.getNumFormat())){
|
|
||||||
// return Boolean.valueOf(new DecimalFormat(entity.getNumFormat()).format(temp));
|
|
||||||
//}else{
|
|
||||||
return temp;
|
|
||||||
//}
|
|
||||||
//update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
}
|
|
||||||
if ("class java.lang.Double".equals(xclass) || "double".equals(xclass)) {
|
|
||||||
//update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
Double temp = Double.valueOf(String.valueOf(result));
|
|
||||||
//if(StringUtils.isNotEmpty(entity.getNumFormat())){
|
|
||||||
// return Double.valueOf(new DecimalFormat(entity.getNumFormat()).format(temp));
|
|
||||||
//}else{
|
|
||||||
return temp;
|
|
||||||
//}
|
|
||||||
//update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
}
|
|
||||||
if ("class java.lang.Long".equals(xclass) || "long".equals(xclass)) {
|
|
||||||
//update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
Long temp = Long.valueOf(ExcelUtil.remove0Suffix(String.valueOf(result)));
|
|
||||||
//if(StringUtils.isNotEmpty(entity.getNumFormat())){
|
|
||||||
// return Long.valueOf(new DecimalFormat(entity.getNumFormat()).format(temp));
|
|
||||||
//}else{
|
|
||||||
return temp;
|
|
||||||
//}
|
|
||||||
//update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
}
|
|
||||||
if ("class java.lang.Float".equals(xclass) || "float".equals(xclass)) {
|
|
||||||
//update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
Float temp = Float.valueOf(String.valueOf(result));
|
|
||||||
//if(StringUtils.isNotEmpty(entity.getNumFormat())){
|
|
||||||
// return Float.valueOf(new DecimalFormat(entity.getNumFormat()).format(temp));
|
|
||||||
//}else{
|
|
||||||
return temp;
|
|
||||||
//}
|
|
||||||
//update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
}
|
|
||||||
if ("class java.lang.Integer".equals(xclass) || "int".equals(xclass)) {
|
|
||||||
//update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
Integer temp = Integer.valueOf(ExcelUtil.remove0Suffix(String.valueOf(result)));
|
|
||||||
//if(StringUtils.isNotEmpty(entity.getNumFormat())){
|
|
||||||
// return Integer.valueOf(new DecimalFormat(entity.getNumFormat()).format(temp));
|
|
||||||
//}else{
|
|
||||||
return temp;
|
|
||||||
//}
|
|
||||||
//update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
}
|
|
||||||
if ("class java.math.BigDecimal".equals(xclass)) {
|
|
||||||
//update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
BigDecimal temp = new BigDecimal(String.valueOf(result));
|
|
||||||
//if(StringUtils.isNotEmpty(entity.getNumFormat())){
|
|
||||||
// return new BigDecimal(new DecimalFormat(entity.getNumFormat()).format(temp));
|
|
||||||
//}else{
|
|
||||||
return temp;
|
|
||||||
//}
|
|
||||||
//update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970
|
|
||||||
}
|
|
||||||
if ("class java.lang.String".equals(xclass)) {
|
|
||||||
// 针对String 类型,但是Excel获取的数据却不是String,比如Double类型,防止科学计数法
|
|
||||||
if (result instanceof String) {
|
|
||||||
//---update-begin-----autor:scott------date:20191016-------for:excel导入数字类型,去掉后缀.0------
|
|
||||||
return ExcelUtil.remove0Suffix(result);
|
|
||||||
//---update-end-----autor:scott------date:20191016-------for:excel导入数字类型,去掉后缀.0------
|
|
||||||
}
|
|
||||||
// double类型防止科学计数法
|
|
||||||
if (result instanceof Double) {
|
|
||||||
return PoiPublicUtil.doubleToString((Double) result);
|
|
||||||
}
|
|
||||||
//---update-begin-----autor:scott------date:20191016-------for:excel导入数字类型,去掉后缀.0------
|
|
||||||
return ExcelUtil.remove0Suffix(String.valueOf(result));
|
|
||||||
//---update-end-----autor:scott------date:20191016-------for:excel导入数字类型,去掉后缀.0------
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.error(e.getMessage(), e);
|
|
||||||
throw new ExcelImportException(ExcelImportEnum.GET_VALUE_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用处理接口处理值
|
|
||||||
*
|
|
||||||
* @param dataHanlder
|
|
||||||
* @param object
|
|
||||||
* @param result
|
|
||||||
* @param titleString
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Object hanlderValue(IExcelDataHandler dataHanlder, Object object, Object result, String titleString) {
|
|
||||||
if (dataHanlder == null || dataHanlder.getNeedHandlerFields() == null || dataHanlder.getNeedHandlerFields().length == 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (hanlderList == null) {
|
|
||||||
hanlderList = Arrays.asList(dataHanlder.getNeedHandlerFields());
|
|
||||||
}
|
|
||||||
if (hanlderList.contains(titleString)) {
|
|
||||||
return dataHanlder.importHandler(object, titleString, result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//update-begin-author:taoyan date:20180807 for:导入多值替换--
|
|
||||||
/**
|
|
||||||
* 导入支持多值替换
|
|
||||||
* @param replace 数据库中字典查询出来的数组
|
|
||||||
* @param result excel单元格获取的值
|
|
||||||
* @param multiReplace 是否支持多值替换
|
|
||||||
* @author taoYan
|
|
||||||
* @since 2018年8月7日
|
|
||||||
*/
|
|
||||||
private Object replaceValue(String[] replace, Object result,boolean multiReplace) {
|
|
||||||
if(result == null){
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
if(replace == null || replace.length<=0){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
String temp = String.valueOf(result);
|
|
||||||
String backValue = "";
|
|
||||||
if(temp.indexOf(",")>0 && multiReplace){
|
|
||||||
//原值中带有逗号,认为他是多值的
|
|
||||||
String multiReplaces[] = temp.split(",");
|
|
||||||
for (String str : multiReplaces) {
|
|
||||||
backValue = backValue.concat(replaceSingleValue(replace, str)+",");
|
|
||||||
}
|
|
||||||
if(backValue.equals("")){
|
|
||||||
backValue = temp;
|
|
||||||
}else{
|
|
||||||
backValue = backValue.substring(0, backValue.length()-1);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
backValue = replaceSingleValue(replace, temp);
|
|
||||||
}
|
|
||||||
//update-begin-author:liusq date:20210204 for:字典替换失败提示日志
|
|
||||||
if(replace.length>0 && backValue.equals(temp)){
|
|
||||||
LOGGER.warn("====================字典替换失败,字典值:{},要转换的导入值:{}====================", replace, temp);
|
|
||||||
}
|
|
||||||
//update-end-author:liusq date:20210204 for:字典替换失败提示日志
|
|
||||||
return backValue;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 单值替换 ,若没找到则原值返回
|
|
||||||
*/
|
|
||||||
private String replaceSingleValue(String[] replace, String temp){
|
|
||||||
String[] tempArr;
|
|
||||||
for (int i = 0; i < replace.length; i++) {
|
|
||||||
//update-begin---author:scott Date:20211220 for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析---
|
|
||||||
//tempArr = replace[i].split("_");
|
|
||||||
tempArr = getValueArr(replace[i]);
|
|
||||||
if (temp.equals(tempArr[0]) || temp.replace("_","---").equals(tempArr[0])) {
|
|
||||||
//update-begin---author:wangshuai ---date:20220422 for:导入字典替换需要将---替换成_,不然数据库会存--- ------------
|
|
||||||
if(tempArr[1].contains("---")){
|
|
||||||
return tempArr[1].replace("---","_");
|
|
||||||
}
|
|
||||||
//update-end---author:wangshuai ---date:20220422 for:导入字典替换需要将---替换成_,不然数据库会存--- --------------
|
|
||||||
return tempArr[1];
|
|
||||||
}
|
|
||||||
//update-end---author:scott Date:20211220 for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析---
|
|
||||||
}
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
//update-end-author:taoyan date:20180807 for:导入多值替换--
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字典文本中含多个下划线横岗,取最后一个(解决空值情况)
|
|
||||||
*
|
|
||||||
* @param val
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String[] getValueArr(String val) {
|
|
||||||
int i = val.lastIndexOf("_");//最后一个分隔符的位置
|
|
||||||
String[] c = new String[2];
|
|
||||||
c[0] = val.substring(0, i); //label
|
|
||||||
c[1] = val.substring(i + 1); //key
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,620 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2013-2015 JEECG (jeecgos@163.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jeecgframework.poi.excel.imports;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
||||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
|
||||||
import org.apache.poi.poifs.filesystem.FileMagic;
|
|
||||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
|
||||||
import org.apache.poi.ss.formula.functions.T;
|
|
||||||
import org.apache.poi.ss.usermodel.*;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
||||||
import org.jeecgframework.core.util.ApplicationContextUtil;
|
|
||||||
import org.jeecgframework.poi.excel.annotation.ExcelTarget;
|
|
||||||
import org.jeecgframework.poi.excel.entity.ImportParams;
|
|
||||||
import org.jeecgframework.poi.excel.entity.params.ExcelCollectionParams;
|
|
||||||
import org.jeecgframework.poi.excel.entity.params.ExcelImportEntity;
|
|
||||||
import org.jeecgframework.poi.excel.entity.result.ExcelImportResult;
|
|
||||||
import org.jeecgframework.poi.excel.entity.result.ExcelVerifyHanlderResult;
|
|
||||||
import org.jeecgframework.poi.excel.imports.base.ImportBaseService;
|
|
||||||
import org.jeecgframework.poi.excel.imports.base.ImportFileServiceI;
|
|
||||||
import org.jeecgframework.poi.excel.imports.verifys.VerifyHandlerServer;
|
|
||||||
import org.jeecgframework.poi.exception.excel.ExcelImportException;
|
|
||||||
import org.jeecgframework.poi.exception.excel.enums.ExcelImportEnum;
|
|
||||||
import org.jeecgframework.poi.util.ExcelUtil;
|
|
||||||
import org.jeecgframework.poi.util.PoiPublicUtil;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Excel 导入服务
|
|
||||||
*
|
|
||||||
* @author JEECG
|
|
||||||
* @date 2014年6月26日 下午9:20:51
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked", "hiding" })
|
|
||||||
public class ExcelImportServer extends ImportBaseService {
|
|
||||||
|
|
||||||
private final static Logger LOGGER = LoggerFactory.getLogger(ExcelImportServer.class);
|
|
||||||
|
|
||||||
private CellValueServer cellValueServer;
|
|
||||||
|
|
||||||
private VerifyHandlerServer verifyHandlerServer;
|
|
||||||
|
|
||||||
private boolean verfiyFail = false;
|
|
||||||
//仅允许字母数字字符的正则表达式
|
|
||||||
private static final Pattern lettersAndNumbersPattern = Pattern.compile("^[a-zA-Z0-9]+$") ;
|
|
||||||
/**
|
|
||||||
* 异常数据styler
|
|
||||||
*/
|
|
||||||
private CellStyle errorCellStyle;
|
|
||||||
|
|
||||||
public ExcelImportServer() {
|
|
||||||
this.cellValueServer = new CellValueServer();
|
|
||||||
this.verifyHandlerServer = new VerifyHandlerServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* 向List里面继续添加元素
|
|
||||||
*
|
|
||||||
* @param object
|
|
||||||
* @param param
|
|
||||||
* @param row
|
|
||||||
* @param titlemap
|
|
||||||
* @param targetId
|
|
||||||
* @param pictures
|
|
||||||
* @param params
|
|
||||||
*/
|
|
||||||
private void addListContinue(Object object, ExcelCollectionParams param, Row row, Map<Integer, String> titlemap, String targetId, Map<String, PictureData> pictures, ImportParams params) throws Exception {
|
|
||||||
Collection collection = (Collection) PoiPublicUtil.getMethod(param.getName(), object.getClass()).invoke(object, new Object[] {});
|
|
||||||
Object entity = PoiPublicUtil.createObject(param.getType(), targetId);
|
|
||||||
String picId;
|
|
||||||
boolean isUsed = false;// 是否需要加上这个对象
|
|
||||||
for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) {
|
|
||||||
Cell cell = row.getCell(i);
|
|
||||||
String titleString = (String) titlemap.get(i);
|
|
||||||
if (param.getExcelParams().containsKey(titleString)) {
|
|
||||||
if (param.getExcelParams().get(titleString).getType() == 2) {
|
|
||||||
picId = row.getRowNum() + "_" + i;
|
|
||||||
saveImage(object, picId, param.getExcelParams(), titleString, pictures, params);
|
|
||||||
} else {
|
|
||||||
saveFieldValue(params, entity, cell, param.getExcelParams(), titleString, row);
|
|
||||||
}
|
|
||||||
isUsed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isUsed) {
|
|
||||||
collection.add(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取key的值,针对不同类型获取不同的值
|
|
||||||
*
|
|
||||||
* @Author JEECG
|
|
||||||
* @date 2013-11-21
|
|
||||||
* @param cell
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String getKeyValue(Cell cell) {
|
|
||||||
if(cell==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Object obj = null;
|
|
||||||
switch (cell.getCellType()) {
|
|
||||||
case STRING:
|
|
||||||
obj = cell.getStringCellValue();
|
|
||||||
break;
|
|
||||||
case BOOLEAN:
|
|
||||||
obj = cell.getBooleanCellValue();
|
|
||||||
break;
|
|
||||||
case NUMERIC:
|
|
||||||
obj = cell.getNumericCellValue();
|
|
||||||
break;
|
|
||||||
case FORMULA:
|
|
||||||
obj = cell.getCellFormula();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return obj == null ? null : obj.toString().trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取保存的真实路径
|
|
||||||
*
|
|
||||||
* @param excelImportEntity
|
|
||||||
* @param object
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private String getSaveUrl(ExcelImportEntity excelImportEntity, Object object) throws Exception {
|
|
||||||
String url = "";
|
|
||||||
if (excelImportEntity.getSaveUrl().equals("upload")) {
|
|
||||||
if (excelImportEntity.getMethods() != null && excelImportEntity.getMethods().size() > 0) {
|
|
||||||
object = getFieldBySomeMethod(excelImportEntity.getMethods(), object);
|
|
||||||
}
|
|
||||||
url = object.getClass().getName().split("\\.")[object.getClass().getName().split("\\.").length - 1];
|
|
||||||
return excelImportEntity.getSaveUrl() + "/" + url.substring(0, url.lastIndexOf("Entity"));
|
|
||||||
}
|
|
||||||
return excelImportEntity.getSaveUrl();
|
|
||||||
}
|
|
||||||
//update-begin--Author:xuelin Date:20171205 for:TASK #2098 【excel问题】 Online 一对多导入失败--------------------
|
|
||||||
private <T> List<T> importExcel(Collection<T> result, Sheet sheet, Class<?> pojoClass, ImportParams params, Map<String, PictureData> pictures) throws Exception {
|
|
||||||
List collection = new ArrayList();
|
|
||||||
Map<String, ExcelImportEntity> excelParams = new HashMap<String, ExcelImportEntity>();
|
|
||||||
List<ExcelCollectionParams> excelCollection = new ArrayList<ExcelCollectionParams>();
|
|
||||||
String targetId = null;
|
|
||||||
if (!Map.class.equals(pojoClass)) {
|
|
||||||
Field fileds[] = PoiPublicUtil.getClassFields(pojoClass);
|
|
||||||
ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class);
|
|
||||||
if (etarget != null) {
|
|
||||||
targetId = etarget.value();
|
|
||||||
}
|
|
||||||
getAllExcelField(targetId, fileds, excelParams, excelCollection, pojoClass, null);
|
|
||||||
}
|
|
||||||
ignoreHeaderHandler(excelParams, params);
|
|
||||||
Iterator<Row> rows = sheet.rowIterator();
|
|
||||||
Map<Integer, String> titlemap = getTitleMap(sheet, rows, params, excelCollection);
|
|
||||||
//update-begin-author:liusq date:20220310 for:[issues/I4PU45]@excel里面新增属性fixedIndex
|
|
||||||
Set<String> keys = excelParams.keySet();
|
|
||||||
for (String key : keys) {
|
|
||||||
if (key.startsWith("FIXED_")) {
|
|
||||||
String[] arr = key.split("_");
|
|
||||||
titlemap.put(Integer.parseInt(arr[1]), key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//update-end-author:liusq date:20220310 for:[issues/I4PU45]@excel里面新增属性fixedIndex
|
|
||||||
Set<Integer> columnIndexSet = titlemap.keySet();
|
|
||||||
Integer maxColumnIndex = Collections.max(columnIndexSet);
|
|
||||||
Integer minColumnIndex = Collections.min(columnIndexSet);
|
|
||||||
Row row = null;
|
|
||||||
//跳过表头和标题行
|
|
||||||
for (int j = 0; j < params.getTitleRows() + params.getHeadRows(); j++) {
|
|
||||||
row = rows.next();
|
|
||||||
}
|
|
||||||
Object object = null;
|
|
||||||
String picId;
|
|
||||||
while (rows.hasNext() && (row == null || sheet.getLastRowNum() - row.getRowNum() > params.getLastOfInvalidRow())) {
|
|
||||||
row = rows.next();
|
|
||||||
//update-begin--Author:xuelin Date:20171017 for:TASK #2373 【bug】表改造问题,导致 3.7.1批量导入用户bug-导入不成功--------------------
|
|
||||||
// 判断是集合元素还是不是集合元素,如果是就继续加入这个集合,不是就创建新的对象
|
|
||||||
//update-begin--Author:xuelin Date:20171206 for:TASK #2451 【excel导出bug】online 一对多导入成功, 但是现在代码生成后的一对多online导入有问题了
|
|
||||||
Cell keyIndexCell = row.getCell(params.getKeyIndex());
|
|
||||||
if (excelCollection.size()>0 && StringUtils.isEmpty(getKeyValue(keyIndexCell)) && object != null && !Map.class.equals(pojoClass)) {
|
|
||||||
//update-end--Author:xuelin Date:20171206 for:TASK #2451 【excel导出bug】online 一对多导入成功, 但是现在代码生成后的一对多online导入有问题了
|
|
||||||
for (ExcelCollectionParams param : excelCollection) {
|
|
||||||
addListContinue(object, param, row, titlemap, targetId, pictures, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
object = PoiPublicUtil.createObject(pojoClass, targetId);
|
|
||||||
try {
|
|
||||||
//update-begin-author:taoyan date:20200303 for:导入图片
|
|
||||||
int firstCellNum = row.getFirstCellNum();
|
|
||||||
if(firstCellNum>minColumnIndex){
|
|
||||||
firstCellNum = minColumnIndex;
|
|
||||||
}
|
|
||||||
int lastCellNum = row.getLastCellNum();
|
|
||||||
if(lastCellNum<maxColumnIndex+1){
|
|
||||||
lastCellNum = maxColumnIndex+1;
|
|
||||||
}
|
|
||||||
for (int i = firstCellNum, le = lastCellNum; i < le; i++) {
|
|
||||||
Cell cell = row.getCell(i);
|
|
||||||
String titleString = (String) titlemap.get(i);
|
|
||||||
if (excelParams.containsKey(titleString) || Map.class.equals(pojoClass)) {
|
|
||||||
if (excelParams.get(titleString) != null && excelParams.get(titleString).getType() == 2) {
|
|
||||||
picId = row.getRowNum() + "_" + i;
|
|
||||||
saveImage(object, picId, excelParams, titleString, pictures, params);
|
|
||||||
} else {
|
|
||||||
if(params.getImageList()!=null && params.getImageList().contains(titleString)){
|
|
||||||
if (pictures != null) {
|
|
||||||
picId = row.getRowNum() + "_" + i;
|
|
||||||
PictureData image = pictures.get(picId);
|
|
||||||
if(image!=null){
|
|
||||||
byte[] data = image.getData();
|
|
||||||
params.getDataHanlder().setMapValue((Map) object, titleString, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
saveFieldValue(params, object, cell, excelParams, titleString, row);
|
|
||||||
}
|
|
||||||
//update-end-author:taoyan date:20200303 for:导入图片
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ExcelCollectionParams param : excelCollection) {
|
|
||||||
addListContinue(object, param, row, titlemap, targetId, pictures, params);
|
|
||||||
}
|
|
||||||
//update-begin-author:taoyan date:20210526 for:autopoi导入excel 如果单元格被设置边框,即使没有内容也会被当做是一条数据导入 #2484
|
|
||||||
if(isNotNullObject(pojoClass, object)){
|
|
||||||
collection.add(object);
|
|
||||||
}
|
|
||||||
//update-end-author:taoyan date:20210526 for:autopoi导入excel 如果单元格被设置边框,即使没有内容也会被当做是一条数据导入 #2484
|
|
||||||
} catch (ExcelImportException e) {
|
|
||||||
if (!e.getType().equals(ExcelImportEnum.VERIFY_ERROR)) {
|
|
||||||
throw new ExcelImportException(e.getType(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//update-end--Author:xuelin Date:20171017 for:TASK #2373 【bug】表改造问题,导致 3.7.1批量导入用户bug-导入不成功--------------------
|
|
||||||
}
|
|
||||||
return collection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断当前对象不是空
|
|
||||||
* @param pojoClass
|
|
||||||
* @param object
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isNotNullObject(Class pojoClass, Object object){
|
|
||||||
try {
|
|
||||||
Method method = pojoClass.getMethod("isNullObject");
|
|
||||||
if(method!=null){
|
|
||||||
Object flag = method.invoke(object);
|
|
||||||
if(flag!=null && true == Boolean.parseBoolean(flag.toString())){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
LOGGER.debug("未定义方法 isNullObject");
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
LOGGER.warn("没有权限访问该方法 isNullObject");
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
LOGGER.warn("方法调用失败 isNullObject");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取忽略的表头信息
|
|
||||||
* @param excelParams
|
|
||||||
* @param params
|
|
||||||
*/
|
|
||||||
private void ignoreHeaderHandler(Map<String, ExcelImportEntity> excelParams,ImportParams params){
|
|
||||||
List<String> ignoreList = new ArrayList<>();
|
|
||||||
for(String key:excelParams.keySet()){
|
|
||||||
String temp = excelParams.get(key).getGroupName();
|
|
||||||
if(temp!=null && temp.length()>0){
|
|
||||||
ignoreList.add(temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params.setIgnoreHeaderList(ignoreList);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取表格字段列名对应信息
|
|
||||||
*
|
|
||||||
* @param rows
|
|
||||||
* @param params
|
|
||||||
* @param excelCollection
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Map<Integer, String> getTitleMap(Sheet sheet, Iterator<Row> rows, ImportParams params, List<ExcelCollectionParams> excelCollection) throws Exception {
|
|
||||||
Map<Integer, String> titlemap = new HashMap<Integer, String>();
|
|
||||||
Iterator<Cell> cellTitle = null;
|
|
||||||
String collectionName = null;
|
|
||||||
ExcelCollectionParams collectionParams = null;
|
|
||||||
Row headRow = null;
|
|
||||||
int headBegin = params.getTitleRows();
|
|
||||||
//update_begin-author:taoyan date:2020622 for:当文件行数小于代码里设置的TitleRows时headRow一直为空就会出现死循环
|
|
||||||
int allRowNum = sheet.getPhysicalNumberOfRows();
|
|
||||||
//找到首行表头,每个sheet都必须至少有一行表头
|
|
||||||
while(headRow == null && headBegin < allRowNum){
|
|
||||||
headRow = sheet.getRow(headBegin++);
|
|
||||||
}
|
|
||||||
if(headRow==null){
|
|
||||||
throw new Exception("不识别该文件");
|
|
||||||
}
|
|
||||||
//update-end-author:taoyan date:2020622 for:当文件行数小于代码里设置的TitleRows时headRow一直为空就会出现死循环
|
|
||||||
|
|
||||||
//设置表头行数
|
|
||||||
if (ExcelUtil.isMergedRegion(sheet, headRow.getRowNum(), 0)) {
|
|
||||||
params.setHeadRows(2);
|
|
||||||
}else{
|
|
||||||
params.setHeadRows(1);
|
|
||||||
}
|
|
||||||
cellTitle = headRow.cellIterator();
|
|
||||||
while (cellTitle.hasNext()) {
|
|
||||||
Cell cell = cellTitle.next();
|
|
||||||
String value = getKeyValue(cell);
|
|
||||||
if (StringUtils.isNotEmpty(value)) {
|
|
||||||
titlemap.put(cell.getColumnIndex(), value);//加入表头列表
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//多行表头
|
|
||||||
for (int j = headBegin; j < headBegin + params.getHeadRows()-1; j++) {
|
|
||||||
headRow = sheet.getRow(j);
|
|
||||||
cellTitle = headRow.cellIterator();
|
|
||||||
while (cellTitle.hasNext()) {
|
|
||||||
Cell cell = cellTitle.next();
|
|
||||||
String value = getKeyValue(cell);
|
|
||||||
if (StringUtils.isNotEmpty(value)) {
|
|
||||||
int columnIndex = cell.getColumnIndex();
|
|
||||||
//当前cell的上一行是否为合并单元格
|
|
||||||
if(ExcelUtil.isMergedRegion(sheet, cell.getRowIndex()-1, columnIndex)){
|
|
||||||
collectionName = ExcelUtil.getMergedRegionValue(sheet, cell.getRowIndex()-1, columnIndex);
|
|
||||||
if(params.isIgnoreHeader(collectionName)){
|
|
||||||
titlemap.put(cell.getColumnIndex(), value);
|
|
||||||
}else{
|
|
||||||
titlemap.put(cell.getColumnIndex(), collectionName + "_" + value);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
//update-begin-author:taoyan date:20220112 for: JT640 【online】导入 无论一对一还是一对多 如果子表只有一个字段 则子表无数据
|
|
||||||
// 上一行不是合并的情况下另有一种特殊的场景: 如果当前单元格和上面的单元格同一列 即子表字段只有一个 所以标题没有出现跨列
|
|
||||||
String prefixTitle = titlemap.get(cell.getColumnIndex());
|
|
||||||
if(prefixTitle!=null && !"".equals(prefixTitle)){
|
|
||||||
titlemap.put(cell.getColumnIndex(), prefixTitle + "_" +value);
|
|
||||||
}else{
|
|
||||||
titlemap.put(cell.getColumnIndex(), value);
|
|
||||||
}
|
|
||||||
//update-end-author:taoyan date:20220112 for: JT640 【online】导入 无论一对一还是一对多 如果子表只有一个字段 则子表无数据
|
|
||||||
}
|
|
||||||
/*int i = cell.getColumnIndex();
|
|
||||||
// 用以支持重名导入
|
|
||||||
if (titlemap.containsKey(i)) {
|
|
||||||
collectionName = titlemap.get(i);
|
|
||||||
collectionParams = getCollectionParams(excelCollection, collectionName);
|
|
||||||
titlemap.put(i, collectionName + "_" + value);
|
|
||||||
} else if (StringUtils.isNotEmpty(collectionName) && collectionParams.getExcelParams().containsKey(collectionName + "_" + value)) {
|
|
||||||
titlemap.put(i, collectionName + "_" + value);
|
|
||||||
} else {
|
|
||||||
collectionName = null;
|
|
||||||
collectionParams = null;
|
|
||||||
}
|
|
||||||
if (StringUtils.isEmpty(collectionName)) {
|
|
||||||
titlemap.put(i, value);
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return titlemap;
|
|
||||||
}
|
|
||||||
//update-end--Author:xuelin Date:20171205 for:TASK #2098 【excel问题】 Online 一对多导入失败--------------------
|
|
||||||
/**
|
|
||||||
* 获取这个名称对应的集合信息
|
|
||||||
*
|
|
||||||
* @param excelCollection
|
|
||||||
* @param collectionName
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private ExcelCollectionParams getCollectionParams(List<ExcelCollectionParams> excelCollection, String collectionName) {
|
|
||||||
for (ExcelCollectionParams excelCollectionParams : excelCollection) {
|
|
||||||
if (collectionName.equals(excelCollectionParams.getExcelName())) {
|
|
||||||
return excelCollectionParams;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Excel 导入 field 字段类型 Integer,Long,Double,Date,String,Boolean
|
|
||||||
*
|
|
||||||
* @param inputstream
|
|
||||||
* @param pojoClass
|
|
||||||
* @param params
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public ExcelImportResult importExcelByIs(InputStream inputstream, Class<?> pojoClass, ImportParams params) throws Exception {
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug("Excel import start ,class is {}", pojoClass);
|
|
||||||
}
|
|
||||||
List<T> result = new ArrayList<T>();
|
|
||||||
Workbook book = null;
|
|
||||||
boolean isXSSFWorkbook = false;
|
|
||||||
if (!(inputstream.markSupported())) {
|
|
||||||
inputstream = new PushbackInputStream(inputstream, 8);
|
|
||||||
}
|
|
||||||
//begin-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】--------
|
|
||||||
//------poi4.x begin----
|
|
||||||
// FileMagic fm = FileMagic.valueOf(FileMagic.prepareToCheckMagic(inputstream));
|
|
||||||
// if(FileMagic.OLE2 == fm){
|
|
||||||
// isXSSFWorkbook=false;
|
|
||||||
// }
|
|
||||||
book = WorkbookFactory.create(inputstream);
|
|
||||||
if(book instanceof XSSFWorkbook){
|
|
||||||
isXSSFWorkbook=true;
|
|
||||||
}
|
|
||||||
LOGGER.info(" >>> poi3升级到4.0兼容改造工作, isXSSFWorkbook = " +isXSSFWorkbook);
|
|
||||||
//end-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】--------
|
|
||||||
|
|
||||||
//begin-------author:liusq------date:20210313-----for:-------多sheet导入改造点--------
|
|
||||||
//获取导入文本的sheet数
|
|
||||||
//update-begin-author:taoyan date:20211210 for:https://gitee.com/jeecg/jeecg-boot/issues/I45C32 导入空白sheet报错
|
|
||||||
if(params.getSheetNum()==0){
|
|
||||||
int sheetNum = book.getNumberOfSheets();
|
|
||||||
if(sheetNum>0){
|
|
||||||
params.setSheetNum(sheetNum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//update-end-author:taoyan date:20211210 for:https://gitee.com/jeecg/jeecg-boot/issues/I45C32 导入空白sheet报错
|
|
||||||
//end-------author:liusq------date:20210313-----for:-------多sheet导入改造点--------
|
|
||||||
createErrorCellStyle(book);
|
|
||||||
Map<String, PictureData> pictures;
|
|
||||||
// 获取指定的sheet名称
|
|
||||||
String sheetName = params.getSheetName();
|
|
||||||
|
|
||||||
//update-begin-author:liusq date:20220609 for:issues/I57UPC excel导入 ImportParams 中没有startSheetIndex参数
|
|
||||||
for (int i = params.getStartSheetIndex(); i < params.getStartSheetIndex()
|
|
||||||
+ params.getSheetNum(); i++) {
|
|
||||||
//update-end-author:liusq date:20220609 for:issues/I57UPC excel导入 ImportParams 中没有startSheetIndex参数
|
|
||||||
|
|
||||||
//update-begin-author:taoyan date:2023-3-4 for: 导入数据支持指定sheet名称
|
|
||||||
if(sheetName!=null && !"".equals(sheetName)){
|
|
||||||
Sheet tempSheet = book.getSheetAt(i);
|
|
||||||
if(!sheetName.equals(tempSheet.getSheetName())){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//update-end-author:taoyan date:2023-3-4 for: 导入数据支持指定sheet名称
|
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug(" start to read excel by is ,startTime is {}", System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
if (isXSSFWorkbook) {
|
|
||||||
pictures = PoiPublicUtil.getSheetPictrues07((XSSFSheet) book.getSheetAt(i), (XSSFWorkbook) book);
|
|
||||||
} else {
|
|
||||||
pictures = PoiPublicUtil.getSheetPictrues03((HSSFSheet) book.getSheetAt(i), (HSSFWorkbook) book);
|
|
||||||
}
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug(" end to read excel by is ,endTime is {}", new Date().getTime());
|
|
||||||
}
|
|
||||||
result.addAll(importExcel(result, book.getSheetAt(i), pojoClass, params, pictures));
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug(" end to read excel list by pos ,endTime is {}", new Date().getTime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (params.isNeedSave()) {
|
|
||||||
saveThisExcel(params, pojoClass, isXSSFWorkbook, book);
|
|
||||||
}
|
|
||||||
return new ExcelImportResult(result, verfiyFail, book);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param is
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static byte[] getBytes(InputStream is) throws IOException {
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
int len;
|
|
||||||
byte[] data = new byte[100000];
|
|
||||||
while ((len = is.read(data, 0, data.length)) != -1) {
|
|
||||||
buffer.write(data, 0, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.flush();
|
|
||||||
return buffer.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存字段值(获取值,校验值,追加错误信息)
|
|
||||||
*
|
|
||||||
* @param params
|
|
||||||
* @param object
|
|
||||||
* @param cell
|
|
||||||
* @param excelParams
|
|
||||||
* @param titleString
|
|
||||||
* @param row
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private void saveFieldValue(ImportParams params, Object object, Cell cell, Map<String, ExcelImportEntity> excelParams, String titleString, Row row) throws Exception {
|
|
||||||
Object value = cellValueServer.getValue(params.getDataHanlder(), object, cell, excelParams, titleString);
|
|
||||||
if (object instanceof Map) {
|
|
||||||
if (params.getDataHanlder() != null) {
|
|
||||||
params.getDataHanlder().setMapValue((Map) object, titleString, value);
|
|
||||||
} else {
|
|
||||||
((Map) object).put(titleString, value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ExcelVerifyHanlderResult verifyResult = verifyHandlerServer.verifyData(object, value, titleString, excelParams.get(titleString).getVerify(), params.getVerifyHanlder());
|
|
||||||
if (verifyResult.isSuccess()) {
|
|
||||||
setValues(excelParams.get(titleString), object, value);
|
|
||||||
} else {
|
|
||||||
Cell errorCell = row.createCell(row.getLastCellNum());
|
|
||||||
errorCell.setCellValue(verifyResult.getMsg());
|
|
||||||
errorCell.setCellStyle(errorCellStyle);
|
|
||||||
verfiyFail = true;
|
|
||||||
throw new ExcelImportException(ExcelImportEnum.VERIFY_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param object
|
|
||||||
* @param picId
|
|
||||||
* @param excelParams
|
|
||||||
* @param titleString
|
|
||||||
* @param pictures
|
|
||||||
* @param params
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private void saveImage(Object object, String picId, Map<String, ExcelImportEntity> excelParams, String titleString, Map<String, PictureData> pictures, ImportParams params) throws Exception {
|
|
||||||
if (pictures == null || pictures.get(picId)==null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PictureData image = pictures.get(picId);
|
|
||||||
byte[] data = image.getData();
|
|
||||||
String fileName = "pic" + Math.round(Math.random() * 100000000000L);
|
|
||||||
fileName += "." + PoiPublicUtil.getFileExtendName(data);
|
|
||||||
//update-beign-author:taoyan date:20200302 for:【多任务】online 专项集中问题 LOWCOD-159
|
|
||||||
int saveType = excelParams.get(titleString).getSaveType();
|
|
||||||
if ( saveType == 1) {
|
|
||||||
String path = PoiPublicUtil.getWebRootPath(getSaveUrl(excelParams.get(titleString), object));
|
|
||||||
File savefile = new File(path);
|
|
||||||
if (!savefile.exists()) {
|
|
||||||
savefile.mkdirs();
|
|
||||||
}
|
|
||||||
savefile = new File(path + "/" + fileName);
|
|
||||||
FileOutputStream fos = new FileOutputStream(savefile);
|
|
||||||
fos.write(data);
|
|
||||||
fos.close();
|
|
||||||
setValues(excelParams.get(titleString), object, getSaveUrl(excelParams.get(titleString), object) + "/" + fileName);
|
|
||||||
} else if(saveType==2) {
|
|
||||||
setValues(excelParams.get(titleString), object, data);
|
|
||||||
} else {
|
|
||||||
ImportFileServiceI importFileService = null;
|
|
||||||
try {
|
|
||||||
importFileService = ApplicationContextUtil.getContext().getBean(ImportFileServiceI.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println(e.getMessage());
|
|
||||||
}
|
|
||||||
if(importFileService!=null){
|
|
||||||
//update-beign-author:liusq date:20230411 for:【issue/4415】autopoi-web 导入图片字段时无法指定保存路径
|
|
||||||
String saveUrl = excelParams.get(titleString).getSaveUrl();
|
|
||||||
String dbPath;
|
|
||||||
if(StringUtils.isNotBlank(saveUrl)){
|
|
||||||
LOGGER.debug("图片保存路径saveUrl = "+saveUrl);
|
|
||||||
Matcher matcher = lettersAndNumbersPattern.matcher(saveUrl);
|
|
||||||
if(!matcher.matches()){
|
|
||||||
LOGGER.warn("图片保存路径格式错误,只能设置字母和数字的组合!");
|
|
||||||
dbPath = importFileService.doUpload(data);
|
|
||||||
}else{
|
|
||||||
dbPath = importFileService.doUpload(data,saveUrl);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
dbPath = importFileService.doUpload(data);
|
|
||||||
}
|
|
||||||
//update-end-author:liusq date:20230411 for:【issue/4415】autopoi-web 导入图片字段时无法指定保存路径
|
|
||||||
setValues(excelParams.get(titleString), object, dbPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//update-end-author:taoyan date:20200302 for:【多任务】online 专项集中问题 LOWCOD-159
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createErrorCellStyle(Workbook workbook) {
|
|
||||||
errorCellStyle = workbook.createCellStyle();
|
|
||||||
Font font = workbook.createFont();
|
|
||||||
font.setColor(Font.COLOR_RED);
|
|
||||||
errorCellStyle.setFont(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2013-2015 JEECG (jeecgos@163.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jeecgframework.poi.excel.imports.sax;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
|
||||||
import org.apache.poi.xssf.eventusermodel.XSSFReader;
|
|
||||||
import org.apache.poi.xssf.model.SharedStringsTable;
|
|
||||||
import org.jeecgframework.poi.excel.entity.ImportParams;
|
|
||||||
import org.jeecgframework.poi.excel.imports.sax.parse.ISaxRowRead;
|
|
||||||
import org.jeecgframework.poi.excel.imports.sax.parse.SaxRowRead;
|
|
||||||
import org.jeecgframework.poi.exception.excel.ExcelImportException;
|
|
||||||
import org.jeecgframework.poi.handler.inter.IExcelReadRowHanlder;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.xml.sax.ContentHandler;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import org.xml.sax.XMLReader;
|
|
||||||
import org.xml.sax.helpers.XMLReaderFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 基于SAX Excel大数据读取,读取Excel 07版本,不支持图片读取
|
|
||||||
*
|
|
||||||
* @author JEECG
|
|
||||||
* @date 2014年12月29日 下午9:41:38
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
public class SaxReadExcel {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(SaxReadExcel.class);
|
|
||||||
|
|
||||||
public <T> List<T> readExcel(InputStream inputstream, Class<?> pojoClass, ImportParams params, ISaxRowRead rowRead, IExcelReadRowHanlder hanlder) {
|
|
||||||
try {
|
|
||||||
OPCPackage opcPackage = OPCPackage.open(inputstream);
|
|
||||||
return readExcel(opcPackage, pojoClass, params, rowRead, hanlder);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.error(e.getMessage(), e);
|
|
||||||
throw new ExcelImportException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> List<T> readExcel(OPCPackage opcPackage, Class<?> pojoClass, ImportParams params, ISaxRowRead rowRead, IExcelReadRowHanlder hanlder) {
|
|
||||||
try {
|
|
||||||
XSSFReader xssfReader = new XSSFReader(opcPackage);
|
|
||||||
SharedStringsTable sst = (SharedStringsTable) xssfReader.getSharedStringsTable();
|
|
||||||
if (rowRead == null) {
|
|
||||||
rowRead = new SaxRowRead(pojoClass, params, hanlder);
|
|
||||||
}
|
|
||||||
XMLReader parser = fetchSheetParser(sst, rowRead);
|
|
||||||
Iterator<InputStream> sheets = xssfReader.getSheetsData();
|
|
||||||
int sheetIndex = 0;
|
|
||||||
while (sheets.hasNext() && sheetIndex < params.getSheetNum()) {
|
|
||||||
sheetIndex++;
|
|
||||||
InputStream sheet = sheets.next();
|
|
||||||
InputSource sheetSource = new InputSource(sheet);
|
|
||||||
parser.parse(sheetSource);
|
|
||||||
sheet.close();
|
|
||||||
}
|
|
||||||
return rowRead.getList();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.error(e.getMessage(), e);
|
|
||||||
throw new ExcelImportException("SAX导入数据失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private XMLReader fetchSheetParser(SharedStringsTable sst, ISaxRowRead rowRead) throws SAXException {
|
|
||||||
XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
|
|
||||||
ContentHandler handler = new SheetHandler(sst, rowRead);
|
|
||||||
parser.setContentHandler(handler);
|
|
||||||
return parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2013-2015 JEECG (jeecgos@163.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jeecgframework.poi.excel.imports.sax;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.DateUtil;
|
|
||||||
import org.apache.poi.xssf.model.SharedStringsTable;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
|
|
||||||
import org.jeecgframework.poi.excel.entity.enmus.CellValueType;
|
|
||||||
import org.jeecgframework.poi.excel.entity.sax.SaxReadCellEntity;
|
|
||||||
import org.jeecgframework.poi.excel.imports.sax.parse.ISaxRowRead;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 回调接口
|
|
||||||
*
|
|
||||||
* @author JEECG
|
|
||||||
* @date 2014年12月29日 下午9:50:09
|
|
||||||
*/
|
|
||||||
public class SheetHandler extends DefaultHandler {
|
|
||||||
|
|
||||||
private SharedStringsTable sst;
|
|
||||||
private String lastContents;
|
|
||||||
|
|
||||||
// 当前行
|
|
||||||
private int curRow = 0;
|
|
||||||
// 当前列
|
|
||||||
private int curCol = 0;
|
|
||||||
|
|
||||||
private CellValueType type;
|
|
||||||
|
|
||||||
private ISaxRowRead read;
|
|
||||||
|
|
||||||
// 存储行记录的容器
|
|
||||||
private List<SaxReadCellEntity> rowlist = Lists.newArrayList();
|
|
||||||
|
|
||||||
public SheetHandler(SharedStringsTable sst, ISaxRowRead rowRead) {
|
|
||||||
this.sst = sst;
|
|
||||||
this.read = rowRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
|
|
||||||
// 置空
|
|
||||||
lastContents = "";
|
|
||||||
// c => 单元格
|
|
||||||
if ("c".equals(name)) {
|
|
||||||
// 如果下一个元素是 SST 的索引,则将nextIsString标记为true
|
|
||||||
String cellType = attributes.getValue("t");
|
|
||||||
if ("s".equals(cellType)) {
|
|
||||||
type = CellValueType.String;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 日期格式
|
|
||||||
cellType = attributes.getValue("s");
|
|
||||||
if ("1".equals(cellType)) {
|
|
||||||
type = CellValueType.Date;
|
|
||||||
} else if ("2".equals(cellType)) {
|
|
||||||
type = CellValueType.Number;
|
|
||||||
}
|
|
||||||
} else if ("t".equals(name)) {// 当元素为t时
|
|
||||||
type = CellValueType.TElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void endElement(String uri, String localName, String name) throws SAXException {
|
|
||||||
|
|
||||||
// 根据SST的索引值的到单元格的真正要存储的字符串
|
|
||||||
// 这时characters()方法可能会被调用多次
|
|
||||||
if (CellValueType.String.equals(type)) {
|
|
||||||
try {
|
|
||||||
int idx = Integer.parseInt(lastContents);
|
|
||||||
lastContents = sst.getItemAt(idx).getString();
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// t元素也包含字符串
|
|
||||||
if (CellValueType.TElement.equals(type)) {
|
|
||||||
String value = lastContents.trim();
|
|
||||||
rowlist.add(curCol, new SaxReadCellEntity(CellValueType.String, value));
|
|
||||||
curCol++;
|
|
||||||
type = CellValueType.None;
|
|
||||||
// v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引
|
|
||||||
// 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符
|
|
||||||
} else if ("v".equals(name)) {
|
|
||||||
String value = lastContents.trim();
|
|
||||||
value = value.equals("") ? " " : value;
|
|
||||||
if (CellValueType.Date.equals(type)) {
|
|
||||||
Date date = DateUtil.getJavaDate(Double.valueOf(value));
|
|
||||||
rowlist.add(curCol, new SaxReadCellEntity(CellValueType.Date, date));
|
|
||||||
} else if (CellValueType.Number.equals(type)) {
|
|
||||||
BigDecimal bd = new BigDecimal(value);
|
|
||||||
rowlist.add(curCol, new SaxReadCellEntity(CellValueType.Number, bd));
|
|
||||||
} else if (CellValueType.String.equals(type)) {
|
|
||||||
rowlist.add(curCol, new SaxReadCellEntity(CellValueType.String, value));
|
|
||||||
}
|
|
||||||
curCol++;
|
|
||||||
} else if (name.equals("row")) {// 如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法
|
|
||||||
read.parse(curRow, rowlist);
|
|
||||||
rowlist.clear();
|
|
||||||
curRow++;
|
|
||||||
curCol = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void characters(char[] ch, int start, int length) throws SAXException {
|
|
||||||
// 得到单元格内容的值
|
|
||||||
lastContents += new String(ch, start, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,327 +0,0 @@
|
|||||||
package org.jeecgframework.poi.util;
|
|
||||||
/**
|
|
||||||
* @author Link Xue
|
|
||||||
* @version 20171025
|
|
||||||
* POI对EXCEL操作工具
|
|
||||||
*/
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.apache.poi.EncryptedDocumentException;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
||||||
import org.apache.poi.ss.usermodel.*;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
||||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
|
||||||
import org.apache.poi.ss.util.CellRangeAddress;
|
|
||||||
|
|
||||||
public class ExcelUtil {
|
|
||||||
|
|
||||||
public static void main(String[] args){
|
|
||||||
//读取excel数据
|
|
||||||
ArrayList<Map<String,String>> result = ExcelUtil.readExcelToObj("D:\\上传表.xlsx");
|
|
||||||
for(Map<String,String> map:result){
|
|
||||||
System.out.println(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 读取excel数据
|
|
||||||
* @param path
|
|
||||||
*/
|
|
||||||
public static ArrayList<Map<String,String>> readExcelToObj(String path) {
|
|
||||||
|
|
||||||
Workbook wb = null;
|
|
||||||
ArrayList<Map<String,String>> result = null;
|
|
||||||
try {
|
|
||||||
wb = WorkbookFactory.create(new File(path));
|
|
||||||
result = readExcel(wb, 0, 2, 0);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取excel文件
|
|
||||||
* @param wb
|
|
||||||
* @param sheetIndex sheet页下标:从0开始
|
|
||||||
* @param startReadLine 开始读取的行:从0开始
|
|
||||||
* @param tailLine 去除最后读取的行
|
|
||||||
*/
|
|
||||||
public static ArrayList<Map<String,String>> readExcel(Workbook wb,int sheetIndex, int startReadLine, int tailLine) {
|
|
||||||
Sheet sheet = wb.getSheetAt(sheetIndex);
|
|
||||||
Row row = null;
|
|
||||||
ArrayList<Map<String,String>> result = new ArrayList<Map<String,String>>();
|
|
||||||
for(int i=startReadLine; i<sheet.getLastRowNum()-tailLine+1; i++) {
|
|
||||||
|
|
||||||
row = sheet.getRow(i);
|
|
||||||
Map<String,String> map = new HashMap<String,String>();
|
|
||||||
for(Cell c : row) {
|
|
||||||
String returnStr = "";
|
|
||||||
|
|
||||||
boolean isMerge = isMergedRegion(sheet, i, c.getColumnIndex());
|
|
||||||
//判断是否具有合并单元格
|
|
||||||
if(isMerge) {
|
|
||||||
String rs = getMergedRegionValue(sheet, row.getRowNum(), c.getColumnIndex());
|
|
||||||
// System.out.print(rs + "------ ");
|
|
||||||
returnStr = rs;
|
|
||||||
}else {
|
|
||||||
// System.out.print(c.getRichStringCellValue()+"++++ ");
|
|
||||||
returnStr = c.getRichStringCellValue().getString();
|
|
||||||
}
|
|
||||||
if(c.getColumnIndex()==0){
|
|
||||||
map.put("id",returnStr);
|
|
||||||
}else if(c.getColumnIndex()==1){
|
|
||||||
map.put("base",returnStr);
|
|
||||||
}else if(c.getColumnIndex()==2){
|
|
||||||
map.put("siteName",returnStr);
|
|
||||||
}else if(c.getColumnIndex()==3){
|
|
||||||
map.put("articleName",returnStr);
|
|
||||||
}else if(c.getColumnIndex()==4){
|
|
||||||
map.put("mediaName",returnStr);
|
|
||||||
}else if(c.getColumnIndex()==5){
|
|
||||||
map.put("mediaUrl",returnStr);
|
|
||||||
}else if(c.getColumnIndex()==6){
|
|
||||||
map.put("newsSource",returnStr);
|
|
||||||
}else if(c.getColumnIndex()==7){
|
|
||||||
map.put("isRecord",returnStr);
|
|
||||||
}else if(c.getColumnIndex()==8){
|
|
||||||
map.put("recordTime",returnStr);
|
|
||||||
}else if(c.getColumnIndex()==9){
|
|
||||||
map.put("remark",returnStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
result.add(map);
|
|
||||||
// System.out.println();
|
|
||||||
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取合并单元格的值
|
|
||||||
* @param sheet
|
|
||||||
* @param row
|
|
||||||
* @param column
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getMergedRegionValue(Sheet sheet ,int row , int column){
|
|
||||||
int sheetMergeCount = sheet.getNumMergedRegions();
|
|
||||||
|
|
||||||
for(int i = 0 ; i < sheetMergeCount ; i++){
|
|
||||||
CellRangeAddress ca = sheet.getMergedRegion(i);
|
|
||||||
int firstColumn = ca.getFirstColumn();
|
|
||||||
int lastColumn = ca.getLastColumn();
|
|
||||||
int firstRow = ca.getFirstRow();
|
|
||||||
int lastRow = ca.getLastRow();
|
|
||||||
|
|
||||||
if(row >= firstRow && row <= lastRow){
|
|
||||||
|
|
||||||
if(column >= firstColumn && column <= lastColumn){
|
|
||||||
Row fRow = sheet.getRow(firstRow);
|
|
||||||
Cell fCell = fRow.getCell(firstColumn);
|
|
||||||
return getCellValue(fCell) ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断合并了行
|
|
||||||
* @param sheet
|
|
||||||
* @param row
|
|
||||||
* @param column
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean isMergedRow(Sheet sheet,int row ,int column) {
|
|
||||||
int sheetMergeCount = sheet.getNumMergedRegions();
|
|
||||||
for (int i = 0; i < sheetMergeCount; i++) {
|
|
||||||
CellRangeAddress range = sheet.getMergedRegion(i);
|
|
||||||
int firstColumn = range.getFirstColumn();
|
|
||||||
int lastColumn = range.getLastColumn();
|
|
||||||
int firstRow = range.getFirstRow();
|
|
||||||
int lastRow = range.getLastRow();
|
|
||||||
if(row == firstRow && row == lastRow){
|
|
||||||
if(column >= firstColumn && column <= lastColumn){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断指定的单元格是否是合并单元格
|
|
||||||
* @param sheet
|
|
||||||
* @param row 行下标
|
|
||||||
* @param column 列下标
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean isMergedRegion(Sheet sheet,int row ,int column) {
|
|
||||||
int sheetMergeCount = sheet.getNumMergedRegions();
|
|
||||||
for (int i = 0; i < sheetMergeCount; i++) {
|
|
||||||
CellRangeAddress range = sheet.getMergedRegion(i);
|
|
||||||
int firstColumn = range.getFirstColumn();
|
|
||||||
int lastColumn = range.getLastColumn();
|
|
||||||
int firstRow = range.getFirstRow();
|
|
||||||
int lastRow = range.getLastRow();
|
|
||||||
if(row >= firstRow && row <= lastRow){
|
|
||||||
if(column >= firstColumn && column <= lastColumn){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断sheet页中是否含有合并单元格
|
|
||||||
* @param sheet
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean hasMerged(Sheet sheet) {
|
|
||||||
return sheet.getNumMergedRegions() > 0 ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 合并单元格
|
|
||||||
* @param sheet
|
|
||||||
* @param firstRow 开始行
|
|
||||||
* @param lastRow 结束行
|
|
||||||
* @param firstCol 开始列
|
|
||||||
* @param lastCol 结束列
|
|
||||||
*/
|
|
||||||
public static void mergeRegion(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) {
|
|
||||||
//update-begin-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B
|
|
||||||
try{
|
|
||||||
sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol));
|
|
||||||
}catch (IllegalArgumentException e){
|
|
||||||
e.fillInStackTrace();
|
|
||||||
}
|
|
||||||
//update-end-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取单元格的值
|
|
||||||
* @param cell
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getCellValue(Cell cell){
|
|
||||||
|
|
||||||
if(cell == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cell.getCellType() == CellType.STRING){
|
|
||||||
|
|
||||||
return cell.getStringCellValue();
|
|
||||||
|
|
||||||
}else if(cell.getCellType() == CellType.BOOLEAN){
|
|
||||||
|
|
||||||
return String.valueOf(cell.getBooleanCellValue());
|
|
||||||
|
|
||||||
}else if(cell.getCellType() == CellType.FORMULA){
|
|
||||||
|
|
||||||
return cell.getCellFormula() ;
|
|
||||||
|
|
||||||
}else if(cell.getCellType() == CellType.NUMERIC){
|
|
||||||
|
|
||||||
return String.valueOf(cell.getNumericCellValue());
|
|
||||||
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数字值,去掉.0后缀
|
|
||||||
* @param cell
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String remove0Suffix(Object value){
|
|
||||||
if(value!=null) {
|
|
||||||
// update-begin-author:taoyan date:20210526 for:对于特殊的字符串 V1.0 也进行了去.0操作 这是不合理的
|
|
||||||
String val = value.toString();
|
|
||||||
if(val.endsWith(".0") && isNumberString(val)) {
|
|
||||||
val = val.replace(".0", "");
|
|
||||||
}
|
|
||||||
// update-end-author:taoyan date:20210526 for:对于特殊的字符串 V1.0 也进行了去.0操作 这是不合理的
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断给定的字符串是不是只有数字
|
|
||||||
* @param str
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private static boolean isNumberString(String str){
|
|
||||||
String regex = "^[0-9]+\\.0+$";
|
|
||||||
Pattern pattern = Pattern.compile(regex);
|
|
||||||
Matcher m = pattern.matcher(str);
|
|
||||||
if (m.find()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从excel读取内容
|
|
||||||
*/
|
|
||||||
public static void readContent(String fileName) {
|
|
||||||
boolean isE2007 = false; //判断是否是excel2007格式
|
|
||||||
if(fileName.endsWith("xlsx"))
|
|
||||||
isE2007 = true;
|
|
||||||
try {
|
|
||||||
InputStream input = new FileInputStream(fileName); //建立输入流
|
|
||||||
Workbook wb = null;
|
|
||||||
//根据文件格式(2003或者2007)来初始化
|
|
||||||
if(isE2007)
|
|
||||||
wb = new XSSFWorkbook(input);
|
|
||||||
else
|
|
||||||
wb = new HSSFWorkbook(input);
|
|
||||||
Sheet sheet = wb.getSheetAt(0); //获得第一个表单
|
|
||||||
Iterator<Row> rows = sheet.rowIterator(); //获得第一个表单的迭代器
|
|
||||||
while (rows.hasNext()) {
|
|
||||||
Row row = rows.next(); //获得行数据
|
|
||||||
System.out.println("Row #" + row.getRowNum()); //获得行号从0开始
|
|
||||||
Iterator<Cell> cells = row.cellIterator(); //获得第一行的迭代器
|
|
||||||
while (cells.hasNext()) {
|
|
||||||
Cell cell = cells.next();
|
|
||||||
System.out.println("Cell #" + cell.getColumnIndex());
|
|
||||||
switch (cell.getCellType()) { //根据cell中的类型来输出数据
|
|
||||||
case NUMERIC:
|
|
||||||
System.out.println(cell.getNumericCellValue());
|
|
||||||
break;
|
|
||||||
case STRING:
|
|
||||||
System.out.println(cell.getStringCellValue());
|
|
||||||
break;
|
|
||||||
case BOOLEAN:
|
|
||||||
System.out.println(cell.getBooleanCellValue());
|
|
||||||
break;
|
|
||||||
case FORMULA:
|
|
||||||
System.out.println(cell.getCellFormula());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
System.out.println("unsuported sell type======="+cell.getCellType());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2013-2015 JEECG (jeecgos@163.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jeecgframework.poi.util;
|
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 国外高手的,不过也不好,慎用,效率不行 Helper functions to aid in the management of sheets
|
|
||||||
*/
|
|
||||||
public class PoiSheetUtility extends Object {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a sheet, this method deletes a column from a sheet and moves all
|
|
||||||
* the columns to the right of it to the left one cell.
|
|
||||||
*
|
|
||||||
* Note, this method will not update any formula references.
|
|
||||||
*
|
|
||||||
* @param sheet
|
|
||||||
* @param column
|
|
||||||
*/
|
|
||||||
public static void deleteColumn(Sheet sheet, int columnToDelete) {
|
|
||||||
int maxColumn = 0;
|
|
||||||
for (int r = 0; r < sheet.getLastRowNum() + 1; r++) {
|
|
||||||
Row row = sheet.getRow(r);
|
|
||||||
|
|
||||||
// if no row exists here; then nothing to do; next!
|
|
||||||
if (row == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// if the row doesn't have this many columns then we are good; next!
|
|
||||||
int lastColumn = row.getLastCellNum();
|
|
||||||
if (lastColumn > maxColumn)
|
|
||||||
maxColumn = lastColumn;
|
|
||||||
|
|
||||||
if (lastColumn < columnToDelete)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (int x = columnToDelete + 1; x < lastColumn + 1; x++) {
|
|
||||||
Cell oldCell = row.getCell(x - 1);
|
|
||||||
if (oldCell != null)
|
|
||||||
row.removeCell(oldCell);
|
|
||||||
|
|
||||||
Cell nextCell = row.getCell(x);
|
|
||||||
if (nextCell != null) {
|
|
||||||
Cell newCell = row.createCell(x - 1, nextCell.getCellType());
|
|
||||||
cloneCell(newCell, nextCell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust the column widths
|
|
||||||
for (int c = 0; c < maxColumn; c++) {
|
|
||||||
sheet.setColumnWidth(c, sheet.getColumnWidth(c + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Takes an existing Cell and merges all the styles and forumla into the new
|
|
||||||
* one
|
|
||||||
*/
|
|
||||||
private static void cloneCell(Cell cNew, Cell cOld) {
|
|
||||||
cNew.setCellComment(cOld.getCellComment());
|
|
||||||
cNew.setCellStyle(cOld.getCellStyle());
|
|
||||||
|
|
||||||
switch (cNew.getCellType()) {
|
|
||||||
case BOOLEAN: {
|
|
||||||
cNew.setCellValue(cOld.getBooleanCellValue());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NUMERIC: {
|
|
||||||
cNew.setCellValue(cOld.getNumericCellValue());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case STRING: {
|
|
||||||
cNew.setCellValue(cOld.getStringCellValue());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ERROR: {
|
|
||||||
cNew.setCellValue(cOld.getErrorCellValue());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FORMULA: {
|
|
||||||
cNew.setCellFormula(cOld.getCellFormula());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
281
autopoi/pom.xml
281
autopoi/pom.xml
@@ -1,281 +0,0 @@
|
|||||||
<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>
|
|
||||||
<groupId>org.jeecgframework.boot3</groupId>
|
|
||||||
<artifactId>autopoi-parent</artifactId>
|
|
||||||
|
|
||||||
<version>3.7.0</version>
|
|
||||||
<packaging>pom</packaging>
|
|
||||||
|
|
||||||
<name>autopoi-parent</name>
|
|
||||||
<url>http://www.jeecg.com</url>
|
|
||||||
|
|
||||||
<modules>
|
|
||||||
<module>autopoi</module>
|
|
||||||
<module>autopoi-web</module>
|
|
||||||
</modules>
|
|
||||||
|
|
||||||
<description>office 工具类 基于 poi</description>
|
|
||||||
<licenses>
|
|
||||||
<license>
|
|
||||||
<name>The Apache License, Version 2.0</name>
|
|
||||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
|
||||||
</license>
|
|
||||||
</licenses>
|
|
||||||
|
|
||||||
<scm>
|
|
||||||
<connection>scm:git:https://github.com/zhangdaiscott/autopoi.git</connection>
|
|
||||||
<developerConnection>scm:git:https://github.com/zhangdaiscott/autopoi.git</developerConnection>
|
|
||||||
<url>https://github.com/zhangdaiscott/autopoi</url>
|
|
||||||
</scm>
|
|
||||||
<developers>
|
|
||||||
<developer>
|
|
||||||
<name>jeecg</name>
|
|
||||||
<email>jeecgos@163.com</email>
|
|
||||||
</developer>
|
|
||||||
</developers>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<autopoi.version>3.7.0</autopoi.version>
|
|
||||||
<poi.version>5.2.2</poi.version>
|
|
||||||
<xerces.version>2.9.1</xerces.version>
|
|
||||||
<guava.version>29.0-jre</guava.version>
|
|
||||||
<commons-lang.version>3.10</commons-lang.version>
|
|
||||||
<slf4j.version>1.7.30</slf4j.version>
|
|
||||||
<spring.version>6.0.13</spring.version>
|
|
||||||
</properties>
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<!-- poi -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi</artifactId>
|
|
||||||
<version>${poi.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi-ooxml</artifactId>
|
|
||||||
<version>${poi.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>org.apache.poi</groupId>-->
|
|
||||||
<!-- <artifactId>poi-ooxml-schemas</artifactId>-->
|
|
||||||
<!-- <version>${poi.version}</version>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi-ooxml-full</artifactId>
|
|
||||||
<version>${poi.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- sax 读取时候用到的 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>xerces</groupId>
|
|
||||||
<artifactId>xercesImpl</artifactId>
|
|
||||||
<version>${xerces.version}</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi-scratchpad</artifactId>
|
|
||||||
<version>${poi.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- excel背景
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>ooxml-schemas</artifactId>
|
|
||||||
<version>1.4</version>
|
|
||||||
</dependency>-->
|
|
||||||
|
|
||||||
<!-- google 工具类 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.guava</groupId>
|
|
||||||
<artifactId>guava</artifactId>
|
|
||||||
<version>${guava.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-lang3</artifactId>
|
|
||||||
<version>${commons-lang.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--日志 -->
|
|
||||||
<!-- slf4j -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
<version>${slf4j.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
<version>${slf4j.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--spring-web -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-webmvc</artifactId>
|
|
||||||
<version>${spring.version}</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<!--servlet -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.servlet</groupId>
|
|
||||||
<artifactId>jakarta.servlet-api</artifactId>
|
|
||||||
<version>6.0.0</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 模块版本 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jeecgframework.boot3</groupId>
|
|
||||||
<artifactId>autopoi</artifactId>
|
|
||||||
<version>${autopoi.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>jeecg</id>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>17</source>
|
|
||||||
<target>17</target>
|
|
||||||
<encoding>UTF-8</encoding>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<!-- Source -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>jar-no-fork</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<distributionManagement>
|
|
||||||
<repository>
|
|
||||||
<id>jeecg</id>
|
|
||||||
<name>jeecg Repository</name>
|
|
||||||
<url>http://maven.jeecg.com:8090/nexus/content/repositories/jeecg</url>
|
|
||||||
</repository>
|
|
||||||
<snapshotRepository>
|
|
||||||
<id>jeecg-snapshots</id>
|
|
||||||
<name>jeecg Snapshot Repository</name>
|
|
||||||
<url>http://maven.jeecg.com:8090/nexus/content/repositories/snapshots/</url>
|
|
||||||
</snapshotRepository>
|
|
||||||
</distributionManagement>
|
|
||||||
</profile>
|
|
||||||
<profile>
|
|
||||||
<id>release</id>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>17</source>
|
|
||||||
<target>17</target>
|
|
||||||
<encoding>UTF-8</encoding>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<!-- Source -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>jar-no-fork</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<!-- Javadoc -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<encoding>UTF-8</encoding>
|
|
||||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<!--Maven GPG插件用于使用以下配置对组件进行签名-->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
|
||||||
<version>1.6</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>sign-artifacts</id>
|
|
||||||
<phase>verify</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>sign</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<!--Nexus Staging Maven插件是将组件部署到OSS并将其发布到Central Repository的推荐方法-->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.sonatype.plugins</groupId>
|
|
||||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
|
||||||
<extensions>true</extensions>
|
|
||||||
<configuration>
|
|
||||||
<serverId>oss</serverId>
|
|
||||||
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
|
|
||||||
<autoReleaseAfterClose>true</autoReleaseAfterClose>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<distributionManagement>
|
|
||||||
<snapshotRepository>
|
|
||||||
<id>oss</id>
|
|
||||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
|
||||||
</snapshotRepository>
|
|
||||||
<repository>
|
|
||||||
<id>oss</id>
|
|
||||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
|
||||||
</repository>
|
|
||||||
</distributionManagement>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>17</source>
|
|
||||||
<target>17</target>
|
|
||||||
<encoding>UTF-8</encoding>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
1
pom.xml
1
pom.xml
@@ -72,7 +72,6 @@
|
|||||||
<module>physical-base-core</module>
|
<module>physical-base-core</module>
|
||||||
<module>physical-module-system</module>
|
<module>physical-module-system</module>
|
||||||
<module>physical-launcher</module>
|
<module>physical-launcher</module>
|
||||||
<module>autopoi</module>
|
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
|||||||
Reference in New Issue
Block a user