前提:
在<Java导出Excel> 1.0 Java实现Excel动态模板导出 的基础上,我们做动态模板数据的导入!
枚举类:
public enum ErrorCodeEnum {
NULL_PARAM(900, "参数不能为空"),
DUPLICATE_USER(9011, "用户已存在"),
DOWN_TEMPLATE_01(500,"服务异常,模板下载失败!"),
SERVICE_EXCEPTION(500,"服务异常"),
DOWN_POSITION_CHECKLIST_01(400,"上传文件不能为空");
private final int code;
private final String description;
ErrorCodeEnum(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
}
Controller层:
/**
* 导入:表单数据
* 权限-管理员
*
* @param multipartFile
* @return
*/
@PostMapping(value = "/uploadListData")
@AuthInterceptor("mag:getUpload:uploadListData") // 资源项
public Result uploadListData(HttpServletRequest request, @RequestParam("file") MultipartFile multipartFile) {
try {
if (multipartFile.isEmpty()) {
// DOWN_POSITION_CHECKLIST_01(400,"上传文件不能为空");
return CommonUtil.getErrorInfo(ErrorCodeEnum.DOWN_POSITION_CHECKLIST_01);
}
return heimaListService.uploadListData(request, multipartFile);
} catch (Exception e) {
log.error("=== uploadListDatais error===:" + e.getMessage(), e);
// SERVICE_EXCEPTION(500,"服务异常"),
return CommonUtil.getErrorInfo(ErrorCodeEnum.SERVICE_EXCEPTION);
}
}
service接口层:
Result uploadListData(HttpServletRequest request , MultipartFile multipartFile) throws Exception;
serviceImpl实现层:
/*
*导入:表单数据
*
*/
@Override
public synchronized Result uploadListData(HttpServletRequest request, MultipartFile multipartFile) throws Exception {
/*
* getHeaderss_1 为导出的模板:
* 如果导出模板字段和导入模板字段一致,则可以使用导出的模板数据;
* 如果导出模板字段和导入模板字段不一致,则需要对getHeaderss_1 的数据进行调整(具体根据业务调整);
* 如:导出数据模板里面有序号这个字段,但是导出模板和导入数据模板不需要这个字段,则自行调整
*/
List<Map<String, Object>> headers = getHeaderss_1();
Result result = CommonUtil.checkExcel(multipartFile, headers);
if (result != null) {
return result;
}
String[][] data = CommonUtil.getExcelData(multipartFile);
for (int i = 1; i < data.length; i++) {
if (data[0].length != headers.size()
|| data[i].length != headers.size()) {
return Result.failure("上传清单模板与系统不一致,请重新下载模板!");
}
}
// 插入数据库并返回结果
return insertList(data, request);
}
/*
* 数据入库
*
*/
private Result insertList(String[][] data, HttpServletRequest request) throws Exception {
List<Map<String, Object>> positons = CommonUtil.excelCellToSqlTypes(data, getHeaderss_1());
List<Map<String, Object>> oldPositons = CommonUtil.excelCellToSqlTypes(data, getHeaderss_1());
// 获取总数
int total = oldPositons .size();
// 批量入库
batchInsertList(positons,request);
return Result.success().result(null);
}
/**
* 批量入库
*
*/
private void batchInsertList(List<Map<String, Object>> xxListData, HttpServletRequest request) {
List<Map<String, Object>> ListNews = new ArrayList();
List<Map<String, Object>> queMap = heimaListMapper.getHeimaListAll(); // 查询所有数据
if(xxListData.size() > 0){
xxListData.remove(0); // 删除第一行字段提示;
// 该处for循环为一段业务逻辑,实际导入可根据业务调整;此处记录单据编号生成思路的代码
for (int i = 0; i < xxListData.size(); i++) {
//xxListData.remove(0); // 第一行元素为字段提示,需删除;
// 计算单据编号算法:
String waysOfProbleml = String.valueOf(xxListData.get(i).get("waysOfProbleml")); // 获取表格当前行数据,字段为:途径
String month = String.valueOf(xxListData.get(i).get("month")); // 获取表格当前行数据:月份
if(month.isEmpty() || month.equals("null")){
month = DateUtil.getCurrentDate().substring(0,7);
}else{
month = month.replace("年","-").replace("月",""); // 获取表格当前行数据:稽查月度 转换数据格式
}
xxListData.get(i).put("month",month);
List<Integer> integerList = new ArrayList<>(); // 创建新集合,用于存储:表格中当前行月度与数据库已有数据月度相等时候的单据编号;
String sqMonth = ""; // 获取数据库查询的当前月份
if(queMap.size() > 0){ // 循环数据库已有的数据,根据月度获取单据编号排序;
for (Map<String, Object> map : queMap) {
// 表格中当前行月度与数据库已有数据月度相等,获取数据库中所有数据的单号
if(month.equals(map.get("month"))){
sqMonth = String.valueOf(map.get("month"));
String qu = String.valueOf(map.get("numberNo"));
integerList.add(new Integer(Integer.parseInt(qu.substring(qu.length() - 8))));
}
}
}
Collections.sort(integerList); // 根据单据编号排序;
String queNo = "";
if(integerList.size() > 0){
queNo = String.valueOf(integerList.get(integerList.size()-1)); // 获取与当前表格数据月份匹配且单据编号最大的编号;
}
String numberNo = "";
// 表单中第一条数据:单据编号的计算需要根据数据库中存在的数据计算;
if(queMap.size() < 1){
//表中第一次插入数据的时候,从0001递增;
numberNo = "0001";
}else{
//如果输入的月份与数据库查询的月份相等,则为同月;递增;否则重置清零递增;
//if(xxListData.get(i).get("month").equals(sqMonth)){
if(month.equals(sqMonth)){
numberNo = Integer.toString(Integer.parseInt(queNo.substring(queNo.length() - 4)) + 1);
}else{
numberNo = "0001";
}
}
if(waysOfProbleml.equals("员工自主申报")){
waysOfProbleml = "ESD"; // Employee self declaration 缩写:ESD
}
month = month.replace("-","").substring(2,6); // 获取表格当前行数据:月度
String result = CommonUtil.getId(waysOfProbleml + month,Integer.parseInt(numberNo));
xxListData.get(i).put("numberNo",result); // 新生成的单据编号添加到表格当前行数据中;
queMap.add(xxListData.get(i)); // 将新生成单据编号的数据每次都添加到数据库查询的数据中,当作历史数据,每次需重新根据月份匹配最大单据编号;
ListNews.add(xxListData.get(i)); // 将当前行数据添加新集合,用于数据批量插入;
}
}
if (ListNews.size() > 0) {
heimaListMapper.uploadListData(ListNews);
}
}
mapper接口层:
void uploadListData(List<Map<String, Object>> paramList);
mapper.xml层:
<!-- 表单数据批量入库 -->
<insert id="uploadListData" parameterType="java.util.List">
<foreach collection="list" item="question" index="index" separator=";">
INSERT IGNORE INTO bcg_question_list_form_data
<foreach collection="question.entrySet()" index="key" separator="," open="(" close=")">
${key}
</foreach>
VALUES
<foreach collection="question.entrySet()" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</foreach>
</insert>
Excel读取数据操作工具类:
package com.itheima.service.common.util;
import com.github.pagehelper.PageHelper;
import com.itheima.service.common.constant.Constants;
import com.itheima.service.common.entity.DeptInfo;
import com.itheima.service.exception.ErrorCodeEnum;
import com.isoftstone.ican.platform.common.tools.model.Result;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import static com.google.common.io.ByteStreams.copy;
public class CommonUtil {
// linux 下
public static final String XX_PATH = "listdata"+ File.separator;
// windows下
// public static final String XX_PATH = "listdata/";
/**
* 获取两个数组的不同元素
*
* @param t1
* @param t2
* @return
*/
public static <T> List<T> compare(T[] t1, T[] t2) {
//将t1数组转成list数组
List<T> list1 = Arrays.asList(t1);
for (int i = 0; i < list1.size(); i++) {
String header = list1.get(i).toString().replace("\n", "");
list1.set(i, (T) header);
}
//用来存放2个数组中不相同的元素
List<T> list2 = new ArrayList<T>();
for (T t : t2) {
if (!list1.contains(t)) {
list2.add(t);
}
}
return list2;
}
/**
* 获取错误信息
*
* @param DUPLICATE_USER
* @return
*/
public static Result getErrorInfo(ErrorCodeEnum DUPLICATE_USER) {
return Result.failure(DUPLICATE_USER.getCode(), DUPLICATE_USER.getDescription());
}
/**
* 获取模板表头信息
*
* @param headers
* @return
*/
public static List<List<String>> getTemplateHeaders(List<Map<String, Object>> headers) {
List<List<String>> cells = new ArrayList<List<String>>();
for (Map<String, Object> header : headers) {
List<String> headerList = new ArrayList<String>();
headerList.add(header.get("headerName").toString());
cells.add(headerList);
}
return cells;
}
/**
* 清单上传校验
*
* @param multipartFile
* @param templateHeaders
* @return
* @throws Exception
*/
public static Result checkExcel(MultipartFile multipartFile,
List<Map<String, Object>> templateHeaders) throws Exception {
String fileName = multipartFile.getOriginalFilename();
// 校验后缀
if (!"xls".equals(fileName.split("\\.")[1]) &&
!"xlsx".equals(fileName.split("\\.")[1])) {
return Result.failure("上传文件格式不正确,请检查");
}
String[][] data = getExcelData(multipartFile);
// 对excel表头校验
String[] dataArray = data[0];
// 查表表头信息
List<Object> tempHeader = templateHeaders.stream().map(
e -> e.get("headerName")).collect(Collectors.toList());
String[] headers = tempHeader.toArray(new String[tempHeader.size()]);
List<String> list = CommonUtil.compare(dataArray, headers);
if (list != null && list.size() > 0) {
return Result.failure(ExcelUtil.getStringMessage(list).toString());
}
return null;
}
/**
* 读取excel数据
*
* @param multipartFile
* @return
* @throws Exception
*/
public static String[][] getExcelData(MultipartFile multipartFile) throws Exception {
String[][] data;
String fileName = multipartFile.getOriginalFilename();
InputStream inputStream = multipartFile.getInputStream();
String flag = fileName.substring(fileName.lastIndexOf("."));
if (Constants.EXCEL_XLSX_VERSION.equals(flag)) {
data = ExcelUtil.getXlsxData(inputStream, 0);
} else {
data = ExcelUtil.getXlsData(inputStream, 0);
}
return data;
}
/**
* excel表头转换成sql中的字段
*
* @param data
* @param headers
* @return
*/
public static List<Map<String, String>> excelCellToSqlType(
String[][] data, List<Map<String, Object>> headers) {
List<Map<String, String>> dataPositons = new ArrayList<Map<String, String>>();
for (int i = 1; i < data.length; i++) {
Map<String, String> map = new HashMap<String, String>();
for (int columnNo = 0; columnNo < data[i].length; columnNo++) {
String columnName = data[0][columnNo].replace("\n", "");
String columnValue = data[i][columnNo];
map.put(columnName, columnValue);
}
dataPositons.add(map);
}
dataPositons = changeColumnName(dataPositons, headers);
return dataPositons;
}
// excel表头转换成sql中的字段2
public static List<Map<String, Object>> excelCellToSqlTypes(
String[][] data, List<Map<String, Object>> headers) {
List<Map<String, Object>> dataPositons = new ArrayList<Map<String, Object>>();
for (int i = 1; i < data.length; i++) {
Map<String, Object> map = new HashMap<String, Object>();
for (int columnNo = 0; columnNo < data[i].length; columnNo++) {
String columnName = data[0][columnNo].replace("\n", "");
String columnValue = data[i][columnNo];
map.put(columnName, columnValue);
}
dataPositons.add(map);
}
dataPositons = changeColumnNames(dataPositons, headers);
return dataPositons;
}
/**
* 属性名与属性转换
*
* @param dataPositons
* @param headers
* @return
*/
private static List<Map<String, String>> changeColumnName(
List<Map<String, String>> dataPositons,
List<Map<String, Object>> headers) {
List<Map<String, String>> dataPositonsNews = new ArrayList<Map<String, String>>();
for (Map<String, String> xxPostion : dataPositons) {
Map<String, String> keyPositionNew = new HashMap<String, String>();
for (Map<String, Object> header : headers) {
if (!StringUtils.isEmpty(xxPostion.get(header.get("headerName")))) {
keyPositionNew.put(header.get("headerField").toString(),
xxPostion.get(header.get("headerName")));
}
}
dataPositonsNews.add(keyPositionNew);
}
return dataPositonsNews;
}
// 属性名与属性转换2
private static List<Map<String, Object>> changeColumnNames(
List<Map<String, Object>> dataPositons,
List<Map<String, Object>> headers) {
List<Map<String, Object>> dataPositonsNews = new ArrayList<Map<String, Object>>();
for (Map<String, Object> xxPostion : dataPositons) {
Map<String, Object> keyPositionNew = new HashMap<String, Object>();
for (Map<String, Object> header : headers) {
if (!StringUtils.isEmpty(String.valueOf(xxPostion.get(header.get("headerName"))))) {
keyPositionNew.put(header.get("headerField").toString(),
xxPostion.get(header.get("headerName")));
}
}
dataPositonsNews.add(keyPositionNew);
}
return dataPositonsNews;
}
public static String getObjectKey(String filePath) {
return XX_PATH + filePath;
}
public static byte[] inputStreamToByte(InputStream input) throws Exception {
ByteArrayOutputStream output = new ByteArrayOutputStream();
copy(input, output);
return output.toByteArray();
}
public static void getPageHelper(Map<String, Object> params) {
if (params.get("pageNum") != null) {
PageHelper.startPage(Integer.parseInt(String.valueOf(params.get("pageNum"))),
Integer.parseInt(String.valueOf(params.get("pageSize"))));
}
}
/**
* 由年月日时分秒毫秒 生成流水号
*
* @return
*/
public static String getSerialNumber(String strFlag) {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String dateString = formatter.format(currentTime);
return strFlag + dateString;
}
/*
* 自定义:自增流水号工具类
*
* @param prefix
* @param id
*/
private static final Integer ONE = 1;
private static final Integer TWO = 2;
private static final Integer THREE = 3;
public static String getId(String prefix, Integer id){
//判断位数
String s = id + "";
int count = s.length();
String producerNum = prefix;
if (ONE == count){
producerNum += "000"+ String.valueOf(id);
}else if (TWO == count){
producerNum += "00"+ String.valueOf(id);
}else if (THREE == count){
producerNum += "0" + String.valueOf(id);
}else {
producerNum += String.valueOf(id);
}
return producerNum;
}
}
ExcelUtil 工具类查找:
<Java导出Excel> 1.0 Java实现Excel动态模板导出