{
+ @Override
+ public String convert(LocalDateTime source) {
+ return source.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
+ }
+ }
+ private static Object convertForProperty(Wrapper wrapper, Object object, Object value, String propertyName)
+ throws TypeMismatchException {
+ Object result;
+ if (wrapper == null) {
+ result = null;
+ } else {
+ wrapper.setWrappedInstance(object);
+ result = wrapper.getBeanWrapper().convertForProperty(value, propertyName);
+ }
+ return result;
+ }
+
+ private static Object copyProperties(Object source, Object target) throws BeansException {
+ Wrapper wrapper = new BeanCopyUtils().new Wrapper(source);
+ copyProperties(wrapper, source, target);
+ return target;
+ }
+
+ /**
+ * Copy the property values of the given source bean into the target bean.
+ *
+ * Note: The source and target classes do not have to match or even be derived from each other, as long as the properties match. Any bean
+ * properties that the source bean exposes but the target bean does not will silently be ignored.
+ *
+ * This is just a convenience method. For more complex transfer needs, consider using a full BeanWrapper.
+ *
+ * @param source
+ * the source bean
+ * @param target
+ * the target bean
+ * @throws BeansException
+ * if the copying failed
+ */
+ private static void copyProperties(Wrapper wrapper, Object source, Object target) throws BeansException {
+ Assert.notNull(source, "Source must not be null");
+ Assert.notNull(target, "Target must not be null");
+
+ Class> actualEditable = target.getClass();
+ PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(actualEditable);
+
+ for (PropertyDescriptor targetPd : targetPds) {
+ if (targetPd.getWriteMethod() != null) {
+ PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
+ if ( sourcePd.getReadMethod() != null) {
+ try {
+ Method readMethod = sourcePd.getReadMethod();
+ if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
+ readMethod.setAccessible(true);
+ }
+ Object value = readMethod.invoke(source);
+ // 判断是否类型不一致
+ if (value != null && !(targetPd.getPropertyType().isInstance(value))) {
+ // 数据转型
+ value = convertForProperty(wrapper, target, value, targetPd.getName());
+ }
+ Method writeMethod = targetPd.getWriteMethod();
+ if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
+ writeMethod.setAccessible(true);
+ }
+ writeMethod.invoke(target, value);
+ } catch (Exception ex) {
+ throw new FatalBeanException("Could not copy properties from source to target", ex);
+ }
+ }
+ }
+ }
+
+ }
+
+ private final class Wrapper {
+
+ private GenericConversionService conversion;
+ private BeanWrapperImpl bean;
+
+ private Wrapper(Object object) {
+ conversion = initDefaultConversionService();
+ bean = initDefaultBeanWrapper(conversion, object);
+ }
+
+ private void setWrappedInstance(Object object) {
+ bean.setWrappedInstance(object);
+ }
+
+ private GenericConversionService initDefaultConversionService() {
+ GenericConversionService conversionService = new DefaultConversionService();
+ conversionService.addConverter(new DateToStringConverter());
+ return conversionService;
+ }
+
+ private BeanWrapperImpl initDefaultBeanWrapper(@SuppressWarnings("hiding") ConversionService conversion,
+ Object object) {
+ BeanWrapperImpl beanWrapper = new BeanWrapperImpl(object);
+ beanWrapper.setConversionService(conversion);
+ return beanWrapper;
+ }
+
+ private BeanWrapperImpl getBeanWrapper() {
+ return bean;
+ }
+ }
+
+ /**
+ * 复制源对象到目的对象
+ */
+ private static void convert(Object source, Object target) {
+ copyProperties(source, target);
+ }
+
+ public static List convert(List> sources, Class targetClass) {
+ List> sourcesObj = sources;
+ if (sourcesObj == null) {
+ sourcesObj = Collections.emptyList();
+ }
+ List targets = new ArrayList<>(sourcesObj.size());
+ BeanCopyUtils.convert(sourcesObj, targets, targetClass);
+ return targets;
+ }
+
+ private static void convert(List> sources, List targets, Class targetClass) {
+ if (targets == null) {
+ return;
+ }
+ targets.clear();
+ if (sources == null) {
+ return;
+ }
+ for (Object obj : sources) {
+ try {
+ T target = targetClass.newInstance();
+ targets.add(target);
+ convert(obj, target);
+ } catch (Exception e) {
+ //do something
+ return;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/pigx-common/pigx-common-excel/src/main/java/com/pig4cloud/common/excel/util/ExcelUtils.java b/pigx-common/pigx-common-excel/src/main/java/com/pig4cloud/common/excel/util/ExcelUtils.java
new file mode 100644
index 000000000..c97f44130
--- /dev/null
+++ b/pigx-common/pigx-common-excel/src/main/java/com/pig4cloud/common/excel/util/ExcelUtils.java
@@ -0,0 +1,251 @@
+package com.pig4cloud.common.excel.util;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.excel.EasyExcelFactory;
+import com.alibaba.excel.ExcelReader;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.metadata.BaseRowModel;
+import com.alibaba.excel.metadata.Sheet;
+import com.alibaba.excel.support.ExcelTypeEnum;
+import com.pig4cloud.common.excel.exception.ExcelException;
+import com.pig4cloud.common.excel.factory.ExcelWriterFactory;
+import com.pig4cloud.common.excel.handler.PreWriterHandler;
+import com.pig4cloud.common.excel.listener.ExcelListener;
+import lombok.experimental.UtilityClass;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.MediaType;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Excel工具类
+ *
+ * @author lishangbu
+ * @date 2019-06-11
+ */
+@Slf4j
+@UtilityClass
+public class ExcelUtils {
+
+ private final String DEFAULT_EXCEL_SHEET_NAME="Sheet1";
+
+ /**
+ * 读取 Excel(多个 sheet)
+ * 将多sheet合并成一个list数据集,通过自定义ExcelReader继承AnalysisEventListener
+ * 重写invoke doAfterAllAnalysed方法
+ * getExtendsBeanList 主要是做Bean的属性拷贝 ,可以通过ExcelReader中添加的数据集直接获取
+ *
+ * @param excel 文件
+ * @param rowModel 实体类映射,继承 BaseRowModel 类
+ * @return Excel 数据 list
+ */
+ public List readExcel(MultipartFile excel, Class rowModel) {
+ ExcelListener excelListener = new ExcelListener();
+ ExcelReader reader = getReader(excel, excelListener);
+ if (reader == null) {
+ return new ArrayList<>();
+ }
+ for (Sheet sheet : reader.getSheets()) {
+ sheet.setClazz(rowModel);
+ reader.read(sheet);
+ }
+ return getExtendsBeanList(excelListener.getDataList(), rowModel);
+ }
+
+ /**
+ * 读取某个 sheet 的 Excel
+ *
+ * @param excel 文件
+ * @param rowModel 实体类映射,继承 BaseRowModel 类
+ * @param sheetNo sheet 的序号 从1开始
+ * @return Excel 数据 list
+ */
+ public List readExcel(MultipartFile excel, Class rowModel, int sheetNo) {
+ return readExcel(excel, rowModel, sheetNo, 1);
+ }
+
+ /**
+ * 读取某个 sheet 的 Excel
+ *
+ * @param excel 文件
+ * @param rowModel 实体类映射,继承 BaseRowModel 类
+ * @param sheetNo sheet 的序号 从1开始
+ * @param headLineNum 表头行数,默认为1
+ * @return Excel 数据 list
+ */
+ public List readExcel(MultipartFile excel, Class rowModel, int sheetNo,
+ int headLineNum) {
+ ExcelListener excelListener = new ExcelListener();
+ ExcelReader reader = getReader(excel, excelListener);
+ if (reader == null) {
+ return new ArrayList<>();
+ }
+ reader.read(new Sheet(sheetNo, headLineNum, rowModel));
+ return getExtendsBeanList(excelListener.getDataList(), rowModel);
+ }
+
+
+ /**
+ * 导出 2007 Excel :一个 sheet,带表头,默认sheet名称
+ *
+ * @param response HttpServletResponse
+ * @param list 数据 list,每个元素为一个 BaseRowModel
+ * @param fileName 导出的文件名
+ * @param classType 实体类映射,继承 BaseRowModel 类
+ * @param
+ */
+ public void writeExcel(HttpServletResponse response, List list,
+ String fileName, Class classType){
+ writeExcel(response,list,fileName,null,classType);
+ }
+
+
+ /**
+ * 导出 2007 Excel :一个 sheet,带表头
+ *
+ * @param response HttpServletResponse
+ * @param list 数据 list,每个元素为一个 BaseRowModel
+ * @param fileName 导出的文件名
+ * @param sheetName 导入文件的 sheet 名
+ * @param classType 实体类映射,继承 BaseRowModel 类
+ * @param
+ */
+ public void writeExcel(HttpServletResponse response, List list,
+ String fileName, String sheetName,
+ Class classType){
+ writeExcel(response,list,fileName,sheetName,ExcelTypeEnum.XLSX,classType);
+ }
+
+ /**
+ * 导出 Excel :一个 sheet,带表头
+ * 自定义WriterHandler 可以定制行列数据进行灵活化操作
+ *
+ * @param response HttpServletResponse
+ * @param list 数据 list,每个元素为一个 BaseRowModel
+ * @param fileName 导出的文件名
+ * @param sheetName 导入文件的 sheet 名
+ * @param excelTypeEnum 导出Excel类型
+ * @param classType 实体类映射,继承 BaseRowModel 类
+ *
+ */
+ public void writeExcel(HttpServletResponse response, List list,
+ String fileName, String sheetName, ExcelTypeEnum excelTypeEnum,
+ Class classType) {
+ if (StrUtil.isBlank(sheetName)) {
+ sheetName = DEFAULT_EXCEL_SHEET_NAME;
+ }
+ OutputStream outputStream =null;
+ try {
+ response.reset();
+ outputStream = getOutputStream(fileName, response, excelTypeEnum);
+ if (excelTypeEnum == ExcelTypeEnum.XLSX) {
+ ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(null, outputStream
+ , excelTypeEnum, true, new PreWriterHandler<>(classType));
+ Sheet sheet = new Sheet(1, 0, classType);
+ sheet.setSheetName(sheetName);
+ try {
+ writer.write(list, sheet);
+ } finally {
+ writer.finish();
+ }
+ } else if (excelTypeEnum == ExcelTypeEnum.XLS) {
+ // 其实也可以专门调03版的样式,或者直接套用
+ ExcelWriterFactory writer = new ExcelWriterFactory(outputStream, excelTypeEnum);
+ Sheet sheet = new Sheet(1, 0, classType);
+ sheet.setSheetName(sheetName);
+ try {
+ writer.write(list, sheet);
+ } finally {
+ writer.finish();
+ writer.close();
+ }
+ }
+ outputStream.flush();
+ }catch (IOException e){
+ log.error("导出excel异常:{}",e);
+ }finally {
+ if(outputStream!=null){
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ }
+
+ /**
+ * 导出 Excel :多个 sheet,带表头
+ *
+ * @param response HttpServletResponse
+ * @param list 数据 list,每个元素为一个 BaseRowModel
+ * @param fileName 导出的文件名
+ * @param sheetName 导入文件的 sheet 名
+ * @param object 映射实体类,Excel 模型
+ */
+ public ExcelWriterFactory writeExcelWithSheets(HttpServletResponse response, List extends BaseRowModel> list,
+ String fileName, String sheetName, BaseRowModel object, ExcelTypeEnum excelTypeEnum) {
+ ExcelWriterFactory writer = new ExcelWriterFactory(getOutputStream(fileName, response, excelTypeEnum), excelTypeEnum);
+ Sheet sheet = new Sheet(1, 0, object.getClass());
+ sheet.setSheetName(sheetName);
+ writer.write(list, sheet);
+ return writer;
+ }
+
+ /**
+ * 导出文件时为Writer生成OutputStream
+ */
+ private OutputStream getOutputStream(String fileName, HttpServletResponse response, ExcelTypeEnum excelTypeEnum) {
+ try {
+ String encodeFilename = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
+ response.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ response.setHeader("Content-disposition", "attachment;filename="+ encodeFilename+excelTypeEnum.getValue());
+ return response.getOutputStream();
+ } catch (IOException e) {
+ throw new ExcelException("创建文件失败!");
+ }
+ }
+
+ /**
+ * 返回 ExcelReader
+ *
+ * @param excel 需要解析的 Excel 文件
+ * @param excelListener new ExcelListener()
+ */
+ private ExcelReader getReader(MultipartFile excel,
+ ExcelListener excelListener) {
+ String fileName = excel.getOriginalFilename();
+ if (fileName == null) {
+ throw new ExcelException("文件格式错误!");
+ }
+ if (!fileName.toLowerCase().endsWith(ExcelTypeEnum.XLS.getValue()) && !fileName.toLowerCase().endsWith(ExcelTypeEnum.XLSX.getValue())) {
+ throw new ExcelException("文件格式错误!");
+ }
+ InputStream inputStream;
+ try {
+ inputStream = excel.getInputStream();
+ return new ExcelReader(inputStream, null, excelListener, false);
+ } catch (IOException e) {
+ //do something
+ }
+ return null;
+ }
+
+ /**
+ * 利用BeanCopy转换list
+ */
+ private List getExtendsBeanList(List> list, Class typeClazz) {
+ return BeanCopyUtils.convert(list, typeClazz);
+ }
+}
+
diff --git a/pigx-common/pom.xml b/pigx-common/pom.xml
index 1227d7038..d8b988368 100644
--- a/pigx-common/pom.xml
+++ b/pigx-common/pom.xml
@@ -36,14 +36,15 @@
pigx-common-bom
pigx-common-core
pigx-common-data
+ pigx-common-datasource
+ pigx-common-excel
pigx-common-gateway
pigx-common-job
pigx-common-log
pigx-common-minio
pigx-common-security
- pigx-common-swagger
pigx-common-sequence
+ pigx-common-swagger
pigx-common-transaction
- pigx-common-datasource
diff --git a/pom.xml b/pom.xml
index 93468c95a..60e8432ef 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,6 +49,7 @@
1.8
1.8
2.1.5
+ 1.1.2-beta5
4.5.10
0.0.9
2.9.2