之前转载过一篇对Excel基本操作相关的文章,这篇文章的浏览量迅速飙升,以至于在我博客的热门文章中排到了第三的位置,不过那篇转载的文章实用性差并且讲解不是很清晰,所以打算趁着今天休息,写一篇关于SpringBoot通过WorkBook快速实现对Excel的导入、导出、数据校验的文章,也是便于日后查阅。
1、引入依赖
org.apache.poi
poi
4.0.0
org.apache.poi
poi-ooxml
4.0.0
2、Excel类型枚举
/**
* @Description:Excel类型枚举
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 13:59:48
* @Version:1.0
*/
public enum ExcelTypeEnum {
/**
* 报备导入
*/
REPORT_TYPE(BatchImportConsts.EXCEL_REPORT_MODEL_TYPE, new BatchImportStruBO(BatchImportConsts.excel_report_titles, new ReportRecordCheck(), SpringHelper.getBeanByClass(ReportInsertServiceImpl.class))),
/**
* 线索导入
*/
CLUE_TYPE(BatchImportConsts.EXCEL_CLUE_MODEL_TYPE, new BatchImportStruBO(BatchImportConsts.excel_clue_titles, new ClueRecordCheck(), SpringHelper.getBeanByClass(ClueInsertServiceImpl.class)));
@Setter
@Getter
private String type;
@Setter
@Getter
private BatchImportStruBO struBO;
ExcelTypeEnum(String type, BatchImportStruBO struBO) {
this.type = type;
this.struBO = struBO;
}
/**
* 判断key对应的枚举是否存在,若存在,返回此枚举;否则返回null
*
* @param key
* @return
*/
public static ExcelTypeEnum containKey(String key) {
ExcelTypeEnum type = null;
switch (key) {
case "report":
type = ExcelTypeEnum.REPORT_TYPE;
break;
case "clue":
type = ExcelTypeEnum.CLUE_TYPE;
break;
default:
type = null;
break;
}
return type;
}
}
3、 Excel导入相关配置
/**
* Excel导入相关配置
*
* @author zhangzhixiang
* @data 2018/09/18 11:48:59
*/
public class BatchImportConsts {
/**
* Excel导入模式
*/
public static String EXCEL_CLUE_MODEL_TYPE = "clue";
public static String EXCEL_REPORT_MODEL_TYPE = "report";
/**
* 报备批量导入Excel标题映射信息
*/
public static List excel_report_titles;
/**
* 线索批量导入Excel标题映射信息
*/
public static List excel_clue_titles;
/**
* 报备导入Excel标题
*/
public static final String EXCEL_REPORT_RECORD_COLUMN_PROVINCE = "省";
public static final String EXCEL_REPORT_RECORD_COLUMN_CITY = "市";
public static final String EXCEL_REPORT_RECORD_COLUMN_AREA = "区";
public static final String EXCEL_REPORT_RECORD_COLUMN_CUSTOMER_SOURCE = "客户来源(单位名称)";
public static final String EXCEL_REPORT_RECORD_COLUMN_ITEM = "项目归属";
public static final String EXCEL_REPORT_RECORD_COLUMN_DATA_CONTENT_DESC = "数据内容描述";
public static final String EXCEL_REPORT_RECORD_COLUMN_DATA_NUM = "数据数量";
public static final String EXCEL_REPORT_RECORD_COLUMN_DATA_PURPOSE = "数据用途";
/**
* 线索导入Excel标题
*/
public static final String EXCEL_CLUE_RECORD_COLUMN_CLUE_SOURCE = "线索来源地";
public static final String EXCEL_CLUE_RECORD_COLUMN_ITEM = "归属项目";
public static final String EXCEL_CLUE_RECORD_COLUMN_TAG = "线索标签";
public static final String EXCEL_CLUE_RECORD_COLUMN_NAME = "线索名称";
public static final String EXCEL_CLUE_RECORD_COLUMN_DESC = "线索内容";
public static final String EXCEL_CLUE_RECORD_COLUMN_CLUE_REMARK = "线索备注";
public static final String EXCEL_CLUE_RECORD_COLUMN_PERSON_NUM = "人数";
public static final String EXCEL_CLUE_RECORD_COLUMN_PERSON_NAME = "姓名";
public static final String EXCEL_CLUE_RECORD_COLUMN_ID_CARD = "身份证号";
public static final String EXCEL_CLUE_RECORD_COLUMN_IPHONE = "手机号";
public static final String EXCEL_CLUE_RECORD_COLUMN_SEX = "性别";
public static final String EXCEL_CLUE_RECORD_COLUMN_NATION = "名族";
/**
* 报备配置(标题头+是否必填)
*/
static {
excel_report_titles = new ArrayList<>();
excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_PROVINCE, BaseColumn.TRUE));
excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_CITY, BaseColumn.FALSE));
excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_AREA, BaseColumn.FALSE));
excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_CUSTOMER_SOURCE, BaseColumn.TRUE));
excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_ITEM, BaseColumn.TRUE));
excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_DATA_CONTENT_DESC, BaseColumn.TRUE));
excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_DATA_NUM, BaseColumn.FALSE));
excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_DATA_PURPOSE, BaseColumn.FALSE));
}
/**
* 线索配置(标题头+是否必填)
*/
static {
excel_clue_titles = new ArrayList<>();
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_CLUE_SOURCE, BaseColumn.FALSE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_ITEM, BaseColumn.FALSE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_TAG, BaseColumn.FALSE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_NAME, BaseColumn.FALSE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_DESC, BaseColumn.FALSE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_CLUE_REMARK, BaseColumn.FALSE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_PERSON_NUM, BaseColumn.FALSE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_PERSON_NAME, BaseColumn.FALSE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_ID_CARD, BaseColumn.TRUE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_IPHONE, BaseColumn.FALSE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_SEX, BaseColumn.FALSE));
excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_NATION, BaseColumn.FALSE));
}
}
4、批量导入Excel数据结构
/**
* @Description:批量导入Excel数据结构信息
* @Author:zhangzhixiang
* @CreateDate:2018/09/05 19:54:32
* @Version:1.0
*/
@Data
public class BatchImportStruBO {
/**
* Excel字段与db字段关系
*/
private List importTitles;
/**
* 记录校验器
*/
private BaseRecordCheck recordCheck;
/**
* 入表处理器
*/
private BaseInsertService insertHandle;
public BatchImportStruBO(List importTitles, BaseRecordCheck recordCheck, BaseInsertService insertHandle) {
this.importTitles = importTitles;
this.recordCheck = recordCheck;
this.insertHandle = insertHandle;
}
}
5、Spring帮助类
/**
* @Description:Spring帮助类
* @Author:zhangzhixaing
* @CreateDate:2018/08/31 16:39:45
* @Version:1.0
*/
@Component
public class SpringHelper implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(SpringHelper.applicationContext == null) {
SpringHelper.applicationContext = applicationContext;
}
}
/**
* 根据一个bean的id获取配置文件中相应的bean
*/
public static Object getBean(String beanId) throws BeansException {
if(applicationContext.containsBean(beanId)) {
applicationContext.getBean(beanId);
}
return null;
}
/**
* 根据一个bean的类型获取配置文件中相应的bean
*/
public static T getBeanByClass(Class requiredType) throws BeansException {
return applicationContext.getBean(requiredType);
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean的定义,则返回true,否则false
*/
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
/**
* 获取Spring容器
*/
public static ApplicationContext getApplicationContext() {
return SpringHelper.applicationContext;
}
}
6、String帮助类
/**
* @Description:String帮助类
* @Author:zhangzhixaing
* @CreateDate:2018/08/31 16:39:45
* @Version:1.0
*/
public class StringHelper extends StringUtils {
public StringHelper() {}
/**
* 判断是否为空
*/
public static boolean isBlankAnyWay(String str) {
return isBlank(str) || "null".equalsIgnoreCase(str);
}
/**
* 判断是否非空
*/
public static boolean isNotBlankAnyWay(String str) {
return !isBlankAnyWay(str);
}
/**
* 将null转为空
*/
public static String nullToEmpty(String str) {
return Strings.nullToEmpty(str);
}
/**
* 将空转为null
*/
public static String emptyToNumm(String str) {
return Strings.emptyToNull(str);
}
/**
* 左填充
*/
public static String padStart(String str, int minLength, char padChar) {
return Strings.padStart(str, minLength, padChar);
}
/**
* 右填充
*/
public static String padEnd(String str, int minLength, char padChar) {
return Strings.padEnd(str, minLength, padChar);
}
}
7、Excel单元格
/**
* @Description:Excel单元格实体
* @Author:zhangzhixaing
* @CreateDate:2018/08/31 16:39:45
* @Version:1.0
*/
@Data
public class BaseColumn {
/**
* 常量定义
*/
public static final Boolean TRUE = true;
public static final Boolean FALSE = false;
/**
* Excel中对应的字段名称
*/
protected String excelName;
/**
* Excel字段值
*/
protected String excelValue;
/**
* 是否必填
*/
protected Boolean isRequired;
/**
* 值得校验是否成功,默认true
*/
protected boolean checkIsSuccess = true;
/**
* 校验结果信息
*/
protected String checkMessage;
public BaseColumn() {
super();
}
public BaseColumn(String excelName, Boolean isRequired) {
super();
this.excelName = excelName;
this.isRequired = isRequired;
}
public BaseColumn(String excelName) {
super();
this.excelName = excelName;
}
}
8、行校验接口
/**
* @Description:行校验接口
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:56:32
* @Version:1.0
*/
public interface BaseRecordCheck {
/**
* 记录校验
*
* @param cells
* @return
* @throws Exception
*/
List valueCheck(List cells) throws Exception;
}
9、线索行校验实现
/**
* @Description:线索行校验
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 12:59:48
* @Version:1.0
*/
public class ClueRecordCheck implements BaseRecordCheck {
@Override
public List valueCheck(List cells) throws Exception {
//字段校验
for (BaseColumn column : cells) {
switch (column.getExcelName()) {
case BatchImportConsts.EXCEL_CLUE_RECORD_COLUMN_NAME:
new BaseCheck().valueCheck(column);
break;
case BatchImportConsts.EXCEL_CLUE_RECORD_COLUMN_ID_CARD:
new ClueIdcardCheck().valueCheck(column);
break;
case BatchImportConsts.EXCEL_CLUE_RECORD_COLUMN_IPHONE:
new CluePhoneCheck().valueCheck(column);
break;
case BatchImportCONsts.EXCEL_CLUE_RECORD_COLUMN_SEX:
new ClueSexCheck().valueCheck(column);
break;
default:
break;
}
}
return cells;
}
}
10、列校验接口
/**
* @Description:列校验接口
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:56:34
* @Version:1.0
*/
public interface BaseColumnCheck {
/**
* 校验字段值
*
* @param cell
* @return
* @throws Exception
*/
BaseColumn valueCheck(BaseColumn cell) throws Exception;
/**
* 多字段联合校验
*
* @param cells
* @return
* @throws Exception
*/
List valueCheck(List cells) throws Exception;
}
11、线索列校验实现(基础非空校验)
/**
* @Description:基础非空校验
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
public class BaseCheck implements BaseColumnCheck {
private static final String EMPTY_MESSAGE = "不能为空;"
@Override
public BaseColumn valueCheck(BaseColumn cell) throws Exception {
if (StringUtils.isBlank(cell.getExcelValue())) {
cell.setCheckIsSuccess(false);
cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + EMPTY_MESSAGE);
} else {
cell.setCheckIsSuccess(true);
}
return cell;
}
@Override
public List valueCheck(List cells) throws Exception {
return null;
}
}
12、线索列校验实现(身份证号校验)
/**
* @Description:身份证号校验
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
public class ClueIdcardCheck implements BaseColumnCheck {
private static final String EMPTY_MESSAGE = "不能为空;";
private static final String WRONG_MESSAGE = "格式不对;";
@Override
public BaseColumn valueCheck(BaseColumn cell) throws Exception {
if(cell.getIsRequired() || (!cell.getIsRequired() && StringHelper.isNotBlankAnyWay(cell.getExcelValue()))) {
cell.setCheckIsSuccess(false);
cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + EMPTY_MESSAGE);
} else {
//校验身份证号合法性
String reg = "^\\d{15}$|^\\d{17}[0-9Xx]$";
if(!cell.getExcelValue().matches(reg)) {
cell.setCheckIsSuccess(false);
cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + WRONG_MESSAGE);
}
}
return cell;
}
@Override
public List valueCheck(List cells) throws Exception {
return null;
}
}
13、线索列校验实现(手机号校验)
/**
* @Description:手机号校验
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
public class CluePhoneCheck implements BaseColumnCheck {
private static final String EMPTY_MESSAGE = "不能为空;"
private static final String WRONG_MESSAGE = "格式不对;"
private Pattern p = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$");
@Override
public BaseColumn valueCheck(BaseColumn cell) throws Exception {
if(cell.getRequired() || (!cell.getRequired() && StringHelper,isNotBlankAnyWay(cell.getExcelValue()))) {
cell.setCheckIsSuccess(false);
cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + EMPTY_MESSAGE);
} else {
//校验手机号合法性
Matcher m = p.matcher(cell.getExcelValue());
if(!m.matches()) {
cell.setCheckIsSuccess(false);
cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + WRONG_MESSAGE);
}
}
return cell;
}
@Override
public List valueCheck(List cells) throws Exception {
return null;
}
}
14、线索列校验实现(性别校验)
/**
* @Description:性别校验
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
public class ClueSexCheck implements BaseColumnCheck {
private static final String EMPTY_MESSAGE = "不能为空;"
private static final String WRONG_MESSAGE = "格式不对;"
private String man = "男";
private String women = "女";
@Override
public BaseColumn valueCheck(BaseColumn cell) throws Exception {
if(cell.getRequired() || (!cell.getRequired() && StringHelper,isNotBlankAnyWay(cell.getExcelValue()))) {
cell.setCheckIsSuccess(false);
cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + EMPTY_MESSAGE);
} else {
//校验手机号合法性
Matcher m = p.matcher(cell.getExcelValue());
if(!m.matches()) {
if(!(man.equals(cell.getExcelValue()) || women.equals(cell.getExcelValue()))) {
cell.setCheckIsSuccess(false);
cell.setCheckMessage((cell.getCheckMessage == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + WRONG_MESSAGE);
}
}
}
return cell;
}
@Override
public List valueCheck(List cells) throws Exception {
return null;
}
}
15、Excel入库接口
/**
* @Description:Excel入库接口
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
public interface BaseInsertService {
/**
* Excel数据入库
*
* @param rows Excle数据
* @param isSuccess
* @author zhangzhixiang
* @data 2018/09/19 18:56:43
*/
void insertDB(List> rows, Boolean isSuccess) throws Exception;
}
16、Excel入库实现(线索)
/**
* @Description:Excel线索入库接口
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
@Service
public class ClueInsertServiceImpl implements BaseInsertService {
@Autowired
public ClueInfoDAO clueInfoDAO;
@Override
@Transactional(rollbackFor = Exception.class)
public void insertDB(List> rows, Boolean isSuccess) throws Exception {
//线索自定义入库代码
}
}
17、Excel公共服务接口(OSS)
/**
* @Description:Excel服务接口(OSS)
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
public interface ExcelOperateService {
/**
* Excel文件导入
* @param fileName 原文件名
* @param code 文件唯一标示
* @param model Excel类型标识
* @return 解析结果
* @throws Exception
*/
ExcelParseResultBO excelImport(String code, String model) throws Exception;
/**
* Excel文件导出
*
* @param response
* @param rows 需要导出的数据
* @param fileName 文件名
* @param sheetName sheet名
* @return void
* @author zxzhang
* @date 2019/10/10
*/
void excelExport(HttpServletResponse response, List> rows, String fileName, String sheetName) throws Exception;
}
18、Excel公共服务实现(OSS)
/**
* @Description:Excel公共服务实现(OSS)
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
@Service
public class ExcelOperateServiceImpl implements ExcelOperateService {
private static final Logger logger = LoggerFactory.getLogger(ExcelOperateServiceImpl.class);
private static final String SERVICE_ERROR_MESSAGE = "批量导入失败";
/**
* Excel文件导入
*
* @param code OSS文件唯一标示
* @param model 业务类型(clue、report)
* @return 解析结果
* @throws Exception
*/
@Override
public ExcelOperateBO excelImport(String code, String model) throws Exception {
FileClient client = ClientFactory.createClientByType(BootstrapConsts.file_client_type);
ExcelOperateBO resultBO = null;
//1、获取Excel数据
List> excelDatas = null;
excelDatas = ExcelRead.getSheetDataWithTitle(client.getFileStream(code), code, null);
String message;
if(null == excelDatas || excelDatas.size() < SimpleConst.TWO) {
message = "文件无有效数据";
resultBO = new ExcelOperateBO();
resultBO.setFileOK(false);
resultBO.setMessage(message);
return resultBO;
}
logger.info("记录数量:" + excelDatas.size());
//2、校验标题合法性
resultBO = excelTitleCheck(excelDatas.get(0), model);
if(!resultBO.getFileOK()) {
return resultBO;
}
//3、将Excel中的每列数据与title名称绑定
List> excelRows = null;
excelRows = getExcelData(excelDatas, model);
if(null == excelRows || excelRows.size() == 0) {
resultBO = new ExcelOperateBO();
resultBO.setTotalNum(0);
resultBO.setSuccessNum(0);
resultBO.setFailNum(0);
resultBO.setFileOK(true);
return resultBO;
}
//4、Excel数据校验
List> successRows = new ArrayList<>();
List> failRows = new ArrayList<>();
rowsCheck(excelRows, model, successRows, failRows);
//5、入库
if(successRows.size() > 0) {
insertdb(successRows, model, true);
}
if(failRows.size() > 0) {
insertdb(failRows, model, false);
}
return resultBO;
}
/**
* Excel文件导出
*
* @param response
* @param rows 导出文件内容(包括标题)
* @param fileName 导出文件名
* @param sheetName sheet名称
* @return 解析结果
* @throws Exception
*/
@Override
public void excelExport(HttpServletResponse response, List> rows, String fileName, String sheetName) throws Exception {
ExcelWrite.exportExcel(response, rows, fileName, sheetName);
}
/**
* 数据入库
*
* @param rows 待写入的数据
* @param model 业务类型(clue、report)
* @param isSuccess 是否成功
*/
private void insertdb(List> rows, String model, Boolean isSuccess) throws Exception {
BatchImportStruBO struBO = ExcelTypeEnum.containKey(model).getStruBO();
BaseInsertService insertHandle = struBO.getInsertHandle();
insertHandle.insertDB(rows, isSuccess);
}
/**
* Excek数据校验
*
* @param excelRows 待校验数据
* @param model 业务类型(clue、report)
* @param successRows 校验成功的数据
* @param failRows 校验失败的数据
*/
private void rowsCheck(List> excelRows, String model, List> successRows, List> failRows) throws Exception {
BaseRecordCheck recordCheck = ExcelTypeEnum.containKey(model).getStruBO().getRecordCheck();
List checkedRow = null;
boolean isSuccessCheck = true;
for (List rowData : excelRows) {
checkedRow = recordCheck.valueCheck(rowData);
if(checkedRow == null || checkedRow.size() == 0) {
continue;
}
for (BaseColumn cell : checkedRow) {
if (!cell.isCheckIsSuccess()) {
isSuccessCheck = cell.isCheckIsSuccess();
break;
}
}
if(!isSuccessCheck) {
failRows.add(checkedRow);
} else {
successRows.add(checkedRow);
}
isSuccessCheck = true;
}
}
/**
* 获取Excel有效数据(将title与Excel数据绑定)
*
* @param excelDatas Excel数据
* @return
* @throws Exception
*/
private List> getExcelData(List> excelDatas, String model) throws Exception {
BatchImportStruBO batchImportStruBO = ExcelTypeEnum.containKey(model).getStruBO();
List titles = batchImportStruBO.getImportTitles();
excelDatas.remove(0);
for(int i = 0; i row = valueTrim(excelDatas.get(i));
excelDatas.set(i, row);
}
List> excelRows = excelDataTidy(titles, excelDatas);
if (null == excelRows) {
throw new Exception("excelDatas数据转为excelRows数据报错");
}
return excelRows;
}
/**
* 将标题和具体的数据组合
*
* @param titles 标题信息
* @param rowList 记录数据,其中记录的字段索引与对应的标题索引一致
* @return
*/
private List> excelDataTidy(List titles, List> rowList) {
List> datas = new ArrayList<>();
List rowData = null;
BaseColumn cellData = null;
List excelRow = null;
for(int i = 0; i < rowList.size(); i++) {
rowData = new ArrayList<>();
excelRow = rowList.get(i);
for(int j = 0; j < excelRow.size(); j++) {
String excelCellValue = excelRow.get(j);
String title = null;
if(j < titles.size()) {
title = titles.get(j).getExcelName();
} else {
break;
}
cellData = new BaseColumn();
cellData.setExcelName(title);
cellData.setIsRequired(titles.get(j).getIsRequired());
cellData.setExcelValue(excelCellValue);
rowData.add(cellData);
}
datas.add(rowData);
}
return datas;
}
/**
* 校验标题是否合规
*
* @param titles 标题信息
* @param model 业务类型(clue、report)
* @return
*/
private ExcelOperateBO excelTitleCheck(List titles, String model) throws Exception {
BatchImportStruBO batchImportStruBO = ExcelTypeEnum.containKey(model).getStruBO();
String message = "解析标题报错";
titles = valueTrim(titles);
List orderTitles = batchImportStruBO.getImportTitles();
boolean titleCheck = titleCheck(titles, orderTitles);
if (!titleCheck) {
throw new Exception(message);
}
ExcelOperateBO resultBO= new ExcelOperateBO();
resultBO.setFileOK(true);
return resultBO;
}
/**
* 校验Excel中标题是否包含所需要的标题
*
* @param titles 标题信息
* @param orderTitles 要求的标题信息
* @return
*/
private boolean titleCheck(List titles, List orderTitles) {
if (null == titles || titles.size() == 0) {
return false;
}
if(null == orderTitles || orderTitles.size() == 0) {
return false;
}
List names = new ArrayList<>();
for (BaseColumn column : orderTitles) {
names.add(column.getExcelName());
}
for (String name : names) {
if(!titles.contains(name)) {
return false;
}
}
return true;
}
/**
* 去除首尾无效空格
*
* @param values 要去空格的字符串
* @return
*/
private List valueTrim(List values) {
if(null == values || values.size() == 0) {
return values;
}
for(int i=0; i < values.size(); i++) {
if(StringUtils.isBlank(values.get(i))) {
values.set(i, null);
continue;
} else {
values.set(i, values.get(i).trim());
}
}
return values;
}
}
19、Excel基础操作
/**
* @Description:Excel基础操作
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
public class ExcelBaseOperate {
private static final Logger logger = LoggerFactory.getLogger(ExcelBaseOperate.class);
private static final String SUFFIX_XLS = "xls";
private static final String SUFFIX_XLSX = "xlsx";
/**
* 获取Excel操作类
*
* @param inputStream
* @param name
* @return
* @throws Exception
*/
public static Workbook getWorkbook(InputStream inputStream, String name) throws Exception {
Workbook wb = null;
if (name.endsWith(SUFFIX_XLSX)) {
wb = new XSSFWorkbook(OPCPackage.open(inputStream));
} else if (name.endsWith(SUFFIX_XLS)) {
wb = WorkbookFactory.create(inputStream);
} else {
String errorMessage = "无法识别的文件类型。文件名称:" + name;
logger.error(errorMessage);
throw new Exception(errorMessage);
}
return wb;
}
}
20、Excel读取操作
/**
* @Description:Excel读取操作
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
public class ExcelRead {
private static final Logger logger = LoggerFactory.getLogger(ExcelRead.class);
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* 获取sheet页标题
*
* @param inputStream Excel文件流
* @param excelName Excel文件名
* @param sheetName sheet页名称。不输入则默认取第一个sheet
* @return
*/
public static List getSheetTitle(InputStream inputStream, String excelName, String sheetName) throws Exception {
Workbook workbook = ExcelBaseOperate.getWorkbook(inputStream, excelName);
//没有输入sheetname,则默认第一个sheet
if (StringUtils.isBlank(sheetName)) {
sheetName = workbook.getSheetAt(0).getSheetName();
}
List> sheetData = parseSheet(workbook, sheetName, 0, 0);
if(null == sheetData || sheetData.size() == 0) {
return null;
}
return sheetData.get(0);
}
/**
* 获取带标题的sheet页数据
*
* @param inputStream Excel文件流
* @param excelName Excel文件名
* @param sheetName sheet页名称。不输入则默认取第一个sheet
* @return
*/
public static List> getSheetDataWithTitle(InputStream inputStream, String excelName, String sheetName) throws Exception {
Workbook workbook = ExcelBaseOperate.getWorkbook(inputStream, excelName);
//没有输入sheetname,则默认第一个sheet
if (StringUtils.isBlank(sheetName)) {
sheetName = workbook.getSheetAt(0).getSheetName();
}
List> sheetData = parseSheet(workbook, sheetName, 0, workbook.getSheet(sheetName).getPhysicalNumberOfRows());
return sheetData;
}
/**
* 解析sheet页数据
*
* @param wb Excel文件
* @param sheetName sheet页名称
* @param startIndex 解析的起始row,从0开始,包含此row
* @param endIndex 解析的终止row,从0开始,包含此row
* @return 第一层list:row;第二层list:cell
*/
private static List> parseSheet(Workbook wb, String sheetName, int startIndex, int endIndex) throws Exception {
String message = null;
Sheet sheet = wb.getSheet(sheetName);
if(null == sheet) {
message = sheetName + ",此sheet页不存在";
throw new Exception(message);
}
int lastRowNum = sheet.getPhysicalNumberOfRows();
if(startIndex < 0 || endIndex > lastRowNum || startIndex > endIndex) {
message = "输入的解析row范围错误。startIndex:" + startIndex + ",endIndex:" + endIndex;
throw new Exception(message);
}
List> sheetData = new ArrayList<>();
int cellCount = -1;
//row list
for (int i = startIndex; i < endIndex; i++) {
Row row = sheet.getRow(i);
if(null == row) {
continue;
}
List rowData = new ArrayList<>();
cellCount = row.getLastCellNum();
//cell list
for(int j = 0; j < cellCount; j++) {
Cell cell = row.getCell(j);
if(null == cell) {
rowData.add(null);
continue;
}
rowData.add(getCellValue(cell));
}
sheetData.add(rowData);
}
return sheetData;
}
/**
* 获取cell值
*
* @param cell
* @return
*/
private static String getCellValue(Cell cell) {
CellType type = cell.getCellTypeEnum();
String value = null;
if(CellType.NUMERIC.equals(type)) {
if(DateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
value = sdf.format(date);
} else {
cell.setCellType(CellType.STRING);
value = String.valueOf(cell.getStringCellValue());
}
} else if(CellType.BOOLEAN.equals(type)) {
value = String.valueOf(cell.getBooleanCellValue());
} else if(CellType.BLANK.equals(type)) {
value = null;
} else {
value = String.valueOf(cell.getStringCellValue());
}
return value;
}
}
21、Excel写入操作
/**
* @Description:Excel读取操作
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 21:59:43
* @Version:1.0
*/
public class ExcelWrite {
private static final Logger logger = LoggerFactory.getLogger(ExcelWrite.class);
public static final String SUFFIX = "xlsx";
/**
* 导出Excel
*
* @param
* @return void
* @author zhangzhixiang
* @data 2018/09/10 13:59:43
*/
public static void exportExcel(HttpServletResponse response, List> rows, String fileName, String sheetName) {
Workbook workbook = createWb();
try(OutputStream out = response.getOutputStream()) {
Sheet sheet = workbook.createSheet(sheetName);
sheetAppendData(rows, sheet);
response.setContentType("application/ms-excel;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
workbook.write(out);
} catch(Exception e) {
logger.error("ExcelWrite--exportExcel throw Exception.fileName:{}", fileName, e);
}
}
/**
* 生成Excel文件流
*
* @param rows
* @param name
* @return java.io.ByteArrayOutputStream
* @author zhangzhixiang
* @date 2018/09/10 20:54:46
*/
public static ByteArrayOutputStream writeData(List> rows, String name) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Workbook workbook = createWb();
Sheet sheet= workbook.createSheet(name);
sheetAppendData(rows, sheet);
try {
workbook.write(out);
out.flush();
return out;
} catch(Exception e) {
logger.error("ExcelWrite-->writeData throw Exception.name:{}.", name, e);
return null;
}
}
/**
* sheet页填充数据
*
* @param rows
* @param sheet
* @return org.apache.poi.ss.usermodel.Sheet
* @author zhangzhixiang
* @date 2018/09/10 10:59:48
*/
public static Sheet sheetAppendData(List> rows, Sheet sheet) {
int lastRowNum = sheet.getPhysicalNumberOfRows();
if(null == rows || rows.size() == 0) {
return sheet;
}
Row row = null;
for (List rowData : rows) {
row = sheet.createRow(lastRowNum);
rowCreateData(rowData, row);
lastRowNum = lastRowNum + 1;
}
return sheet;
}
/**
* 生成row
*
* @param datas
* @param row
* @return org.apache.poi.ss.usermodel.Row
* @author zhangzhixiang
* @date 2018/09/10 20:35:46
*/
private static Row rowCreateData(List datas, Row row) {
Cell cell = null;
for(int i = 0; i < datas.size(); i++) {
cell = row.createCell(i);
cell.setCellType(CellType.STRING);
cell.setCellValue(datas.get(i));
}
return row;
}
/**
* 创建workbook
*
* @param
* @return org.apache.poi.ss.usermodel.Workbook
* @author zhangzhixiang
* @date 2018/09/10 20:35:42
*/
public static Workbook createWb() {
Workbook wb = null;
if(SimpleConst.EXCEL_EXT.equals(SUFFIX)) {
wb = new XSSFWorkbook();
} else {
wb = new HSSFWorkbook();
}
return wb;
}
}
22、常量类定义
/**
* @Description:简单常亮定义
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 11:34:56
* @Version:1.0
*/
public class SimpleConsts {
public static final String EXCEL_EXT = "xlsx";
}
23、ExcelOperateBO
/**
* @Description:Excel操作结果
* @Author:zhangzhixiang
* @CreateDate:2018/09/05 19:54:32
* @Version:1.0
*/
@Data
public class ExcelOperateBO {
/**
* 文件是否成功
*/
private Boolean fileOK;
/**
* 失败原因
*/
private String message;
/**
* 总行数
*/
private Integer totalNum;
/**
* 成功行数
*/
private Integer successNum;
/**
* 失败行数
*/
private Integer failNum;
}
24、controller层
/**
* @Description:公共服务接口-controller
* @Author:zhangzhixiang
* @CreateDate:2018/08/31 11:34:56
* @Version:1.0
*/
@RestController
@RequestMapping("/api/ops/common")
public class CommonController extends ExceptionHandlerAdvice {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private ExcelOperateService excelOperateService;
@RequestMapping(value = "/excelImport", method = RequestMethod.POST)
public ResponseResult excelImport(@RequestBody ExcelImportBO excelImportBO) throw Exception {
Boolean flag = paramCheckModule(excelImportBO.getModule());
if(!flag) {
return new ResponseResult().setSuccess(false).setMessage(ResultCode.ERROR_PARAM_CHECK.getMessage()).setCode(ResultCode.ERROR_PARAM_CHECK.getCode());
}
ExcelOperateResultBO data = excelOperateService.excelImport(excelImportBO.getCode());
return new ResponseResult().setSuccess(true).setData(data).setMessage(ResultCode.SUCCESS.getMessage);
}
@RequestMapping(value = "/excelExport", method = RequestMethod.GET)
public void excelExport(@RequestBody List> rows, String fileName, String sheetName, HttpServletResponse response) throw Exception {
excelOperateService.excelExport(response, rows, fileName, sheetName);
}
private boolean paramCheckModule(String module) throws Exception {
ExcelTypeEnum type = ExcelTypeEnum.containKey(module);
if(null == type) {
logger.error("********************No specified module was found.module:{}**********************", module);
return false;
}
return true;
}
}
全篇文章完全纯手打,如果觉得对您有帮助,记得加关注给好评哟~~