POI 导入导出Excel 下拉列表多级联动

 参考:https://blog.csdn.net/m0_37956938/article/details/78084503

 前端代码:

<table class="add_table" cellpadding="0" cellspacing="0">
<tr class="main_table_tr">
<td class="td_title" style="width: 25%;"><p class="add_table_p2"> 第一步:</p></td>
<td>
<p style="float: left; margin-left: 10px; font-size: 14px;"> 下载 </p>
<a href="<%=path %>/api/busi/daily/data/downloadTemplate?emId= '${emId}'" style="float: left; margin-left: 11px; font-size: 14px; width: auto;" onclick="downloadExcel(this);"> 日常库内容模板 </a>
</td>
</tr>
<tr class="main_table_tr">
<td class="td_title" style="width: 25%;"><p class="add_table_p2"> 第二步:</p></td>
<td>
<input type="file" id="file" name="file" style="display: none"/>
<input type="text" id="filename" style="border: none; width: auto; display:none" />
<input type="button" onclick="getExcel()" value="选择文件" />
</td>
</tr>
</table>
 
// 选择excel并上传
function getExcel() {
$("#file").click();
$('#file').change(function (e) {
var fileName = e.target.files[0];//js 获取文件对象
if (fileName !== undefined) {
var file_typename = fileName.name.substring(fileName.name.lastIndexOf('.'));
if (file_typename === '.xlsx' || file_typename === '.xls') {
$("#filename").val(fileName.name);
uploadExcel(fileName);
} else {
layer.alert("请选择正确的文件类型!");
}
} else {
layer.alert("请选择正确的文件!");
}
});
}

// 上传
function uploadExcel(fileName) {
var form = new FormData(); // FormData 对象
form.append("file", fileName); // 文件对象
form.append("dailyId", '${id}');
form.append("emId", '${emId}');
$.ajax({
url: '<%=path %>/api/busi/daily/data/uploadExcel', //url地址
type: 'POST', //上传方式
data: form, // 上传formdata封装的数据
dataType: 'JSON',
cache: false, // 不缓存
processData: false, // jQuery不要去处理发送的数据
contentType: false, // jQuery不要去设置Content-Type请求头
success:function (data) { //成功回调
if (data.success) {
layer.alert("导入成功", function () {
window.parent.location.reload();
});
} else {
$("#errorTip").find("span").html(data.message);
}
},
error:function (data) { //失败回调
layer.alert("导入失败,请稍后重试!");
}
});
}
// 下载Excel模板
function downloadExcel(obj) {
var baseUrl = "具体的下载路径";
$(obj).attr("href", baseUrl);
$(obj)[0].click();
}

后端代码:

/**
* 下载 Excel模板
* @param request
* @param response
* @throws IOException
*/
@RequestMapping("/downloadTemplate")
public void downloadTemplate(String emId, HttpServletRequest request, HttpServletResponse response) throws IOException {
Workbook workbook = new XSSFWorkbook();
String fileName = "template_daily_library"+ ".xlsx"; // Excel文件名
OutputStream os = null;
workbook = buildExcelDocument(emId);
response.reset();// 清空输出流
// web浏览通过MIME类型判断文件是excel类型
response.setHeader("Content-type",
"application/vnd.ms-excel;charset=UTF-8");

// 对文件名进行处理。防止文件名乱码
// Content-disposition属性设置成以附件方式进行下载
response.addHeader("Content-Disposition", "attachment;filename="
+ new String(fileName.getBytes("gb2312"), "ISO8859-1"));
os = response.getOutputStream();// 取得输出流
workbook.write(os);
}

/**
* 创建Excel
* @param emId
* @return
*/
public XSSFWorkbook buildExcelDocument(String emId) {
// 创建一个excel
XSSFWorkbook workbook = new XSSFWorkbook();
// 样式一
XSSFFont font1 = workbook.createFont();
font1.setFontHeightInPoints((short) 12); // 设置字体的大小
font1.setFontName("宋体"); // 设置字体的样式,如:宋体、微软雅黑等
font1.setItalic(false); // 斜体true为斜体

// 样式二
XSSFFont font2 = workbook.createFont();
font2.setFontHeightInPoints((short) 12); // 设置字体的大小
font2.setFontName("宋体"); // 设置字体的样式,如:宋体、微软雅黑等
font2.setColor(Font.COLOR_RED); // 红色显示必填
font2.setItalic(false); // 斜体true为斜体

XSSFCellStyle style1 = workbook.createCellStyle(); // 获取样式1
XSSFCellStyle style2 = workbook.createCellStyle(); // 获取样式2


// 查询所有的一级部件二级部件名称
List<String> part1List = new ArrayList<String>(); // 一级部件列表
List<String> strList6 = new ArrayList<String>(); // 周期单位列表
strList6.add("年");
strList6.add("月");
strList6.add("周");
strList6.add("日");

List<String> strList7 = new ArrayList<String>(); // 作业异常返回类型列表
strList7.add("预警");

// 整理数据,放入一个Map中,mapkey存放父地点,value 存放该地点下的子区域
Map<String, List<String>> map = new HashMap<String, List<String>>();

// 一级部件
Map<String, Object> params1 = new HashMap<String, Object>();
Query query1 = new Query(params1);
query1.put("deleteFlag", DelStatus.status_Y); // 默认查询未删除
query1.put("parentId", "is null");
query1.put("emId", emId);
List<DevicePartBean> parts1 = devicePartBiz.selectByQuery(query1); // 一级部件

// 二级部件
Map<String, Object> params2 = new HashMap<String, Object>();
Query query2 = new Query(params2);
query2.put("deleteFlag", DelStatus.status_Y); // 默认查询未删除

List<DevicePartBean> parts2 = null;
for (DevicePartBean p1 : parts1) {
String partId1 = p1.getId();
String partName1 = p1.getPartName();
part1List.add(partName1);
query2.put("emId", emId);
query2.put("parentId", partId1);
parts2 = devicePartBiz.selectByQuery(query2); // 二级部件
List<String> part2List = new ArrayList<String>(); // 二级部件列表
for (DevicePartBean part2 : parts2) {
String partName2 = part2.getPartName();
part2List.add(partName2);
}
map.put(partName1, part2List);
}

// 创建一个专门用来存放一级部件二级部件的隐藏sheet页
Sheet hideSheet = workbook.createSheet("site_sheet");
workbook.setSheetHidden(workbook.getSheetIndex("site_sheet"), true);

int rowId = 0;
// 设置第一行,存一级部件的信息
Row part1Row = hideSheet.createRow(rowId++);
part1Row.createCell(0).setCellValue("一级部件列表");
for (int i = 0; i < part1List.size(); i++) {
Cell part1Cell = part1Row.createCell(i + 1);
part1Cell.setCellValue(part1List.get(i));
}
// 将具体的数据写入到每一行中,行开头为父级区域,后面是子区域
Iterator<String> keyIterator = map.keySet().iterator();
while (keyIterator.hasNext()) {
String key = keyIterator.next();
List<String> son = map.get(key);

Row row = hideSheet.createRow(rowId++);
row.createCell(0).setCellValue(key);
for (int i = 0; i < son.size(); i++) {
Cell cell = row.createCell(i + 1);
cell.setCellValue(son.get(i));
}

// 添加名称管理器
String range = getRange(1, rowId, son.size());
Name name = workbook.createName();
name.setNameName(key);
String formula = "site_sheet!" + range;
name.setRefersToFormula(formula);
}

XSSFSheet sheet1 = workbook.createSheet("sheet1");
Row row0 = sheet1.createRow(0);

String[] headers = new String[] { "一级部件", "二级部件", "*作业内容", "*作业SOP", "*作业工具方法", "*作业周期", "*周期单位", "*作业异常返回类型", "*异常处理方案" };
for (int i = 0; i < headers.length; i++) {
sheet1.setColumnWidth(i, 5000); //设置每列的列宽
Cell cell = row0.createCell(i, Cell.CELL_TYPE_STRING);
if (i==0 || i==1) {
style1.setFont(font1);// 选择需要用到的字体格式
cell.setCellStyle(style1);
} else {
style2.setFont(font2);// 选择需要用到的字体格式
cell.setCellStyle(style2);
}

cell.setCellValue(headers[i]);
}

XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet1);
// 一级部件规则
DataValidationConstraint partConstraint = dvHelper.createExplicitListConstraint(part1List.toArray(new String[] {}));
// 四个参数分别是:起始行、终止行、起始列、终止列
CellRangeAddressList partRangeAddressList = new CellRangeAddressList(1, 200, 0, 0);
DataValidation partDataValidation = dvHelper.createValidation(partConstraint, partRangeAddressList);
//验证
partDataValidation.createErrorBox("error", "请选择正确的一级部件");
partDataValidation.setShowErrorBox(true);
partDataValidation.setSuppressDropDownArrow(true);
sheet1.addValidationData(partDataValidation);

// 周期单位规则
DataValidationConstraint cycleUnitConstraint = dvHelper.createExplicitListConstraint(strList6.toArray(new String[] {}));
// 四个参数分别是:起始行、终止行、起始列、终止列
CellRangeAddressList cycleUnitRangeAddressList = new CellRangeAddressList(1, 200, 6, 6);
DataValidation cycleUnitDataValidation = dvHelper.createValidation(cycleUnitConstraint, cycleUnitRangeAddressList);
//验证
cycleUnitDataValidation.createErrorBox("error", "请选择正确的周期单位");
cycleUnitDataValidation.setShowErrorBox(true);
cycleUnitDataValidation.setSuppressDropDownArrow(true);
sheet1.addValidationData(cycleUnitDataValidation);

// 作业异常返回类型规则
DataValidationConstraint exceptConstraint = dvHelper.createExplicitListConstraint(strList7.toArray(new String[] {}));
// 四个参数分别是:起始行、终止行、起始列、终止列
CellRangeAddressList exceptRangeAddressList = new CellRangeAddressList(1, 200, 7, 7);
DataValidation exceptDataValidation = dvHelper.createValidation(exceptConstraint, exceptRangeAddressList);
//验证
exceptDataValidation.createErrorBox("error", "请选择正确的作业异常返回类型");
exceptDataValidation.setShowErrorBox(true);
exceptDataValidation.setSuppressDropDownArrow(true);
sheet1.addValidationData(exceptDataValidation);


//对前20行设置有效性
for(int i = 2;i < 200;i++){
setDataValidation("A" ,sheet1,i,2);
}

return workbook;
}

/**
* 设置有效性
* @param offset 主影响单元格所在列,即此单元格由哪个单元格影响联动
* @param sheet
* @param rowNum 行数
* @param colNum 列数
*/
public static void setDataValidation(String offset,XSSFSheet sheet, int rowNum,int colNum) {
XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet);
DataValidation data_validation_list;
data_validation_list = getDataValidationByFormula(
"INDIRECT($" + offset + (rowNum) + ")", rowNum, colNum,dvHelper);
sheet.addValidationData(data_validation_list);
}

/**
* 加载下拉列表内容
* @param formulaString
* @param naturalRowIndex
* @param naturalColumnIndex
* @param dvHelper
* @return
*/
private static DataValidation getDataValidationByFormula(
String formulaString, int naturalRowIndex, int naturalColumnIndex,XSSFDataValidationHelper dvHelper) {
// 加载下拉列表内容
// 举例:若formulaString = "INDIRECT($A$2)" 表示规则数据会从名称管理器中获取key与单元格 A2 值相同的数据,
XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint) dvHelper.createFormulaListConstraint(formulaString);
// 设置数据有效性加载在哪个单元格上。
// 四个参数分别是:起始行、终止行、起始列、终止列
int firstRow = naturalRowIndex -1;
int lastRow = naturalRowIndex - 1;
int firstCol = naturalColumnIndex - 1;
int lastCol = naturalColumnIndex - 1;
CellRangeAddressList regions = new CellRangeAddressList(firstRow,
lastRow, firstCol, lastCol);
// 数据有效性对象
// 绑定
XSSFDataValidation data_validation_list = (XSSFDataValidation) dvHelper.createValidation(dvConstraint, regions);
data_validation_list.setEmptyCellAllowed(false);
if (data_validation_list instanceof XSSFDataValidation) {
data_validation_list.setSuppressDropDownArrow(true);
data_validation_list.setShowErrorBox(true);
} else {
data_validation_list.setSuppressDropDownArrow(false);
}
// 设置输入信息提示信息
data_validation_list.createPromptBox("下拉选择提示", "请使用下拉方式选择合适的值!");
// 设置输入错误提示信息
//data_validation_list.createErrorBox("选择错误提示", "你输入的值未在备选列表中,请下拉选择合适的值!");
return data_validation_list;
}

/**
*
* @param offset 偏移量,如果给0,表示从A列开始,1,就是从B列
* @param rowId 第几行
* @param colCount 一共多少列
* @return 如果给入参 1,1,10. 表示从B1-K1。最终返回 $B$1:$K$1
*
* @author wb 2020年1月04日 15:00:00
*/
public static String getRange(int offset, int rowId, int colCount) {
char start = (char)('A' + offset);
if (colCount <= 25) {
char end = (char)(start + colCount - 1);
return "$" + start + "$" + rowId + ":$" + end + "$" + rowId;
} else {
char endPrefix = 'A';
char endSuffix = 'A';
if ((colCount - 25) / 26 == 0 || colCount == 51) {// 26-51之间,包括边界(仅两次字母表计算)
if ((colCount - 25) % 26 == 0) {// 边界值
endSuffix = (char)('A' + 25);
} else {
endSuffix = (char)('A' + (colCount - 25) % 26 - 1);
}
} else {// 51以上
if ((colCount - 25) % 26 == 0) {
endSuffix = (char)('A' + 25);
endPrefix = (char)(endPrefix + (colCount - 25) / 26 - 1);
} else {
endSuffix = (char)('A' + (colCount - 25) % 26 - 1);
endPrefix = (char)(endPrefix + (colCount - 25) / 26);
}
}
return "$" + start + "$" + rowId + ":$" + endPrefix + endSuffix + "$" + rowId;
}
}


/**
* 上传Excel
*/
@RequestMapping(value = "/uploadExcel", method = RequestMethod.POST)
@ResponseBody
public String uploadExcel (@RequestParam("dailyId") String dailyId, @RequestParam("emId") String emId, @RequestParam(value="file", required = false) MultipartFile file) {
boolean flag = false;
try {
List<DailyLibraryDataBean> list = ExcelUtils.readExcel("", DailyLibraryDataBean.class, file);
String msg = "";
for (int i=1;i<=list.size();i++) {
DailyLibraryDataBean data = list.get(i-1);
data.setDailyId(dailyId);
String ms = "";
DevicePartBean bean = new DevicePartBean();
if (!"".equals(data.getPartId()) && data.getPartId() != null) {

bean = devicePartBiz.fetch(Cnd.where("part_name", "=", data.getPartId()).and("parent_id", "is", null).and("em_id", "=", emId));

if (bean != null) {
data.setPartId(bean.getId());

if (!"".equals(data.getPartId2()) && data.getPartId2() != null) {
DevicePartBean bean2 = devicePartBiz.fetch(Cnd.where("part_name", "=", data.getPartId2()).and("parent_id", "=", bean.getId()).and("em_id", "=", emId));
if (bean2 != null) {
data.setPartId2(bean2.getId());
} else {
ms += "第" + i + "行设备型号查无此二级部件;";
}
} else {
data.setPartId2("");
}
} else {
ms += "第" + i + "行设备型号查无此一级部件;";
}
} else {
data.setPartId("");
}

if ("".equals(data.getDailyContent()) || data.getDailyContent() == null) {
ms += "第" + i + "行作业内容不能为空;";
}
if ("".equals(data.getDailySop()) || data.getDailySop() == null) {
ms += "第" + i + "行作业SOP不能为空;";
}
if ("".equals(data.getDailyTool()) || data.getDailyTool() == null) {
ms += "第" + i + "行作业工具方法不能为空;";
}
if ("".equals(data.getCycle()) || data.getCycle() == null) {
ms += "第" + i + "行作业周期不能为空;";
}
if ("".equals(data.getCycleUnit()) || data.getCycleUnit() == null) {
ms += "第" + i + "行周期单位不能为空;";
} else {
switch (data.getCycleUnit()) {
case "年" : data.setCycleUnit("cycle_unit_year");
break;

case "月" : data.setCycleUnit("cycle_unit_month");
break;

case "周" : data.setCycleUnit("cycle_unit_week");
break;

case "日" : data.setCycleUnit("cycle_unit_day");
break;

default: ms += "第" + i + "行查无此周期单位;";
break;
}
}
if ("".equals(data.getExcepResultType()) || data.getExcepResultType() == null) {
ms += "第" + i + "行作业异常返回类型不能为空;";
} else {
switch (data.getExcepResultType()) {
case "预警" : data.setExcepResultType("excep_result_alarm");
break;

default: ms += "第" + i + "行查无此作业异常返回类型;";
break;
}
}
if ("".equals(data.getExcepSchemes()) || data.getExcepSchemes() == null) {
ms += "第" + i + "行异常处理方案不能为空;";
}
if (StringUtils.isNotBlank(ms)) {
ms += "\r\n";
msg += ms;
continue;
}
dataBiz.insert(data);
}
if (StringUtils.isNotBlank(msg)) {
return Json.toJson(new ApiResult(msg));
}
flag = true;
} catch (Exception e) {
e.printStackTrace();
}

return Json.toJson(new ApiResult(flag, flag == true));
}


public class ExcelUtils {

private final static Logger log = LoggerFactory.getLogger(ExcelUtils.class);

private final static String EXCEL2003 = "xls";
private final static String EXCEL2007 = "xlsx";

public static <T> List<T> readExcel(String path, Class<T> cls,MultipartFile file){

String fileName = file.getOriginalFilename();
if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
log.error("上传文件格式不正确");
}
List<T> dataList = new ArrayList<>();
Workbook workbook = null;
try {
InputStream is = file.getInputStream();
if (fileName.endsWith(EXCEL2007)) {
// FileInputStream is = new FileInputStream(new File(path));
workbook = new XSSFWorkbook(is);
}
if (fileName.endsWith(EXCEL2003)) {
// FileInputStream is = new FileInputStream(new File(path));
workbook = new HSSFWorkbook(is);
}
if (workbook != null) {
//类映射 注解 value-->bean columns
Map<String, List<Field>> classMap = new HashMap<>();
List<Field> fields = Stream.of(cls.getDeclaredFields()).collect(Collectors.toList());
fields.forEach(
field -> {
ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
if (annotation != null) {
String value = annotation.value();
if (StringUtils.isBlank(value)) {
return;//return起到的作用和continue是相同的 语法
}
if (!classMap.containsKey(value)) {
classMap.put(value, new ArrayList<>());
}
field.setAccessible(true);
classMap.get(value).add(field);
}
}
);
//索引-->columns
Map<Integer, List<Field>> reflectionMap = new HashMap<>(16);
//默认读取第一个sheet
Sheet sheet = workbook.getSheetAt(0);

boolean firstRow = true;
for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
//首行 提取注解
if (firstRow) {
for (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {
Cell cell = row.getCell(j);
String cellValue = getCellValue(cell);
if (classMap.containsKey(cellValue)) {
reflectionMap.put(j, classMap.get(cellValue));
}
}
firstRow = false;
} else {
//忽略空白行
if (row == null) {
continue;
}
try {
T t = cls.newInstance();
//判断是否为空白行
boolean allBlank = true;
for (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {
if (reflectionMap.containsKey(j)) {
Cell cell = row.getCell(j);
String cellValue = getCellValue(cell);
if (StringUtils.isNotBlank(cellValue)) {
allBlank = false;
}
List<Field> fieldList = reflectionMap.get(j);
fieldList.forEach(
x -> {
try {
handleField(t, cellValue, x);
} catch (Exception e) {
log.error(String.format("reflect field:%s value:%s exception!", x.getName(), cellValue), e);
}
}
);
}
}
if (!allBlank) {
dataList.add(t);
} else {
log.warn(String.format("row:%s is blank ignore!", i));
}
} catch (Exception e) {
log.error(String.format("parse row:%s exception!", i), e);
}
}
}
}
} catch (Exception e) {
log.error(String.format("parse excel exception!"), e);
} finally {
if (workbook != null) {
try {
// workbook.close();
} catch (Exception e) {
log.error(String.format("parse excel exception!"), e);
}
}
}
return dataList;
}

private static <T> void handleField(T t, String value, Field field) throws Exception {
Class<?> type = field.getType();
if (type == null || type == void.class || StringUtils.isBlank(value)) {
return;
}
if (type == Object.class) {
field.set(t, value);
//数字类型
} else if (type.getSuperclass() == null || type.getSuperclass() == Number.class) {
if (type == int.class || type == Integer.class) {
field.set(t, NumberUtils.toInt(value));
} else if (type == long.class || type == Long.class) {
field.set(t, NumberUtils.toLong(value));
} else if (type == byte.class || type == Byte.class) {
field.set(t, NumberUtils.toByte(value));
} else if (type == short.class || type == Short.class) {
field.set(t, NumberUtils.toShort(value));
} else if (type == double.class || type == Double.class) {
field.set(t, NumberUtils.toDouble(value));
} else if (type == float.class || type == Float.class) {
field.set(t, NumberUtils.toFloat(value));
} else if (type == char.class || type == Character.class) {
field.set(t, CharUtils.toChar(value));
} else if (type == boolean.class) {
field.set(t, BooleanUtils.toBoolean(value));
} else if (type == BigDecimal.class) {
field.set(t, new BigDecimal(value));
}
} else if (type == Boolean.class) {
field.set(t, BooleanUtils.toBoolean(value));
} else if (type == Date.class) {
//
field.set(t, value);
} else if (type == String.class) {
field.set(t, value);
} else {
Constructor<?> constructor = type.getConstructor(String.class);
field.set(t, constructor.newInstance(value));
}
}

private static String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
if (HSSFDateUtil.isCellDateFormatted(cell)) {
return HSSFDateUtil.getJavaDate(cell.getNumericCellValue()).toString();
} else {
return new BigDecimal(cell.getNumericCellValue()).toString();
}
} else if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
return StringUtils.trimToEmpty(cell.getStringCellValue());
} else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
return StringUtils.trimToEmpty(cell.getCellFormula());
} else if (cell.getCellType() == Cell.CELL_TYPE_BLANK) {
return "";
} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
return String.valueOf(cell.getBooleanCellValue());
} else if (cell.getCellType() == Cell.CELL_TYPE_ERROR) {
return "ERROR";
} else {
return cell.toString().trim();
}

}
}
 

猜你喜欢

转载自www.cnblogs.com/wzb0228/p/12196257.html