导入导出

master
周宇恒 2024-02-02 21:24:36 +08:00
parent 8b12c6a70d
commit 119d3fefa9
20 changed files with 1532 additions and 5 deletions

View File

@ -102,6 +102,23 @@
<artifactId>easyexcel</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.83</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>

View File

@ -0,0 +1,8 @@
package com.zyh.common.Enum;
public class WriteRowsOption {
public static final int TOTAL_COUNT = 10000000; // 总行数
public static final int SHEET_DATA_ROWS = 1000000; // 每个 Sheet 的行数
public static final int WRITE_DATA_ROWS = 1000000; // 每次写入的行数
}

View File

@ -2,7 +2,10 @@ package com.zyh.common.domain;
import lombok.Data;
import com.alibaba.excel.annotation.ExcelProperty;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
@Data
@ -16,7 +19,7 @@ public class Person {
@NotEmpty(message = "身份证号不能为空")
private String idcard;
@ExcelProperty("身份证类型编号")
@NotEmpty(message = "身份证类型不能为空")
@NotNull(message = "身份证类型不能为空")
private Integer idcardType;
@ExcelProperty("出生日期")
@NotEmpty(message = "出生日期不能为空")
@ -25,7 +28,7 @@ public class Person {
@NotEmpty(message = "民族不能为空")
private String nation;
@ExcelProperty("性别")
@NotEmpty(message = "性别不能为空")
@NotNull(message = "性别不能为空")
private Integer sex;
@ExcelProperty("手机号")
@NotEmpty(message = "手机号不能为空")
@ -37,13 +40,13 @@ public class Person {
@NotEmpty(message = "小区不能为空")
private String houseId;
@ExcelProperty("楼栋id")
@NotEmpty(message = "楼栋不能为空")
@NotNull(message = "楼栋不能为空")
private Integer buildId;
@ExcelProperty("单元")
@NotEmpty(message = "单元不能为空")
@NotNull(message = "单元不能为空")
private Integer unit;
@ExcelProperty("房号")
@NotEmpty(message = "房号不能为空")
@NotNull(message = "房号不能为空")
private Integer holdId;
@ExcelProperty("身份证照片")
@NotEmpty(message = "身份证照片不能为空")

View File

@ -0,0 +1,69 @@
package com.zyh.common.domain;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class PersonTest {
@ExcelProperty("编号")
private Integer id;
@ExcelProperty("姓名")
@NotNull(message = "姓名不能为空")
private String name;
@ExcelProperty("身份证号")
@NotNull(message = "身份证号不能为空")
private String idcard;
@ExcelProperty("身份证类型编号")
@NotNull(message = "身份证类型不能为空")
private Integer idcardType;
@ExcelProperty("出生日期")
@NotNull(message = "出生日期不能为空")
private String birth;
@ExcelProperty("民族")
@NotNull(message = "民族不能为空")
private String nation;
@ExcelProperty("性别")
@NotNull(message = "性别不能为空")
private Integer sex;
@ExcelProperty("手机号")
@NotNull(message = "手机号不能为空")
private String phone;
@ExcelProperty("户籍")
@NotNull(message = "户籍不能为空")
private String address;
@ExcelProperty("小区id")
@NotNull(message = "小区不能为空")
private String houseId;
@ExcelProperty("楼栋id")
@NotNull(message = "楼栋不能为空")
private Integer buildId;
@ExcelProperty("单元")
@NotNull(message = "单元不能为空")
private Integer unit;
@ExcelProperty("房号")
@NotNull(message = "房号不能为空")
private Integer holdId;
@ExcelProperty("身份证照片")
@NotNull(message = "身份证照片不能为空")
private String pic;
}

View File

@ -0,0 +1,413 @@
package com.zyh.common.util;
import com.zyh.common.utils.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.NumberToTextConverter;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class ImportExeclUtil {
private static int totalRows = 0;// 总行数
private static int totalCells = 0;// 总列数
private static String errorInfo;// 错误信息
/** 无参构造方法 */
public ImportExeclUtil()
{
}
public static int getTotalRows()
{
return totalRows;
}
public static int getTotalCells()
{
return totalCells;
}
public static String getErrorInfo()
{
return errorInfo;
}
/**
*
* Excel
*
*
* @param inputStream
* @param isExcel2003
* @return
* @see [##]
*/
public List<List<String>> read(InputStream inputStream, boolean isExcel2003) throws IOException {
List<List<String>> dataLst = null;
/** 根据版本选择创建Workbook的方式 */
Workbook wb = null;
if (isExcel2003) {
// 修改为XSSFWorkbook处理Excel 2007+格式
wb = new XSSFWorkbook(inputStream);
} else {
wb = new XSSFWorkbook(inputStream);
}
dataLst = readDate(wb);
return dataLst;
}
/**
*
*
*
* @param wb
* @return
* @see [##]
*/
private List<List<String>> readDate(Workbook wb)
{
List<List<String>> dataLst = new ArrayList<List<String>>();
/** 得到第一个shell */
Sheet sheet = wb.getSheetAt(0);
/** 得到Excel的行数 */
totalRows = sheet.getPhysicalNumberOfRows();
/** 得到Excel的列数 */
if (totalRows >= 1 && sheet.getRow(0) != null)
{
totalCells = sheet.getRow(0).getPhysicalNumberOfCells();
}
/** 循环Excel的行 */
for (int r = 1; r < totalRows; r++)
{
Row row = sheet.getRow(r);
if (row == null)
{
continue;
}
List<String> rowLst = new ArrayList<String>();
/** 循环Excel的列 */
for (int c = 0; c < getTotalCells(); c++)
{
Cell cell = row.getCell(c);
String cellValue = "";
if (null != cell)
{
// 以下是判断数据的类型
switch (cell.getCellTypeEnum())
{
case NUMERIC: // 数字
//如果是日期的话
if(cell != null && HSSFDateUtil.isCellDateFormatted(cell)){
Date d = cell.getDateCellValue();
DateFormat formater = new SimpleDateFormat("yyyy/MM/dd");
String da = formater.format(d);
cellValue = da;
break;
}
cellValue = NumberToTextConverter.toText(cell.getNumericCellValue());
break;
case STRING: // 字符串
cellValue = cell.getStringCellValue();
break;
case BOOLEAN: // Boolean
cellValue = cell.getBooleanCellValue() + "";
break;
case FORMULA: // 公式
cellValue = cell.getCellFormula() + "";
break;
case BLANK: // 空值
cellValue = "";
break;
case ERROR: // 故障
cellValue = "非法字符";
break;
default:
cellValue = "未知类型";
break;
}
}
rowLst.add(cellValue);
}
/** 保存第r行的第c列 */
dataLst.add(rowLst);
}
return dataLst;
}
/**
*
* Excel
*
* @param cell
* @return
* @see [##]
*/
/*private static String getCellValue(Cell cell)
{
String cellValue = "";
if (null != cell)
{
// 以下是判断数据的类型
switch (cell.getCellType())
{
case HSSFCell.CELL_TYPE_NUMERIC: // 数字
;: // 数字
if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell))
{
Date theDate = cell.getDateCellValue();
SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd");
cellValue = dff.format(theDate);
}
else
{
DecimalFormat df = new DecimalFormat("0");
cellValue = df.format(cell.getNumericCellValue());
}
break;
case HSSFCell.CELL_TYPE_STRING: // 字符串
cellValue = cell.getStringCellValue();
break;
case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
cellValue = cell.getBooleanCellValue() + "";
break;
case HSSFCell.CELL_TYPE_FORMULA: // 公式
cellValue = cell.getCellFormula() + "";
break;
case HSSFCell.CELL_TYPE_BLANK: // 空值
cellValue = "";
break;
case HSSFCell.CELL_TYPE_ERROR: // 故障
cellValue = "非法字符";
break;
default:
cellValue = "未知类型";
break;
}
}
return cellValue;
}*/
/**
*
*
*
* @param realValue
* @param fields
* @param f
* @param cellValue
* @return
* @see [##]
*/
private static Object getEntityMemberValue(Object realValue, Field[] fields, int f, String cellValue)
{
String type = fields[f].getType().getName();
switch (type)
{
case "char":
case "java.lang.Character":
case "java.lang.String":
realValue = cellValue;
break;
case "java.util.Date":
realValue = StringUtils.isBlank(cellValue) ? null : DateUtil.strToDate(cellValue, DateUtil.YYYY_MM_DD);
break;
case "java.lang.Integer":
realValue = StringUtils.isBlank(cellValue) ? null : Integer.valueOf(cellValue);
break;
case "int":
case "float":
case "double":
case "java.lang.Double":
case "java.lang.Float":
case "java.lang.Long":
case "java.lang.Short":
case "java.math.BigDecimal":
realValue = StringUtils.isBlank(cellValue) ? null : new BigDecimal(cellValue);
break;
default:
break;
}
return realValue;
}
/**
*
* Excel
*
*
* @param filePathOrName
* @param in
* @return
* @throws IOException
* @see [##]
*/
public static Workbook chooseWorkbook(String filePathOrName, InputStream in) throws IOException {
/** 根据版本选择创建Workbook的方式 */
Workbook wb = null;
boolean isExcel2003 = ExcelVersionUtil.isExcel2003(filePathOrName);
if (isExcel2003) {
// 修改为XSSFWorkbook处理Excel 2007+格式
wb = new XSSFWorkbook(in);
} else {
wb = new XSSFWorkbook(in);
}
return wb;
}
static class ExcelVersionUtil
{
/**
*
* 2003exceltrue2003
*
*
* @param filePath
* @return
* @see [##]
*/
public static boolean isExcel2003(String filePath)
{
return filePath.matches("^.+\\.(?i)(xls)$");
}
/**
*
* 2007exceltrue2007
*
*
* @param filePath
* @return
* @see [##]
*/
public static boolean isExcel2007(String filePath)
{
return filePath.matches("^.+\\.(?i)(xlsx)$");
}
}
public static class DateUtil
{
// ======================日期格式化常量=====================//
public static final String YYYY_MM_DDHHMMSS = "yyyy-MM-dd HH:mm:ss";
public static final String YYYY_MM_DD = "yyyy-MM-dd";
public static final String YYYY_MM = "yyyy-MM";
public static final String YYYY = "yyyy";
public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
public static final String YYYYMMDD = "yyyyMMdd";
public static final String YYYYMM = "yyyyMM";
public static final String YYYYMMDDHHMMSS_1 = "yyyy/MM/dd HH:mm:ss";
public static final String YYYY_MM_DD_1 = "yyyy/MM/dd";
public static final String YYYY_MM_1 = "yyyy/MM";
/**
*
* DateString
*
* @param date
* @param pattern
* @return
* @see [##]
*/
public static String dateToStr(Date date, String pattern)
{
SimpleDateFormat format = null;
if (null == date)
return null;
format = new SimpleDateFormat(pattern, Locale.getDefault());
return format.format(date);
}
/**
* Date
* <hr>
*
* @param s <br>
* datePattern :YYYY_MM_DD<br>
* @return java.util.Date
*/
public static Date strToDate(String s, String pattern)
{
if (s == null)
{
return null;
}
Date date = null;
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
try
{
date = sdf.parse(s);
}
catch (ParseException e)
{
e.printStackTrace();
}
return date;
}
}
}

View File

@ -0,0 +1,33 @@
package com.zyh.common.utils;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
* excel
*
* @author xuyingfa
*/
public class ExcelContextUtil {
private static final String SUFFIX = ".xlsx";
/**
*
*
* @param response
* @param filename
*/
public static void setDownloadHeader(HttpServletResponse response, String filename) {
if (!filename.endsWith(SUFFIX)) {
filename += SUFFIX;
}
response.setCharacterEncoding("utf-8");
filename = URLEncoder.encode(filename, StandardCharsets.UTF_8).replace("\\+", "%20");
// axios下载时获取文件名
response.setHeader("filename",filename);
response.setHeader("Content-Disposition", "attachment; filename=" + filename);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}
}

View File

@ -0,0 +1,101 @@
package com.zyh.common.utils;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.context.SheetWriteHandlerContext;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author ly-chn
*/
@Slf4j
@RequiredArgsConstructor
public class ExcelErrorFillHandler<T> implements SheetWriteHandler, RowWriteHandler {
/**
*
*/
private final List<ExcelLineResult<T>> resultList;
/**
* , 1
*/
private final Integer titleLineNumber;
/**
*
*/
private int resultColNum;
/**
*
*/
private static final String SUCCESS_MSG = "导入成功";
private static void setCellStyle(Cell cell, IndexedColors color) {
Workbook workbook = cell.getSheet().getWorkbook();
CellStyle style = workbook.createCellStyle();
Font font = workbook.createFont();
font.setColor(color.getIndex());
style.setFont(font);
cell.setCellStyle(style);
}
@Override
public void afterSheetCreate(SheetWriteHandlerContext context) {
SheetWriteHandler.super.afterSheetCreate(context);
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
Sheet cachedSheet = writeSheetHolder.getCachedSheet();
for (int i = 1; i <= cachedSheet.getLastRowNum() + 1; i++) {
// 空白数据, 不做处理
if (i < titleLineNumber) {
continue;
}
Row row = cachedSheet.getRow(i - 1);
// 标题行, 创建标题
if (i == titleLineNumber) {
this.resultColNum = row.getLastCellNum();
Cell cell = row.createCell(row.getLastCellNum(), CellType.STRING);
setCellStyle(cell, IndexedColors.BLACK);
cell.setCellValue("导入结果");
continue;
}
// 结果行
Cell cell = row.createCell(this.resultColNum, CellType.STRING);
String errMsg = convertErrMsg(resultList.get(i - titleLineNumber - 1));
if (errMsg == null) {
setCellStyle(cell, IndexedColors.GREEN);
cell.setCellValue(SUCCESS_MSG);
continue;
}
setCellStyle(cell, IndexedColors.RED);
cell.setCellValue(errMsg);
}
}
/**
*
*
* @param result
* @return
*/
private String convertErrMsg(ExcelLineResult<T> result) {
if (result.getBizError() != null) {
return result.getBizError();
}
if (result.getViolation().isEmpty()) {
return null;
}
return result.getViolation().stream().map(LyValidationUtil::getMessage)
.collect(Collectors.joining(";\n"));
}
}

View File

@ -0,0 +1,77 @@
package com.zyh.common.utils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
/**
* excel
*
* @author ly-chn
*/
@Slf4j
@RequiredArgsConstructor
class ExcelImportListener<T> implements ReadListener<T> {
private final List<ExcelLineResult<T>> excelLineResultList = new ArrayList<>();
public static String defaultBizError = "未知异常";
/**
* , ,
*/
private final Consumer<T> consumer;
/**
* ,
*/
@Override
public void invoke(T t, AnalysisContext analysisContext) {
if (log.isDebugEnabled()) {
log.debug("读取到数据: {}", t);
}
ExcelLineResult<T> build = ExcelLineResult.<T>builder()
.rowIndex(analysisContext.readRowHolder().getRowIndex())
.target(t)
.build();
excelLineResultList.add(build);
}
/**
*
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
if (excelLineResultList.isEmpty()) {
return;
}
Validator validator = SpringContextUtil.getBean(Validator.class);
excelLineResultList.forEach(it -> {
Set<ConstraintViolation<T>> validate = validator.validate(it.getTarget());
it.setViolation(validate);
// 校验不通过, 不必执行业务逻辑
if (!validate.isEmpty()) {
return;
}
try {
consumer.accept(it.getTarget());
} catch (LyException e) {
log.error("解析数据失败: {}, 异常信息: {}", it, e.getMessage());
it.setBizError(e.getMessage());
} catch (Exception e) {
log.error("解析数据失败", e);
it.setBizError(defaultBizError);
}
});
}
public List<ExcelLineResult<T>> getExcelLineResultList() {
return excelLineResultList;
}
}

View File

@ -0,0 +1,35 @@
package com.zyh.common.utils;
import lombok.Builder;
import lombok.Data;
import javax.validation.ConstraintViolation;
import java.util.Set;
/**
* Excel
*
* @author ly-chn
*/
@Data
@Builder
class ExcelLineResult<T> {
/**
* , 0
*/
private Integer rowIndex;
/**
*
*/
private T target;
/**
*
*/
private Set<ConstraintViolation<T>> violation;
/**
*
*/
private String bizError;
}

View File

@ -0,0 +1,86 @@
package com.zyh.common.utils;
import com.alibaba.excel.EasyExcel;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
/**
* excel
*
* @author ly-chn
*/
@Slf4j
public class ExcelUtil {
/**
* , 1
*
* @param file
* @param pojoClass
* @param consumer , SQL,
* LyException, messageExcel
*
* @param <T>
*/
public static <T> void read(@NotNull MultipartFile file, @NotNull Class<T> pojoClass, @NotNull Consumer<T> consumer) {
read(file, pojoClass, consumer, 1);
}
/**
*
*
* @param file
* @param pojoClass
* @param consumer , SQL,
* LyException, messageExcel
*
* @param titleLineNumber , 1
* @param <T>
*/
public static <T> void read(@NotNull MultipartFile file,
@NotNull Class<T> pojoClass,
@NotNull Consumer<T> consumer,
@NotNull Integer titleLineNumber) {
try {
ExcelImportListener<T> listener = new ExcelImportListener<>(consumer);
@Cleanup InputStream inputStream = file.getInputStream();
EasyExcel.read(inputStream, pojoClass, listener)
.headRowNumber(titleLineNumber)
.sheet().doRead();
List<ExcelLineResult<T>> resultList = listener.getExcelLineResultList();
boolean allSuccess = resultList.stream()
.allMatch(it -> it.getViolation().isEmpty() && Objects.isNull(it.getBizError()));
if (allSuccess) {
log.info("Excel 数据已全部导入: {}", resultList);
return;
}
log.error("Excel校验失败, 读取结果: {}", resultList);
HttpServletResponse response = RequestContextUtil.getResponse();
@Cleanup InputStream templateIs = file.getInputStream();
ExcelContextUtil.setDownloadHeader(response, "文件导入失败.xlsx");
EasyExcel.write(response.getOutputStream(), pojoClass)
.withTemplate(templateIs)
.autoCloseStream(false)
.registerWriteHandler(new ExcelErrorFillHandler<T>(resultList, titleLineNumber))
.needHead(false)
.sheet()
.doWrite(Collections.emptyList());
} catch (Exception e) {
log.error("文件读取失败", e);
throw new LyException.Normal("文件读取失败, 请检查文件格式");
}
throw new LyException.None();
}
}

View File

@ -0,0 +1,64 @@
package com.zyh.common.utils;
import lombok.Getter;
/**
*
*
* @author ly-chn
*/
@Getter
public class LyException extends RuntimeException {
private LyException(String message, Throwable cause) {
super(message, cause);
}
/**
* , (, , 西),
*/
public static class Normal extends LyException {
public Normal(String message, Throwable cause) {
super(message, cause);
}
public Normal(String message) {
this(message, null);
}
}
/**
* , , , /,
*/
public static class Panic extends LyException {
public Panic(String message, Throwable cause) {
super(message, cause);
}
public Panic(String message) {
this(message, null);
}
}
/**
* , , ,
*/
public static class Minor extends LyException {
public Minor(String message, Throwable cause) {
super(message, cause);
}
public Minor(String message) {
this(message, null);
}
}
/**
* , ,
*/
public static class None extends LyException {
public None() {
super(null, null);
}
}
}

View File

@ -0,0 +1,31 @@
package com.zyh.common.utils;
import com.alibaba.excel.annotation.ExcelProperty;
import org.apache.commons.lang3.reflect.FieldUtils;
import javax.validation.ConstraintViolation;
import java.lang.reflect.Field;
import java.util.Objects;
/**
* @author ly-chn
*/
public class LyValidationUtil {
public static String getMessage(ConstraintViolation<?> constraintViolation) {
String message = constraintViolation.getMessage();
if (!message.contains("{fieldTitle}")) {
return message;
}
String fieldTitle = "";
Class<?> rootBeanClass = constraintViolation.getRootBeanClass();
if (Objects.nonNull(rootBeanClass)) {
Field field = FieldUtils
.getField(rootBeanClass, constraintViolation.getPropertyPath().toString(), true);
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
if (Objects.nonNull(excelProperty) && excelProperty.value().length != 0) {
fieldTitle = excelProperty.value()[0];
}
}
return message.replace("{fieldTitle}", fieldTitle);
}
}

View File

@ -0,0 +1,40 @@
package com.zyh.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Optional;
/**
* spring
*
* @author ly-chn
*/
@Slf4j
public class RequestContextUtil {
/**
* @return
*/
public static HttpServletRequest getRequest() {
return getRequestAttributes().getRequest();
}
/**
* @return
*/
public static HttpServletResponse getResponse() {
return getRequestAttributes().getResponse();
}
private static ServletRequestAttributes getRequestAttributes() {
RequestAttributes attributes = Optional.ofNullable(RequestContextHolder.getRequestAttributes()).orElseThrow(() -> {
log.error("非web上下文无法获取请求属性, 异步操作请在同步操作内获取所需信息");
return new LyException.Panic("请求异常");
});
return ((ServletRequestAttributes) attributes);
}
}

View File

@ -0,0 +1,38 @@
package com.zyh.common.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author ly-chn
*/
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T getBean(Class<T> clazz) {
if (context == null) {
// 可以抛出异常或者做其他处理
throw new IllegalStateException("Spring context is not initialized");
}
return context.getBean(clazz);
}
public static <T> T getBean(String name, Class<T> requiredType) {
return context.getBean(name, requiredType);
}
/**
* @return application name
*/
public static String getId() {
return context.getId();
}
}

View File

@ -4,10 +4,12 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@ComponentScan(basePackages = "com.zyh")
public class ShopApplication {
public static void main(String[] args) {

View File

@ -1,16 +1,39 @@
package com.zyh.system.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.zyh.common.domain.House;
import com.zyh.common.domain.Person;
import com.zyh.common.domain.PersonTest;
import com.zyh.common.result.Result;
import com.zyh.common.util.ImportExeclUtil;
import com.zyh.common.utils.ExcelUtil;
import com.zyh.common.utils.LyException;
import com.zyh.common.utils.StringUtils;
import com.zyh.system.service.PersonService;
import lombok.extern.log4j.Log4j2;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@RestController
@RequestMapping("person")
@Log4j2
public class PersonController {
@Autowired
private PersonService personService;
@ -66,4 +89,70 @@ public class PersonController {
@GetMapping(value = "/importPersonInfo")
public Result uuApplyUserInfo(@RequestParam(value = "file",required = false) MultipartFile file) {
try {
//工具类
ImportExeclUtil readExcelUtil = new ImportExeclUtil();
List<List<String>> read = readExcelUtil.read(file.getInputStream(), true);
if (CollectionUtils.isNotEmpty(read)){
List<PersonTest> importList = read.stream().map(e -> {
PersonTest importDto = new PersonTest();
importDto.setId(StringUtils.isNotEmpty(e.get(0)) ? Integer.valueOf(e.get(0)) : null);
importDto.setName(e.get(1));
importDto.setIdcard(e.get(2));
importDto.setIdcardType(StringUtils.isNotEmpty(e.get(3)) ? Integer.valueOf(e.get(3)) : null);
importDto.setBirth(e.get(4));
importDto.setNation(e.get(5));
importDto.setSex(StringUtils.isNotEmpty(e.get(6)) ? Integer.valueOf(e.get(6)) : null);
importDto.setPhone(e.get(7));
importDto.setAddress(e.get(8));
importDto.setHouseId(e.get(9));
importDto.setBuildId(StringUtils.isNotEmpty(e.get(10)) ? Integer.valueOf(e.get(10)) : null);
importDto.setUnit(StringUtils.isNotEmpty(e.get(11)) ? Integer.valueOf(e.get(11)) : null);
importDto.setHoldId(StringUtils.isNotEmpty(e.get(12)) ? Integer.valueOf(e.get(12)) : null);
importDto.setPic(e.get(13));
return importDto;
}).collect(Collectors.toList());
if (CollectionUtils.isEmpty(importList)){
return Result.error("不能导入空文件");
}
//最多导入1W条
final int maxInt = 10000;
if (importList.size() > maxInt){
return Result.error("导入最多修改1W条");
}
Result result = personService.uuApplyUserInfo(importList);
return result;
}else{
return Result.error("不能导入空文件");
}
} catch (Exception e) {
e.printStackTrace();
return Result.error("导入失败,更新数据库时报错!报错信息:" + e.toString());
}
}
@PostMapping("derive")
public String derive() throws IOException {
return personService.derive();
}
}

View File

@ -2,6 +2,7 @@ package com.zyh.system.mapper;
import com.zyh.common.domain.House;
import com.zyh.common.domain.Person;
import com.zyh.common.domain.PersonTest;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@ -29,4 +30,19 @@ public interface PersonMapper {
void updatepersonNum(@Param("buildId") String buildId, @Param("unit") Integer unit, @Param("holdId") String holdId);
void updatepersonNumjia(@Param("buildId") Integer buildId, @Param("unit") Integer unit, @Param("holdId") Integer holdId);
Integer addPersonTest(PersonTest personTest);
List<Person> searchAdmin(Person person);
List<PersonTest> stuListWithLimit(@Param("offset") int offset, @Param("limit") int limit);
int selectHouseId(@Param("houseId") String houseId);
Integer selectBuildId(@Param("buildId") Integer buildId);
Integer selectUnit(@Param("buildId") Integer buildId, @Param("unit") Integer unit);
Integer selectHoldId(@Param("buildId") Integer buildId, @Param("unit") Integer unit, @Param("holdId") Integer holdId);
}

View File

@ -2,8 +2,10 @@ package com.zyh.system.service;
import com.zyh.common.domain.House;
import com.zyh.common.domain.Person;
import com.zyh.common.domain.PersonTest;
import com.zyh.common.result.Result;
import java.io.IOException;
import java.util.List;
public interface PersonService {
@ -22,4 +24,12 @@ public interface PersonService {
Result<List<House>> getHouseId();
Result updatePerson(Person person);
Result uuApplyUserInfo(List<PersonTest> importList);
List<Person> searchAdmin(Person person);
String derive() throws IOException;
}

View File

@ -1,19 +1,39 @@
package com.zyh.system.service.impl;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.zyh.common.Enum.WriteRowsOption;
import com.zyh.common.domain.House;
import com.zyh.common.domain.Person;
import com.zyh.common.domain.PersonTest;
import com.zyh.common.result.Result;
import com.zyh.common.util.ImportExeclUtil;
import com.zyh.common.utils.StringUtils;
import com.zyh.system.mapper.PersonMapper;
import com.zyh.system.service.PersonService;
import lombok.extern.log4j.Log4j2;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
@Service
@Log4j2
public class PersonServicempl implements PersonService {
@Autowired
private PersonMapper personMapper;
@Autowired
private HttpServletResponse response;
@Override
public Result addPerson(Person person) {
Integer add = personMapper.addPerson(person);
@ -75,4 +95,344 @@ public class PersonServicempl implements PersonService {
}
return Result.error("更新失败");
}
@Override
public Result uuApplyUserInfo(List<PersonTest> importList) {
int i = 0;
List<String> importResultColumn = new ArrayList<>(); // 新列,用于存储导入结果
List<String> resultList = createResultList(importList);
if (resultList.size() == 0) {
for (PersonTest personTest : importList) {
try {
Integer add = personMapper.addPersonTest(personTest);
// 修改房间人数
personMapper.updatepersonNumjia(personTest.getBuildId(), personTest.getUnit(), personTest.getHoldId());
i++;
log.info("第" + i + "条导入成功");
importResultColumn.add("导入成功");
} catch (Exception e) {
i++;
log.error("第" + i + "条导入失败,失败原因:" + e.getMessage());
importResultColumn.add("导入失败,原因:" + e.getMessage());
}
}
}else{
for (String s : resultList) {
importResultColumn.add(s);
}
}
// 向原始Excel文件添加新列
updateOriginalExcel(importList, importResultColumn);
return Result.success("导入完毕");
}
private void updateOriginalExcel(List<PersonTest> importList, List<String> importResultColumn) {
String fileName = "PersonTest";
try {
// 加载原始Excel文件
ImportExeclUtil readExcelUtil = new ImportExeclUtil();
List<List<String>> originalData = readExcelUtil.read(new FileInputStream("D:/2104A/daochu/" + fileName + ".xlsx"), true);
// 将导入结果值添加到每一行
for (int i = 0; i < importList.size(); i++) {
originalData.get(i).add(importResultColumn.get(i)); // 注意索引的调整
}
// 将更新后的数据写回原始Excel文件
writeDataToOriginalExcel(originalData, "D:/2104A/daochu/" + fileName + ".xlsx");
} catch (IOException e) {
log.error("更新原始Excel文件时出错" + e.getMessage());
}
}
private void writeDataToOriginalExcel(List<List<String>> data, String filePath) {
try {
Workbook wb = ImportExeclUtil.chooseWorkbook(filePath, new FileInputStream(filePath));
Sheet sheet = wb.getSheetAt(0);
// 清空第一行以下的所有行,保留第一行标题
for (int i = sheet.getLastRowNum(); i > 0; i--) {
Row row = sheet.getRow(i);
if (row != null) {
sheet.removeRow(row);
}
}
// 将数据写入表格,从第二行开始
for (int i = 0; i < data.size(); i++) {
Row row = sheet.createRow(i + 1); // 注意这里是 i + 1
for (int j = 0; j < data.get(i).size(); j++) {
Cell cell = row.createCell(j);
// 将空值用空字符串代替,你也可以使用其他默认值
String cellValue = data.get(i).get(j) != null ? data.get(i).get(j) : "";
cell.setCellValue(cellValue);
}
}
// 将更改写回文件
try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
wb.write(fileOut);
}
// 关闭工作簿
wb.close();
} catch (IOException e) {
log.error("将数据写入原始Excel文件时出错" + e.getMessage());
}
}
@Override
public List<Person> searchAdmin(Person person) {
return personMapper.searchAdmin(person);
}
@Override
public String derive() throws IOException {
download();
return null;
}
public void download() throws IOException {
log.info("*********导出开始!**************");
long startTime = System.currentTimeMillis();
String fileName = "PersonTest";
OutputStream outputStream = null;
try {
int totalCount = WriteRowsOption.TOTAL_COUNT; // 总行数
int sheetDataRows = WriteRowsOption.SHEET_DATA_ROWS; // 每个 Sheet 的行数
int writeDataRows = WriteRowsOption.WRITE_DATA_ROWS; // 每次写入的行数
// 获取路径
String filePath = "D:/2104A/daochu/" + fileName + ".xlsx";
// 计算需要的 Sheet 数量
Integer sheetNum = totalCount % sheetDataRows == 0 ? (totalCount / sheetDataRows) : (totalCount / sheetDataRows + 1);
// 计算一般情况下每一个 Sheet 需要写入的次数
Integer oneSheetWriteCount = sheetDataRows / writeDataRows;
// 计算最后一个 Sheet 需要写入的次数
Integer lastSheetWriteCount = totalCount % sheetDataRows == 0 ?
oneSheetWriteCount :
(totalCount % sheetDataRows % writeDataRows == 0 ?
(totalCount / sheetDataRows / writeDataRows) :
(totalCount / sheetDataRows / writeDataRows + 1));
outputStream = new FileOutputStream(filePath);
ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
for (int i = 0; i < sheetNum; i++) {
// 创建 Sheet
WriteSheet sheet = new WriteSheet();
sheet.setSheetName("Sheet" + i);
sheet.setSheetNo(i);
for (int j = 0; j < (i != sheetNum - 1 ? oneSheetWriteCount : lastSheetWriteCount); j++) {
// 创建 WriteSheet
WriteSheet writeSheet = EasyExcel.writerSheet(i, "Sheet" + (i + 1)).head(PersonTest.class)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
// 从数据库中提取数据
List<PersonTest> data = fetchDataFromDatabase(i * sheetDataRows + j * writeDataRows, writeDataRows);
// 将数据写入 Excel
excelWriter.write(data, writeSheet);
}
}
long endTime = System.currentTimeMillis();
long elapsedTime = endTime - startTime;
log.info("*********导出结束!导出耗时:" + elapsedTime + "毫秒**************");
// 关闭 ExcelWriter
excelWriter.finish();
outputStream.flush();
outputStream.close();
// 返回给前端的响应
response.setContentType("application/octet-stream");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 从生成的文件读取内容并写入响应输出流
try (InputStream inputStream = new FileInputStream(filePath);
OutputStream responseOutputStream = response.getOutputStream()) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
responseOutputStream.write(buffer, 0, bytesRead);
}
}
// 删除生成的文件
// File file = new File(filePath);
// if (file.exists()) {
// file.delete();
// }
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
outputStream.close();
}
}
}
/**
*
*
* @param offset
* @param limit
* @return
*/
public List<PersonTest> fetchDataFromDatabase(int offset, int limit) {
// 调用数据库查询方法以检索数据,注意在 SQL 查询中使用 offset 和 limit
return personMapper.stuListWithLimit(offset, limit);
}
private List<String> createResultList(List<PersonTest> importList) {
List<String> resultList = new ArrayList<>();
for (PersonTest personTest : importList) {
StringBuilder ret=new StringBuilder();
//姓名验证
if (StringUtils.isEmpty(personTest.getName())) {
ret.append("姓名不能为空"+" ");
}
//身份证号验证
if (StringUtils.isEmpty(personTest.getIdcard())) {
ret.append("身份证号不能为空" + " ");
}else{
if (!idcardRule(personTest.getIdcard())) {
ret.append("身份证号格式有误" + " ");
}
}
//身份证号编号验证
if (personTest.getIdcardType()==null) {
ret.append("身份证类型编号不能为空" + " ");
}else {
if (personTest.getIdcardType() != 1 && personTest.getIdcardType() != 2 && personTest.getIdcardType() != 3 && personTest.getIdcardType() != 4) {
ret.append("身份证类型编号必须1-4数字1居民身份证 2军官证 3警官证 4普通护照" + " ");
}
}
//出生日期验证
if (StringUtils.isEmpty(personTest.getBirth())) {
ret.append("出生日期不能为空" + " ");
}
//民族验证
if (StringUtils.isEmpty(personTest.getNation())) {
ret.append("民族不能为空" + " ");
}
//性别验证
if (personTest.getSex()==null) {
ret.append("性别不能为空" + " ");
}else{
if (personTest.getSex() != 1 && personTest.getSex() != 2 && personTest.getSex() != 3) {
ret.append("性别必须1-3数字1男2女3未知" + " ");
}
}
//手机号验证
if (StringUtils.isEmpty(personTest.getPhone())) {
ret.append("手机号不能为空" + " ");
}else{
if (!telRule(personTest.getPhone())) {
ret.append("手机号格式有误" + " ");
}
}
//户籍验证
if (StringUtils.isEmpty(personTest.getAddress())) {
ret.append("地址不能为空" + " ");
}
//小区编号验证
if (StringUtils.isEmpty(personTest.getHouseId())) {
ret.append("小区编号不能为空" + " ");
}else{
int re= personMapper.selectHouseId(personTest.getHouseId());
if (re<=0) {
ret.append("小区编号不存在" + " ");
}
}
//楼栋编号验证
if (personTest.getBuildId()==null) {
ret.append("楼栋编号不能为空" + " ");
}else{
Integer buildId = personMapper.selectBuildId(personTest.getBuildId());
if (buildId<=0 || buildId==null) {
ret.append("楼栋编号不存在" + " ");
}
}
//单元编号验证
if (personTest.getUnit()==null) {
ret.append("单元编号不能为空" + " ");
}else{
if (personTest.getBuildId() != null) {
Integer unit = personMapper.selectUnit(personTest.getBuildId(),personTest.getUnit());
if (unit<=0 || unit==null) {
ret.append("单元编号不存在" + " ");
}
}
}
//房号编号验证
if (personTest.getHoldId()==null) {
ret.append("房号编号不能为空" + " ");
}else{
if (personTest.getBuildId() != null && personTest.getUnit() != null) {
Integer holdId = personMapper.selectHoldId(personTest.getBuildId(),personTest.getUnit(),personTest.getHoldId());
if (holdId<=0 || holdId==null) {
ret.append("房号编号不存在" + " ");
}
}
}
//身份证照片验证
if (StringUtils.isEmpty(personTest.getPic())) {
ret.append("身份证照片不能为空" + " ");
}
resultList.add(ret.toString());
}
return resultList;
}
private boolean telRule(String phone) {
Pattern compile = Pattern.compile("^(?:(?:\\+|00)86)?1(?:(?:3[\\d])|(?:4[5-7|9])|(?:5[0-3|5-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\\d])|(?:9[1|8|9]))\\d{8}$");
return compile.matcher(phone).matches();
}
private boolean idcardRule(String idcard) {
Pattern compile = Pattern.compile("^[1-9]\\\\d{5}(18|19|20)\\\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\\\d|3[01])\\\\d{3}(\\\\d|X|x)$");
return compile.matcher(idcard).matches();
}
}

View File

@ -20,6 +20,23 @@
#{holdId},
#{pic})
</insert>
<insert id="addPersonTest">
insert into person values
(0,
#{name},
#{idcard},
#{idcardType},
#{birth},
#{sex},
#{nation},
#{phone},
#{address},
#{houseId},
#{buildId},
#{unit},
#{holdId},
#{pic})
</insert>
<update id="updatePerson">
update person set
name = #{name},
@ -67,6 +84,24 @@
<select id="getHouseId" resultType="com.zyh.common.domain.House">
select plot_id,name from house
</select>
<select id="searchAdmin" resultType="com.zyh.common.domain.Person">
select * from person
</select>
<select id="stuListWithLimit" resultType="com.zyh.common.domain.PersonTest">
select * from person
</select>
<select id="selectHouseId" resultType="java.lang.Integer">
select plot_id from house where plot_id=#{houseId}
</select>
<select id="selectBuildId" resultType="java.lang.Integer">
select build_id from building where build_id=#{buildId}
</select>
<select id="selectUnit" resultType="java.lang.Integer">
select unit from building where build_id=#{buildId} and unit=#{unit}
</select>
<select id="selectHoldId" resultType="java.lang.Integer">
select hold_id from households where build_id=#{buildId} and unit=#{unit} and hold_id=#{holdId}
</select>
</mapper>