diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExcelField.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExcelField.java new file mode 100644 index 00000000..99723fd8 --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExcelField.java @@ -0,0 +1,51 @@ +package org.jeecg.common.Excel; + +import java.lang.annotation.*; + +@Documented +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExcelField { + + /** + * 字段title + * @return + */ + String title(); + + /** + * 字段排序(升序) + * @return + */ + int sort(); + + /** + * 字段类型(0:导出导入;1:仅导出;2:仅导入) + * @return + */ + int type() default 0; + + /** + * 字段是否可以为空,默认true + * @return + */ + boolean isNotNull() default true; + + /** + * 设置列宽 + * @return + */ + int width() default -1; + + /** + * 日期类型格式化,默认年月日时分秒 + * @return + */ + String dateFormat() default "yyyy-MM-dd HH:mm:ss"; + + /** + * 数据转换:需实现WriteConverter接口 + * @return + */ + Class converter() default Class.class; +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExcelWrite.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExcelWrite.java new file mode 100644 index 00000000..3b55ceb7 --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExcelWrite.java @@ -0,0 +1,48 @@ +package org.jeecg.common.Excel; + +import org.apache.poi.ss.usermodel.Workbook; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; + +public class ExcelWrite { + + /** + * 定义工作簿 + */ + protected Workbook workBook; + + + public ExcelWrite writeToXlsx(HttpServletRequest req,HttpServletResponse res,String fileName) throws IOException { + String contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + this.write(req, res, fileName,contentType); + return this; + } + + public ExcelWrite writeToXls(HttpServletRequest req,HttpServletResponse res,String fileName) throws IOException { + String contentType = "application/vnd.ms-excel"; + this.write(req, res, fileName,contentType); + return this; + } + + /** + * 输出到客户端 + * @param req + * @param res + * @param fileName + * @return + * @throws IOException + */ + private void write(HttpServletRequest req,HttpServletResponse res,String fileName,String contentType) throws IOException { + res.setContentType(contentType); + res.setCharacterEncoding("UTF-8"); + String finalFileName = null; + //如果是谷歌、火狐浏览器 + finalFileName = URLEncoder.encode(fileName,"UTF-8"); + res.setHeader("Content-Disposition", "attachment; filename="+finalFileName); + res.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + workBook.write(res.getOutputStream()); + } +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExportExcel.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExportExcel.java new file mode 100644 index 00000000..fa592e2b --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExportExcel.java @@ -0,0 +1,238 @@ +package org.jeecg.common.Excel; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.utils.Lists; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; + +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.List; + +/** + * 导出Excel支持xls和xlsx两种格式 + */ +@Slf4j +public class ExportExcel extends ExportExcelBase{ + + /** + * 注解列表(Object[]{ ExcelField, Field }) + */ + private List annotationList = Lists.newArrayList(); + + public ExportExcel() { + + } + + /** + * 构造函数 + * @param title 表格title + * @param annotationList 需要导出的列 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param enableRownum 导出excel是否使用行号 + */ + public ExportExcel createXlsxExcel(String title,List annotationList,int type,boolean enableRownum) { + super.workBook = new SXSSFWorkbook(this.initRecordSize); + this.sheet = this.workBook.createSheet(title); + this.enableRownum = enableRownum; + this.enableTitle = StringUtils.isNotBlank(title)?true:false; + this.init(title,annotationList,type); + return this; + } + + /** + * 构造函数 + * @param title 表格title + * @param cls 实体对象 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param enableRownum 导出excel是否使用行号 + */ + public ExportExcel createXlsxExcel(String title,Class cls,int type,boolean enableRownum) { + super.workBook = new SXSSFWorkbook(this.initRecordSize); + this.sheet = this.workBook.createSheet(title); + this.enableRownum = enableRownum; + this.enableTitle = StringUtils.isNotBlank(title)?true:false; + this.init(title,cls,type); + return this; + } + + /** + * 构造函数 + * @param annotationList 需要导出的列 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param enableRownum 导出excel是否使用行号 + */ + public ExportExcel createXlsxExcel(List annotationList,int type,boolean enableRownum) { + super.workBook = new SXSSFWorkbook(this.initRecordSize); + this.sheet = this.workBook.createSheet(); + this.enableRownum = enableRownum; + this.init(null,annotationList,type); + return this; + } + + /** + * 构造函数 + * @param cls 实体对象 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param enableRownum 导出excel是否使用行号 + */ + public ExportExcel createXlsxExcel(Class cls,int type,boolean enableRownum) { + super.workBook = new SXSSFWorkbook(this.initRecordSize); + this.sheet = this.workBook.createSheet(); + this.enableRownum = enableRownum; + this.init(null,cls,type); + return this; + } + + /** + * 构造函数 + * @param title 表格title + * @param cls 实体对象 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param enableRownum 导出excel是否使用行号 + */ + public ExportExcel createXlsExcel(String title,Class cls,int type,boolean enableRownum) { + super.workBook = new HSSFWorkbook(); + this.sheet = this.workBook.createSheet(title); + this.enableRownum = enableRownum; + this.enableTitle = StringUtils.isNotBlank(title)?true:false; + this.init(title,cls,type); + return this; + } + + /** + * 构造函数 + * @param title 表格title + * @param annotationList 需要导出的列 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param enableRownum 导出excel是否使用行号 + */ + public ExportExcel createXlsExcel(String title,List annotationList,int type,boolean enableRownum) { + super.workBook = new HSSFWorkbook(); + this.sheet = this.workBook.createSheet(title); + this.enableRownum = enableRownum; + this.enableTitle = StringUtils.isNotBlank(title)?true:false; + this.init(title,annotationList,type); + return this; + } + + /** + * 构造函数 + * @param cls 实体对象 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param enableRownum 导出excel是否使用行号 + */ + public ExportExcel createXlsExcel(Class cls,int type,boolean enableRownum) { + super.workBook = new HSSFWorkbook(); + this.sheet = this.workBook.createSheet(); + this.enableRownum = enableRownum; + this.init(null,cls,type); + return this; + } + + /** + * 构造函数 + * @param annotationList 需要导出的列 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param enableRownum 导出excel是否使用行号 + */ + public ExportExcel createXlsExcel(List annotationList,int type,boolean enableRownum) { + super.workBook = new HSSFWorkbook(); + this.sheet = this.workBook.createSheet(); + this.enableRownum = enableRownum; + this.init(null,annotationList,type); + return this; + } + + /** + * 初始化excel title,hander,样式 + */ + private void init(String title,Class cls,int type) { + Field[] fields = cls.getDeclaredFields(); + for(Field field:fields) { + ExcelField ef = field.getAnnotation(ExcelField.class); + if(null != ef && (ef.type() == 0 || ef.type() == 1)) { + annotationList.add(new Object[] {ef,field}); + } + } + annotationList.sort(new Comparator() { + @Override + public int compare(Object[] o1, Object[] o2) { + return ((ExcelField)o1[0]).sort()-((ExcelField)o2[0]).sort(); + } + }); + //excel header + List headerList = Lists.newArrayList(); + if(this.enableRownum && type != 2) { + headerList.add("序号"); + } + for(Object[] obj : annotationList) { + headerList.add(((ExcelField)obj[0]).title()); + } + this.createStyles(); + this.createTitle(title,headerList); + this.createHeader(headerList); + this.setCellWidth(annotationList); + } + + /** + * 初始化excel title,hander,样式 + */ + private void init(String title,List annotationList,int type) { + annotationList.sort(new Comparator() { + @Override + public int compare(Object[] o1, Object[] o2) { + return ((ExcelField)o1[0]).sort()-((ExcelField)o2[0]).sort(); + } + }); + this.annotationList = annotationList; + //excel header + List headerList = Lists.newArrayList(); + if(this.enableRownum && type != 2) { + headerList.add("序号"); + } + for(Object[] obj : annotationList) { + headerList.add(((ExcelField)obj[0]).title()); + } + this.createStyles(); + this.createTitle(title,headerList); + this.createHeader(headerList); + this.setCellWidth(annotationList); + } + + /** + * 设置数据 + * @param + * @param list + * @return + */ + public ExportExcel setDataList(List list) { + for(E e : list) { + int column = 0; + Row row = this.createRow(); + if(this.enableRownum) { + Cell cell = row.createCell(column++); + CellStyle style = this.styles.get("data"); + cell.setCellStyle(style); + cell.setCellValue(this.enableTitle==true?this.rownum-2:this.rownum-1); + } + for(Object[] os : this.annotationList) { + ExcelField ef = (ExcelField) os[0]; + Object val = null; + try { + Field field = (Field)os[1]; + field.setAccessible(true); + val = field.get(e); + } catch (Exception e1) { + log.error("列"+ef.title()+"获取值错误",e1); + } + this.createCell(row, column++, val, ef.dateFormat(), ef.converter()); + } + } + return this; + } +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExportExcelBase.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExportExcelBase.java new file mode 100644 index 00000000..59967d8e --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ExportExcelBase.java @@ -0,0 +1,208 @@ +package org.jeecg.common.Excel; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +public class ExportExcelBase extends ExcelWrite{ + + /** + * 定义sheet页 + */ + protected Sheet sheet; + + /** + * 样式列表 + */ + protected Map styles; + + /** + * 当前行号 + */ + protected int rownum; + + /** + * 是否开启导出行号 + */ + protected boolean enableRownum = false; + + /** + * 是否开启表头 + */ + protected boolean enableTitle = false; + + /** + * 初始化创建行数 + */ + protected final int initRecordSize =1000; + + /** + * 创建样式 + */ + protected void createStyles() { + Map styles = new HashMap(); + CellStyle style = this.workBook.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.BLACK.index); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.BLACK.index); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.BLACK.index); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.BLACK.index); + Font titleFont = this.workBook.createFont(); + titleFont.setFontName("宋体"); + titleFont.setFontHeightInPoints((short)16); + titleFont.setBold(true); + style.setFont(titleFont); + styles.put("title", style); + + style = this.workBook.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.BLACK.index); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.BLACK.index); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.BLACK.index); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.BLACK.index); + Font dataFont = this.workBook.createFont(); + dataFont.setFontName("宋体"); + dataFont.setFontHeightInPoints((short)11); + style.setFont(dataFont); + styles.put("data", style); + + style = this.workBook.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + Font headerFont = this.workBook.createFont(); + headerFont.setFontName("宋体"); + headerFont.setFontHeightInPoints((short) 11); + headerFont.setBold(true); + style.setFont(headerFont); + styles.put("header", style); + + this.styles = styles; + } + + /** + * 创建title + * @param title + * @param headerList + */ + protected void createTitle(String title,List headerList) { + if(StringUtils.isNotBlank(title)) { + Row row = this.sheet.createRow(rownum++); + row.setHeightInPoints(30); + Cell cell = row.createCell(0); + cell.setCellStyle(this.styles.get("title")); + cell.setCellValue(title); + this.sheet.addMergedRegion(new CellRangeAddress(row.getRowNum(),row.getRowNum(),row.getRowNum(),headerList.size()-1)); + } + } + + /** + * 创建header + * @param headerList + */ + protected void createHeader(List headerList) { + Row row = this.sheet.createRow(rownum++); + row.setHeightInPoints(16); + for(int i=0;i annotationList) { + for(int i=0;i converterType) { + Cell cell = row.createCell(column); + CellStyle style = this.styles.get("data"); + cell.setCellStyle(style); + try { + if(null == val) { + cell.setCellValue(StringUtils.EMPTY); + }else { + if(converterType == Class.class) { + if(val instanceof String) { + cell.setCellValue(val.toString()); + }else if(val instanceof Integer) { + cell.setCellValue((Integer) val); + }else if(val instanceof Long) { + cell.setCellValue((Long) val); + }else if(val instanceof Double) { + cell.setCellValue((Double) val); + }else if(val instanceof Float) { + cell.setCellValue((Float) val); + }else if(val instanceof LocalDate) { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format); + LocalDate localDate = (LocalDate)val; + cell.setCellValue(localDate.format(dtf)); + }else if(val instanceof LocalDateTime) { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format); + LocalDateTime localDateTime = (LocalDateTime)val; + cell.setCellValue(localDateTime.format(dtf)); + }else { + cell.setCellValue(val.toString()); + } + }else { + Class cls = Class.forName(converterType.getName()); + val = cls.getMethod("converter", Object.class).invoke(cls.newInstance(), val); + cell.setCellValue(val.toString()); + } + } + } catch (Exception e) { + log.error(row.getRowNum()+"行,"+column+"列,设置值错误:",e); + cell.setCellValue(val.toString()); + } + return cell; + } + + +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ImportExcel.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ImportExcel.java new file mode 100644 index 00000000..3f18185b --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/Excel/ImportExcel.java @@ -0,0 +1,178 @@ +package org.jeecg.common.Excel; + +import com.google.common.collect.Lists; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.jeecg.common.util.DateUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.text.NumberFormat; +import java.text.ParseException; +import java.time.LocalDateTime; +import java.util.*; + +/** + * 导入Excel支持xls和xlsx两种格式 + */ +public class ImportExcel { + + /** + * 工作簿对象 + */ + private Workbook workBook; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 标题行号 + */ + private int headerNum; + + public ImportExcel() {} + + public ImportExcel(MultipartFile file,int headerNum,int sheetIndex) throws IOException { + this(file.getOriginalFilename(),file.getInputStream(),headerNum,sheetIndex); + } + + public ImportExcel(String fileName,InputStream is,int headerNum,int sheetIndex) throws IOException { + if(StringUtils.isBlank(fileName)) { + throw new RuntimeException("导入文档为空"); + }else if(fileName.toLowerCase().endsWith(".xls")) { + this.workBook = new HSSFWorkbook(is); + }else if(fileName.toLowerCase().endsWith(".xlsx")) { + this.workBook = new XSSFWorkbook(is); + }else { + throw new RuntimeException("文档格式不正确"); + } + this.headerNum = headerNum; + this.sheet = this.workBook.getSheetAt(sheetIndex); + } + + /** + * 获取行 + * @param rowNum + * @return + */ + public Row getRow(int rowNum) { + return this.sheet.getRow(rowNum); + } + + /** + * 获取行号 + * @return + */ + public int getRowNum() { + return this.headerNum+1; + } + + /** + * 获取最后行号 + * @return + */ + public int getLastRowNum() { + return this.sheet.getLastRowNum(); + } + + /** + * 获取最后列号 + * @return + */ + public int getLastColumnNum() { + return this.getRow(headerNum).getLastCellNum(); + } + + public Object getColumnValue(Row row,int columnIndex) { + Object obj = null; + try { + Cell cell = row.getCell(columnIndex); + if(Objects.nonNull(cell)) { + if(cell.getCellType() == CellType.NUMERIC) { + if(DateUtil.isCellDateFormatted(cell)) { + obj = DateUtil.getLocalDateTime(cell.getNumericCellValue()); + }else { + NumberFormat nf = NumberFormat.getInstance(); + nf.setGroupingUsed(false); + obj = nf.format(cell.getNumericCellValue()); + } + }else if(cell.getCellType() == CellType.STRING) { + String cellValue = cell.getStringCellValue(); + if(StringUtils.isNotBlank(cellValue)) { + obj = cellValue; + } + }else if(cell.getCellType() == CellType.FORMULA) { + obj = cell.getCellFormula(); + }else if(cell.getCellType() == CellType.BOOLEAN) { + obj = cell.getBooleanCellValue(); + }else if(cell.getCellType() == CellType.ERROR) { + obj = cell.getErrorCellValue(); + } + } + } catch (Exception e) { + return obj; + } + return obj; + } + + public List getDataList(Class clz) throws InstantiationException, IllegalAccessException, ParseException { + List annotationList = Lists.newArrayList(); + Field[] fields = clz.getDeclaredFields(); + for(Field field : fields) { + ExcelField ef = field.getAnnotation(ExcelField.class); + if(ef != null && (ef.type() == 0 || ef.type() == 2)) { + annotationList.add(new Object[]{ef,field}); + } + } + Collections.sort(annotationList, new Comparator() { + @Override + public int compare(Object[] o1, Object[] o2) { + return new Integer(((ExcelField)o1[0]).sort()).compareTo(new Integer(((ExcelField)o2[0]).sort())); + } + }); + List dataList = Lists.newArrayList(); + for(int i=this.getRowNum();i<=this.getLastRowNum();i++) { + E e = clz.newInstance(); + int column = 0; + Row row = this.getRow(i); + for(Object[] os : annotationList) { + Object val = this.getColumnValue(row, column++); + if(Objects.nonNull(val)) { + Class valType = Class.class; + if(os[1] instanceof Field) { + Field field = ((Field)os[1]); + valType = field.getType(); + + if(valType == String.class) { + val = String.valueOf(val.toString()); + }else if(valType == Integer.class) { + val = Double.valueOf(val.toString()).intValue(); + }else if(valType == Long.class) { + val = Double.valueOf(val.toString()).longValue(); + }else if(valType == Double.class) { + val = Double.valueOf(val.toString()).doubleValue(); + }else if(valType == Float.class) { + val = Double.valueOf(val.toString()).floatValue(); + }else if(valType == Boolean.class) { + val = Boolean.valueOf(val.toString()).booleanValue(); + }else if(valType == Date.class) { + val = DateUtils.parseDate(val.toString(), "yyyy-MM-dd"); + } + //设置值 + field.setAccessible(true); + ReflectionUtils.setField(field, e, val); + } + } + } + dataList.add(e); + } + return dataList; + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTaskController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTaskController.java index a8792ff4..9629a0af 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTaskController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTaskController.java @@ -1,23 +1,40 @@ package org.jeecg.modules.system.controller; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecg.common.Excel.ImportExcel; import org.jeecg.common.api.vo.Result; +import org.jeecg.common.util.DateUtils; import org.jeecg.config.valid.InsertGroup; import org.jeecg.config.valid.UpdateGroup; import org.jeecg.modules.system.entity.SysTask; +import org.jeecg.modules.system.entity.SysTaskStation; +import org.jeecg.modules.system.entity.vo.ImportViewVo; import org.jeecg.modules.system.entity.vo.SysTaskChangeVo; +import org.jeecg.modules.system.entity.vo.SysTaskExportVo; import org.jeecg.modules.system.entity.vo.SysTaskVo; import org.jeecg.modules.system.service.ISysTaskService; +import org.jeecgframework.poi.excel.ExcelExportUtil; +import org.jeecgframework.poi.excel.entity.ExportParams; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; -import java.util.Date; -import java.util.List; -import java.util.Map; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; @Slf4j @RestController @@ -66,4 +83,31 @@ public class SysTaskController { return sysTaskService.changeScheduling(sysTaskChangeVo); } + @PostMapping("exportExcel") + public void exportExcel(@DateTimeFormat(pattern = "yyyy-MM") Date yearMonth, HttpServletRequest request, HttpServletResponse response){ + sysTaskService.exportExcel(yearMonth, request, response); + } + + @GetMapping("exportImportTemplate") + public void exportImportTemplate(HttpServletRequest request, HttpServletResponse response){ + sysTaskService.exportImportTemplate(request, response); + } + + @PostMapping("importExcel") + public ImportViewVo importExcel(MultipartFile file){ + try { + int headerRow = 1; + List dataList = new ImportExcel(file,headerRow,0).getDataList(SysTaskExportVo.class); + return sysTaskService.importExcel(dataList, headerRow); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/vo/ImportFailureVo.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/vo/ImportFailureVo.java new file mode 100644 index 00000000..68cf54bb --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/vo/ImportFailureVo.java @@ -0,0 +1,19 @@ +package org.jeecg.modules.system.entity.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author admin + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ImportFailureVo { + @ApiModelProperty("失败行数") + private Integer line; + @ApiModelProperty("失败原因") + private String result; +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/vo/ImportViewVo.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/vo/ImportViewVo.java new file mode 100644 index 00000000..0b3ed476 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/vo/ImportViewVo.java @@ -0,0 +1,28 @@ +package org.jeecg.modules.system.entity.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author admin + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ImportViewVo { + @ApiModelProperty("成功条数") + private Integer success; + + @ApiModelProperty("失败条数") + private Integer failure; + + @ApiModelProperty("失败列表") + private List detailList; + + @ApiModelProperty("失败结果文件路径") + private String path; +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/vo/SysTaskExportVo.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/vo/SysTaskExportVo.java new file mode 100644 index 00000000..a1e158e9 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/vo/SysTaskExportVo.java @@ -0,0 +1,18 @@ +package org.jeecg.modules.system.entity.vo; + +import lombok.Data; +import org.jeecg.common.Excel.ExcelField; + +@Data +public class SysTaskExportVo { + + @ExcelField(title = "排班日期", width = 15, sort = 1, dateFormat = "yyyy-MM-dd") + private String schedulingDate; + + @ExcelField(title = "用户名称", width = 15, sort = 2) + private String userName; + + @ExcelField(title = "台站名称", width = 15, sort = 3) + private String stationName; + +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysTaskService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysTaskService.java index d9ccf852..df190055 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysTaskService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysTaskService.java @@ -3,9 +3,14 @@ package org.jeecg.modules.system.service; import com.baomidou.mybatisplus.extension.service.IService; import org.jeecg.common.api.vo.Result; import org.jeecg.modules.system.entity.SysTask; +import org.jeecg.modules.system.entity.vo.ImportViewVo; import org.jeecg.modules.system.entity.vo.SysTaskChangeVo; +import org.jeecg.modules.system.entity.vo.SysTaskExportVo; import org.jeecg.modules.system.entity.vo.SysTaskVo; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.util.Date; import java.util.List; import java.util.Map; @@ -19,6 +24,11 @@ public interface ISysTaskService extends IService { */ Result>> findList(Date yearMonth); + /** + * 查询当日排班任务详情信息 + * @param day + * @return + */ Result> findInfo(Date day); /** @@ -49,4 +59,26 @@ public interface ISysTaskService extends IService { * @return */ Result changeScheduling(SysTaskChangeVo sysTaskChangeVo); + + /** + * 导出排班任务信息 + * @param yearMonth + * @param request + * @param response + */ + void exportExcel(Date yearMonth, HttpServletRequest request, HttpServletResponse response); + + /** + * 导出导入模板 + * @param request + * @param response + */ + void exportImportTemplate(HttpServletRequest request, HttpServletResponse response); + + /** + * 导入排班任务信息 + * @param dataList + */ + ImportViewVo importExcel(List dataList, int headerRow); + } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTaskServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTaskServiceImpl.java index d7e9fb97..356be1da 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTaskServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTaskServiceImpl.java @@ -1,29 +1,42 @@ package org.jeecg.modules.system.service.impl; +import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.jeecg.weibo.exception.BusinessException; +import org.apache.commons.lang3.StringUtils; +import org.jeecg.common.Excel.ExcelField; +import org.jeecg.common.Excel.ExportExcel; import org.jeecg.common.api.vo.Result; import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.util.DateUtils; import org.jeecg.common.util.IpUtils; +import org.jeecg.common.util.RedisUtil; import org.jeecg.common.util.SpringContextUtils; import org.jeecg.modules.system.entity.GardsStations; import org.jeecg.modules.system.entity.SysTask; import org.jeecg.modules.system.entity.SysTaskStation; -import org.jeecg.modules.system.entity.vo.SysTaskChangeVo; -import org.jeecg.modules.system.entity.vo.SysTaskVo; +import org.jeecg.modules.system.entity.SysUser; +import org.jeecg.modules.system.entity.vo.*; import org.jeecg.modules.system.mapper.SysTaskMapper; import org.jeecg.modules.system.mapper.SysTaskStationMapper; +import org.jeecg.modules.system.mapper.SysUserMapper; import org.jeecg.modules.system.service.IGardsStationsService; import org.jeecg.modules.system.service.ISysTaskService; import org.jeecg.modules.system.service.ISysTaskStationService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Field; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; @@ -38,13 +51,17 @@ public class SysTaskServiceImpl extends ServiceImpl impl private SysTaskStationMapper sysTaskStationMapper; @Autowired private IGardsStationsService gardsStationsService; + @Autowired + private SysUserMapper sysUserMapper; + @Autowired + private RedisUtil redisUtil; @Override public Result>> findList(Date yearMonth) { Result>> result = new Result(); Map> map = new LinkedHashMap<>(); //获取全部台站信息 - List gardsStations = gardsStationsService.getGardsStations(); + HashMap stationMap = (HashMap)redisUtil.get("stationMap"); try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String yearMonthStr = DateUtils.formatDate(yearMonth, "yyyy-MM"); @@ -79,13 +96,11 @@ public class SysTaskServiceImpl extends ServiceImpl impl if (CollectionUtils.isNotEmpty(sysTaskStations)){ //遍历所有台站信息并赋值台站名称 for (SysTaskStation taskStation:sysTaskStations) { - //通过stream流获取当前台站id对应的台站信息 - List gardsStationsList = gardsStations.stream().filter(item -> item.getStationId().toString().equals(taskStation.getStationId())).collect(Collectors.toList()); + //通过台站id查询台站code + String stationValue = stationMap.get(taskStation.getStationId()); //如果台站数量大于0,则说明有对应的台站信息 - if (CollectionUtils.isNotEmpty(gardsStationsList)){ - //台站id唯一,取第一条数据 - GardsStations stations = gardsStationsList.get(0); - taskStation.setStationName(stations.getStationCode()); + if (StringUtils.isNotBlank(stationValue)){ + taskStation.setStationName(stationValue); } } //遍历排版任务信息 @@ -120,7 +135,7 @@ public class SysTaskServiceImpl extends ServiceImpl impl public Result> findInfo(Date day) { Result> result = new Result(); //获取全部台站信息 - List gardsStations = gardsStationsService.getGardsStations(); + HashMap stationMap = (HashMap)redisUtil.get("stationMap"); try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Calendar cal = Calendar.getInstance(); @@ -137,12 +152,10 @@ public class SysTaskServiceImpl extends ServiceImpl impl //遍历所有台站信息并赋值台站名称 for (SysTaskStation taskStation:taskStations) { //通过stream流获取当前台站id对应的台站信息 - List gardsStationsList = gardsStations.stream().filter(item -> item.getStationId().toString().equals(taskStation.getStationId())).collect(Collectors.toList()); + String stationValue = stationMap.get(taskStation.getStationId()); //如果台站数量大于0,则说明有对应的台站信息 - if (CollectionUtils.isNotEmpty(gardsStationsList)){ - //台站id唯一,取第一条数据 - GardsStations stations = gardsStationsList.get(0); - taskStation.setStationName(stations.getStationCode()); + if (StringUtils.isNotBlank(stationValue)){ + taskStation.setStationName(stationValue); } } for (SysTask sysTask:sysTasks) { @@ -303,4 +316,210 @@ public class SysTaskServiceImpl extends ServiceImpl impl return result; } + @Override + public void exportExcel(Date yearMonth, HttpServletRequest request, HttpServletResponse response) { + try { + //声明数据集合 + List exportVoList = new LinkedList<>(); + //获取当前年月的所有数据 + Result>> result = this.findList(yearMonth); + Map> sysTaskMap = result.getResult(); + for (Map.Entry> entry:sysTaskMap.entrySet()) { + List sysTaskVos = entry.getValue(); + if (CollectionUtils.isNotEmpty(sysTaskVos)){ + for (SysTaskVo sysTaskVo:sysTaskVos) { + String schedulingDate = DateUtils.formatDate(sysTaskVo.getSchedulingDate(), "yyyy-MM-dd"); + String username = sysTaskVo.getUsername(); + String stationNames = ""; + for (SysTaskStation sysTaskStation:sysTaskVo.getStationList()) { + stationNames+=sysTaskStation.getStationName()+","; + } + stationNames = stationNames.substring(0,stationNames.length()-1); + if (StringUtils.isNotBlank(stationNames)){ + SysTaskExportVo vo = new SysTaskExportVo(); + vo.setSchedulingDate(schedulingDate); + vo.setUserName(username); + vo.setStationName(stationNames); + exportVoList.add(vo); + } + } + } + } + new ExportExcel().createXlsxExcel("排班任务信息",SysTaskExportVo.class,1, true) + .setDataList(exportVoList).writeToXlsx(request, response, "排班任务信息-"+ DateUtil.format(new Date(), "yyyyMMdd")); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void exportImportTemplate(HttpServletRequest request, HttpServletResponse response) { + String fileName = "排班任务导入模板"; + try { + //处理需要导出的列 + List annotationList = Lists.newArrayList(); + Field[] fields = SysTaskExportVo.class.getDeclaredFields(); + for(Field field : fields) { + ExcelField ef = field.getAnnotation(ExcelField.class); + if(null != ef && (ef.type() == 0 || ef.type() == 2)) { + annotationList.add(new Object[] {ef,field}); + } + } + new ExportExcel().createXlsxExcel("排班任务信息", annotationList, 2, false).writeToXlsx(request, response, fileName); + } catch (IOException e) { + e.printStackTrace(); + throw new BusinessException("模板导出失败"); + } + } + + @Override + public ImportViewVo importExcel(List dataList, int headRow) { + ImportViewVo importViewVo = new ImportViewVo(); + //获取用户信息 + List userList = sysUserMapper.selectList(new LambdaQueryWrapper<>()); + //获取台站信息 + List stationsList = gardsStationsService.getGardsStations(); + //存储排班任务信息 + List taskList = new ArrayList<>(); + //导入失败的结果集 + List failureList = new ArrayList<>(); + int successNum = 0; + int failureNum = 0; + try { + //第一步 读取导入数据中的全部排班任务相关信息进行新增 + if (CollectionUtils.isNotEmpty(dataList)){ + //遍历导入数据内容 + for (SysTaskExportVo sysTaskExportVo:dataList) { + boolean failFlag = false; + //排班任务相关台站信息集合 + List sysTaskStationList = new ArrayList<>(); + SysTask sysTask = new SysTask(); + headRow++; + //排班日期 + String schedulingDate = sysTaskExportVo.getSchedulingDate(); + //用户名称 + String userName = sysTaskExportVo.getUserName(); + //台站名称 + String stationName = sysTaskExportVo.getStationName(); + //存放切割后的台站名称 + List stations = new ArrayList<>(); + //判断排版日期,用户名称,台站名称是否为空 + if (StringUtils.isAnyEmpty(schedulingDate,userName,stationName)){ + failureList.add(new ImportFailureVo(headRow+1, "必填信息不全")); + failureNum++; + failFlag = true; + if (failFlag){ + continue; + } + } + //判断台站名称是否为空 + if (StringUtils.isNotBlank(stationName)){ + if (stationName.indexOf(",")>0){ + failureList.add(new ImportFailureVo(headRow+1, "台站信息内容错误,台站编码间用英文逗号隔开")); + failureNum++; + failFlag = true; + if (failFlag){ + continue; + } + }else { + stations = Arrays.asList(stationName.split(StringPool.COMMA)); + } + } + sysTask.setSchedulingDate(DateUtils.parseDate(schedulingDate, "yyyy-MM-dd")); + //根据用户名称过滤出对应的用户信息 + List sysUserList = userList.stream().filter(item -> item.getUsername().equals(userName)).collect(Collectors.toList()); + //如果用户存在,将用户id传入排班任务 + if (CollectionUtils.isNotEmpty(sysUserList)){ + SysUser sysUser = sysUserList.get(0); + sysTask.setUserId(sysUser.getId()); + }else { + failureList.add(new ImportFailureVo(headRow+1, "用户信息不存在")); + failureNum++; + failFlag = true; + if (failFlag){ + continue; + } + } + + //判断内容是否重复 + if (CollectionUtils.isNotEmpty(taskList)){ + //与本次录入的数据进行比较 + for (SysTask task:taskList) { + if (task.getUserId().equals(sysTask.getUserId()) && task.getSchedulingDate().equals(sysTask.getSchedulingDate()) ){ + failureList.add(new ImportFailureVo(headRow+1, "排班任务信息已存在,重复录入")); + failureNum++; + failFlag = true; + } + } + if (failFlag){ + continue; + } + } + + if (CollectionUtils.isNotEmpty(stations)){ + for (GardsStations station:stationsList) { + for (String sName:stations) { + if (station.getStationCode().equals(sName)){ + SysTaskStation taskStation = new SysTaskStation(); + taskStation.setStationId(String.valueOf(station.getStationId())); + taskStation.setStationName(sName); + sysTaskStationList.add(taskStation); + } + } + } + //判断 台站名称集合长度与排班任务对应台站信息长度不一致 丢失台站信息 + if (stations.size()!=sysTaskStationList.size()){ + String code = ""; + List sysTaskStationNames = sysTaskStationList.stream().map(SysTaskStation::getStationName).collect(Collectors.toList()); + for (String name:stations) { + if (sysTaskStationNames.indexOf(name)<0){ + code+=name+","; + } + } + code = code.substring(0,code.length()-1); + failureList.add(new ImportFailureVo(headRow+1, "台站信息"+code+"不存在!")); + failureNum++; + failFlag = true; + if (failFlag){ + continue; + } + } + sysTask.setStationList(sysTaskStationList); + } + successNum++; + taskList.add(sysTask); + } + //判断当前数据库中的排班任务信息是否为空 + if (CollectionUtils.isNotEmpty(taskList)){ + //遍历可以新增的数据信息 + for (SysTask sysTask:taskList) { + this.addOrUpdate(sysTask); + } + } + } + } catch (ParseException e) { + throw new RuntimeException(e); + } + importViewVo.setDetailList(failureList); + importViewVo.setSuccess(successNum); + importViewVo.setFailure(failureNum); + return importViewVo; + } + + private void addOrUpdate(SysTask sysTask){ + //根据用户名称及排班日期查询对应的数据 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysTask::getUserId, sysTask.getUserId()); + queryWrapper.eq(SysTask::getSchedulingDate, sysTask.getSchedulingDate()); + SysTask task = this.baseMapper.selectOne(queryWrapper); + //如果查询到的内容不为空,则进行修改 + if (Objects.nonNull(task)){ + + }else {//如果查询的内容为空,则进行新增 + + } + + } + + }