|
|
package com.dsideal.base.Util;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.jfinal.kit.Kv;
|
|
|
import com.jfinal.kit.PathKit;
|
|
|
import com.jfinal.kit.PropKit;
|
|
|
import com.jfinal.plugin.activerecord.Page;
|
|
|
import com.jfinal.plugin.activerecord.Record;
|
|
|
import com.jfinal.upload.UploadFile;
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
|
import org.apache.poi.hssf.usermodel.*;
|
|
|
import org.apache.poi.ss.usermodel.*;
|
|
|
import org.apache.poi.ss.util.CellRangeAddress;
|
|
|
import org.apache.poi.ss.util.CellRangeAddressList;
|
|
|
import org.apache.poi.ss.util.RegionUtil;
|
|
|
import org.apache.poi.xssf.usermodel.*;
|
|
|
|
|
|
import java.io.*;
|
|
|
import java.sql.ResultSetMetaData;
|
|
|
import java.util.*;
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
public class ExcelCommonUtil {
|
|
|
|
|
|
/**
|
|
|
* https://fireinwind.iteye.com/blog/2168655
|
|
|
* 功能:通用的导出excel功能
|
|
|
* 作者:黄海
|
|
|
* 时间:2018-12-12
|
|
|
*
|
|
|
* @param jo
|
|
|
*/
|
|
|
public static void export(List<Record> list, JSONObject jo, String fileName) {
|
|
|
Page<Record> _page = new Page<>();
|
|
|
_page.setList(list);
|
|
|
_page.setPageNumber(1);
|
|
|
_page.setPageSize(99999);
|
|
|
_page.setTotalPage(1);
|
|
|
_page.setTotalRow(list.size());
|
|
|
export(_page, jo, fileName);
|
|
|
}
|
|
|
|
|
|
public static void export(List<Record> list, JSONObject jo, String fileName, List<Integer> hiddenColumns) {
|
|
|
Page<Record> _page = new Page<>();
|
|
|
_page.setList(list);
|
|
|
_page.setPageNumber(1);
|
|
|
_page.setPageSize(99999);
|
|
|
_page.setTotalPage(1);
|
|
|
_page.setTotalRow(list.size());
|
|
|
export(_page, jo, fileName, hiddenColumns);
|
|
|
}
|
|
|
|
|
|
public static void export(Page<?> page, JSONObject jo, String fileName) {
|
|
|
export(page, jo, fileName, null);
|
|
|
}
|
|
|
|
|
|
public static void export(Page<?> page, JSONObject jo, String fileName, List<Integer> hiddenColumns) {
|
|
|
//标题
|
|
|
String title = jo.getString("title");
|
|
|
|
|
|
//是不是显示序号
|
|
|
String showNumber = jo.getString("showNumber");
|
|
|
|
|
|
//sheet名称
|
|
|
String sheetName = jo.getString("sheetName");
|
|
|
//标题高度
|
|
|
short titleHeight = (short) (jo.getInteger("titleHeight") * 20);
|
|
|
//每一行数据的高度
|
|
|
short rowHeight = (short) (jo.getInteger("rowHeight") * 20);
|
|
|
|
|
|
//列信息
|
|
|
JSONArray colInfo = jo.getJSONArray("colInfo");
|
|
|
if (showNumber != null) {
|
|
|
JSONObject addjo = new JSONObject();
|
|
|
addjo.put("show_column_name", "序号");
|
|
|
addjo.put("list_column_name", "Number");
|
|
|
addjo.put("width", 20);
|
|
|
colInfo.add(0, addjo);
|
|
|
List<Record> list = new ArrayList<>();
|
|
|
for (int i = 0; i < page.getList().size(); i++) {
|
|
|
Record record = (Record) page.getList().get(i);
|
|
|
record.set("Number", (i + 1));
|
|
|
list.add(record);
|
|
|
}
|
|
|
page = new Page(list, page.getPageNumber(), page.getPageSize(), page.getTotalPage(), page.getTotalRow());
|
|
|
}
|
|
|
|
|
|
HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
|
|
|
HSSFSheet hssfSheet = hssfWorkbook.createSheet(sheetName);
|
|
|
int count = 0;
|
|
|
HSSFRow row = hssfSheet.createRow(count++);
|
|
|
HSSFCell cell;
|
|
|
|
|
|
//设置标题字体
|
|
|
Font fontTitle = hssfWorkbook.createFont();
|
|
|
fontTitle.setFontHeightInPoints((short) 18); //字体大小
|
|
|
fontTitle.setFontName("黑体"); //字体
|
|
|
CellStyle cellStyleTitle = hssfWorkbook.createCellStyle();
|
|
|
cellStyleTitle.setFont(fontTitle);
|
|
|
cellStyleTitle.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
cellStyleTitle.setAlignment(HorizontalAlignment.CENTER);
|
|
|
cellStyleTitle.setFillForegroundColor(IndexedColors.LIME.getIndex());
|
|
|
cellStyleTitle.setWrapText(true);//设置自动换行
|
|
|
Cell cellTitle = row.createCell(0);
|
|
|
cellTitle.setCellStyle(cellStyleTitle);
|
|
|
cellTitle.setCellValue(title);// 设置标题内容
|
|
|
//合并前N列,写上标题
|
|
|
CellRangeAddress region = new CellRangeAddress(0, 0, 0, colInfo.size() - 1);// 下标从0开始 起始行号,终止行号, 起始列号,终止列号
|
|
|
//在sheet里增加合并单元格
|
|
|
hssfSheet.addMergedRegion(region);
|
|
|
//设置标题的高度
|
|
|
row.setHeight(titleHeight);
|
|
|
|
|
|
Font txtFont = hssfWorkbook.createFont();
|
|
|
txtFont.setFontHeightInPoints((short) 14); //字体大小
|
|
|
txtFont.setFontName("宋体"); //字体
|
|
|
txtFont.setBold(true);
|
|
|
CellStyle cellStyleTxt = hssfWorkbook.createCellStyle();
|
|
|
cellStyleTxt.setFont(txtFont);
|
|
|
cellStyleTxt.setAlignment(HorizontalAlignment.CENTER);
|
|
|
cellStyleTxt.setFillForegroundColor(IndexedColors.LIME.getIndex());
|
|
|
cellStyleTxt.setWrapText(true);//设置自动换行
|
|
|
cellStyleTxt.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
cellStyleTxt.setBorderBottom(BorderStyle.THIN); // 底部边框
|
|
|
cellStyleTxt.setBorderLeft(BorderStyle.THIN); // 左边边框
|
|
|
cellStyleTxt.setBorderRight(BorderStyle.THIN); // 右边边框
|
|
|
cellStyleTxt.setBorderTop(BorderStyle.THIN); // 上边边框
|
|
|
cellStyleTxt.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
|
|
cellStyleTxt.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
|
|
|
//写入表头
|
|
|
row = hssfSheet.createRow(count++);
|
|
|
for (int i = 0; i < colInfo.size(); i++) {
|
|
|
//创建传入进来的表头的个数
|
|
|
cell = row.createCell(i);
|
|
|
//表头的值就是传入进来的值
|
|
|
JSONObject jsonObject2 = colInfo.getJSONObject(i);
|
|
|
int width = jsonObject2.getInteger("width");
|
|
|
row.setHeight(rowHeight);
|
|
|
cell.setCellValue(jsonObject2.getString("show_column_name"));
|
|
|
cell.setCellStyle(cellStyleTxt);
|
|
|
//需要显示特殊颜色的话
|
|
|
if (jsonObject2.getBoolean("specialColor") != null) {
|
|
|
CellStyle style = hssfWorkbook.createCellStyle();
|
|
|
style.setFont(txtFont);
|
|
|
style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
style.setFillForegroundColor(IndexedColors.LIME.getIndex());
|
|
|
style.setWrapText(true);//设置自动换行
|
|
|
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
style.setBorderBottom(BorderStyle.THIN); // 底部边框
|
|
|
style.setBorderLeft(BorderStyle.THIN); // 左边边框
|
|
|
style.setBorderRight(BorderStyle.THIN); // 右边边框
|
|
|
style.setBorderTop(BorderStyle.THIN); // 上边边框
|
|
|
style.setFillForegroundColor(IndexedColors.AQUA.getIndex());
|
|
|
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
cell.setCellStyle(style);
|
|
|
}
|
|
|
//调转宽度
|
|
|
hssfSheet.setColumnWidth(i, 256 * width + 184);
|
|
|
}
|
|
|
//正文与表头不是一个颜色
|
|
|
txtFont = hssfWorkbook.createFont();
|
|
|
txtFont.setFontHeightInPoints((short) 14); //字体大小
|
|
|
txtFont.setFontName("宋体"); //字体
|
|
|
cellStyleTxt = hssfWorkbook.createCellStyle();
|
|
|
cellStyleTxt.setFont(txtFont);
|
|
|
cellStyleTxt.setAlignment(HorizontalAlignment.CENTER);
|
|
|
cellStyleTxt.setFillForegroundColor(IndexedColors.LIME.getIndex());
|
|
|
cellStyleTxt.setWrapText(true);//设置自动换行
|
|
|
cellStyleTxt.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
cellStyleTxt.setBorderBottom(BorderStyle.THIN); // 底部边框
|
|
|
cellStyleTxt.setBorderLeft(BorderStyle.THIN); // 左边边框
|
|
|
cellStyleTxt.setBorderRight(BorderStyle.THIN); // 右边边框
|
|
|
cellStyleTxt.setBorderTop(BorderStyle.THIN); // 上边边框
|
|
|
//导出数据
|
|
|
for (int i = 0; i < page.getList().size(); i++) {
|
|
|
row = hssfSheet.createRow(count++);
|
|
|
Record record = (Record) page.getList().get(i);
|
|
|
for (int j = 0; j < colInfo.size(); j++) {
|
|
|
JSONObject jsonObject2 = colInfo.getJSONObject(j);
|
|
|
cell = row.createCell(j);
|
|
|
cell.setCellStyle(cellStyleTxt);
|
|
|
String v = record.getStr(jsonObject2.getString("list_column_name"));
|
|
|
if (jsonObject2.getBoolean("booleanConvert") != null) {
|
|
|
if (v.equals("1")) {
|
|
|
v = "是";
|
|
|
} else {
|
|
|
v = "否";
|
|
|
}
|
|
|
}
|
|
|
if (jsonObject2.getString("nullDefault") != null) {
|
|
|
if (v == null || v.length() == 0) {
|
|
|
v = jsonObject2.getString("nullDefault");
|
|
|
}
|
|
|
}
|
|
|
cell.setCellValue(v);
|
|
|
row.setHeight(rowHeight);
|
|
|
}
|
|
|
}
|
|
|
//处理隐藏列
|
|
|
if (null != hiddenColumns && hiddenColumns.size() > 0) {
|
|
|
for (Integer hiddenColumn : hiddenColumns) {
|
|
|
hssfSheet.setColumnHidden(hiddenColumn, true);
|
|
|
}
|
|
|
}
|
|
|
//生成文件
|
|
|
File file = new File(fileName);
|
|
|
try {
|
|
|
FileOutputStream fileOutputStreane = new FileOutputStream(file);
|
|
|
hssfWorkbook.write(fileOutputStreane);
|
|
|
fileOutputStreane.flush();
|
|
|
fileOutputStreane.close();
|
|
|
} catch (FileNotFoundException e) {
|
|
|
e.printStackTrace();
|
|
|
} catch (IOException e) {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:检查是不是合法的xls文件
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-01-03
|
|
|
*
|
|
|
* @return
|
|
|
* @throws FileNotFoundException
|
|
|
*/
|
|
|
public static Workbook getWorkbook(FileInputStream in) throws IOException {
|
|
|
|
|
|
//尝试一下是不是有效的xls文件
|
|
|
Workbook wb = null;
|
|
|
boolean isValidExcel = false;
|
|
|
try {
|
|
|
wb = new HSSFWorkbook(in);
|
|
|
isValidExcel = true;
|
|
|
} finally {
|
|
|
if (!isValidExcel && wb != null) {
|
|
|
wb.close();
|
|
|
|
|
|
return null;
|
|
|
}
|
|
|
return wb;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:添加一级的下拉框校验
|
|
|
* 作者:黄海
|
|
|
* 时间:2020-05-09
|
|
|
*
|
|
|
* @param excelFile
|
|
|
* @param sheetName
|
|
|
* @param col
|
|
|
* @param subjects
|
|
|
* @throws IOException
|
|
|
*/
|
|
|
public static void addValidation(String excelFile, String sheetName, int col, String[] subjects) throws IOException {
|
|
|
FileInputStream fis = new FileInputStream(excelFile);
|
|
|
HSSFWorkbook workbook = new HSSFWorkbook(fis);
|
|
|
HSSFSheet sheet = workbook.getSheet(sheetName);
|
|
|
DataValidationHelper helper = sheet.getDataValidationHelper();
|
|
|
DataValidationConstraint constraint = helper.createExplicitListConstraint(subjects);
|
|
|
CellRangeAddressList addressList;
|
|
|
DataValidation dataValidation;
|
|
|
//产生限制条件
|
|
|
for (int i = 1; i < sheet.getLastRowNum(); i++) {
|
|
|
addressList = new CellRangeAddressList(i, i, col, col);
|
|
|
dataValidation = helper.createValidation(constraint, addressList);
|
|
|
sheet.addValidationData(dataValidation);
|
|
|
}
|
|
|
FileOutputStream stream = new FileOutputStream(excelFile);
|
|
|
workbook.write(stream);
|
|
|
stream.close();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:获取指定单元格的值(字符串)
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-01-01
|
|
|
*
|
|
|
* @param cell
|
|
|
* @return
|
|
|
*/
|
|
|
public static String getStringValue(Cell cell) {
|
|
|
String value = "";
|
|
|
if (cell == null || cell.equals(null) || cell.getCellType() == CellType.BLANK) {
|
|
|
value = "";
|
|
|
} else {
|
|
|
//判断数据类型
|
|
|
switch (cell.getCellType()) {
|
|
|
case FORMULA:
|
|
|
try {
|
|
|
/*
|
|
|
* 此处判断使用公式生成的字符串有问题,因为HSSFDateUtil.isCellDateFormatted(cell)判断过程中cell
|
|
|
* .getNumericCellValue();方法会抛出java.lang.NumberFormatException异常
|
|
|
*/
|
|
|
if (DateUtil.isCellDateFormatted(cell)) {
|
|
|
Date businessDateTime = cell.getDateCellValue();
|
|
|
Calendar cal = Calendar.getInstance();
|
|
|
cal.setTime(businessDateTime);
|
|
|
int year = cal.get(Calendar.YEAR);
|
|
|
int month = cal.get(Calendar.MONTH) + 1;
|
|
|
int date = cal.get(Calendar.DATE);
|
|
|
value = year + "-" + month + "-" + date;
|
|
|
break;
|
|
|
} else {
|
|
|
value = String.valueOf(cell.getNumericCellValue());
|
|
|
}
|
|
|
} catch (IllegalStateException e) {
|
|
|
value = String.valueOf(cell.getRichStringCellValue());
|
|
|
}
|
|
|
break;
|
|
|
case NUMERIC:
|
|
|
value = "" + cell.getNumericCellValue();
|
|
|
break;
|
|
|
case STRING:
|
|
|
value = cell.getStringCellValue();
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
//先设置为字符串格式
|
|
|
//cell.setCellType(CellType.STRING);
|
|
|
//然后读取之
|
|
|
//value=cell.getStringCellValue().trim();
|
|
|
if (value.endsWith(".0")) {
|
|
|
value = value.substring(0, value.length() - 2);
|
|
|
}
|
|
|
return value;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:检查是不是用于导入的模板
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-01-03
|
|
|
*
|
|
|
* @param wb
|
|
|
* @return
|
|
|
*/
|
|
|
public static Sheet getSheetByWorkbook(Workbook wb, int needCols, int ignoreRowCount) {
|
|
|
//实际列数
|
|
|
Sheet sheet1 = wb.getSheetAt(0);
|
|
|
int nowCols = sheet1.getRow(ignoreRowCount).getPhysicalNumberOfCells();
|
|
|
if (needCols > nowCols) {
|
|
|
return null;
|
|
|
}
|
|
|
return sheet1;
|
|
|
}
|
|
|
|
|
|
public static Sheet getSheetByWorkbook(Workbook wb) {
|
|
|
//实际列数
|
|
|
Sheet sheet1 = wb.getSheetAt(0);
|
|
|
return sheet1;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:检查是不是有空值
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-01-03
|
|
|
*
|
|
|
* @param sheet1
|
|
|
* @return
|
|
|
*/
|
|
|
public static JSONObject checkHaveBlankError(Sheet sheet1, int ignoreRowCount, int nowCols, CellStyle redStyle, CellStyle whileStyle) {
|
|
|
JSONObject jo = new JSONObject();
|
|
|
int count = 0;
|
|
|
boolean Error = false;
|
|
|
//遍历每一行
|
|
|
for (Row row : sheet1) {
|
|
|
count++;
|
|
|
//放过行首
|
|
|
if (count < ignoreRowCount + 1) {
|
|
|
continue;
|
|
|
}
|
|
|
//如果当前行没有数据,跳出循环: 行首第一个单元格为空,即视为当前行及以下不再为有效区域!
|
|
|
if (row.getCell(0) == null || row.getCell(0).toString().equals("")) {
|
|
|
break;
|
|
|
}
|
|
|
for (int i = 0; i < nowCols; i++) {
|
|
|
Cell cell = row.getCell(i);
|
|
|
if (cell == null || cell.toString().equals("")) {
|
|
|
cell = row.createCell(i);
|
|
|
cell.setCellStyle(redStyle);
|
|
|
Error = true;
|
|
|
} else {
|
|
|
cell.setCellStyle(whileStyle);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
jo.put("Error", Error);
|
|
|
jo.put("count", count - ignoreRowCount);
|
|
|
return jo;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 功能:检查是不是合法的xls文件
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-01-04
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
|
public static JSONObject IsValidXls(String templateXls, int needCols, int ignoreRowCount) throws IOException {
|
|
|
//返回结果
|
|
|
JSONObject jo = new JSONObject();
|
|
|
|
|
|
//检查是不是EXCEL文件
|
|
|
File excelFile = new File(templateXls); // 创建文件对象
|
|
|
if (!excelFile.exists()) {
|
|
|
jo.put("success", false);
|
|
|
jo.put("message", "文件不存在!!");
|
|
|
return jo;
|
|
|
}
|
|
|
if (!excelFile.getName().endsWith("xls")) {
|
|
|
jo.put("success", false);
|
|
|
jo.put("message", "只接收xls格式文件!");
|
|
|
return jo;
|
|
|
}
|
|
|
FileInputStream in = new FileInputStream(excelFile); // 文件流
|
|
|
Workbook wb = ExcelCommonUtil.getWorkbook(in);
|
|
|
if (wb == null) {
|
|
|
jo.put("success", false);
|
|
|
jo.put("message", "不是EXCEL文件格式!");
|
|
|
} else {
|
|
|
//检查是不是符合我们要求的模板
|
|
|
Sheet sheet1 = ExcelCommonUtil.getSheetByWorkbook(wb, needCols, ignoreRowCount);
|
|
|
if (sheet1 == null) {
|
|
|
jo.put("success", false);
|
|
|
jo.put("message", "不是符合要求的模板文件!");
|
|
|
} else {
|
|
|
jo.put("success", true);
|
|
|
jo.put("message", "是符合要求的模板文件!");
|
|
|
}
|
|
|
}
|
|
|
if (in != null) {
|
|
|
in.close();
|
|
|
}
|
|
|
if (wb != null) {
|
|
|
wb.close();
|
|
|
}
|
|
|
return jo;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:检查xls文件是不是存在空值
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-01-04
|
|
|
*
|
|
|
* @param templateXls
|
|
|
* @return
|
|
|
*/
|
|
|
public static JSONObject IsHaveBlank(String templateXls, int ignoreRowCount, int nowCols) throws IOException {
|
|
|
JSONObject jo = new JSONObject();
|
|
|
|
|
|
FileInputStream in = new FileInputStream(templateXls); // 文件流
|
|
|
Workbook wb = ExcelCommonUtil.getWorkbook(in);
|
|
|
|
|
|
//声明两个样式
|
|
|
CellStyle redStyle = ExcelCommonUtil.getCellStyle(wb, IndexedColors.RED.getIndex());
|
|
|
CellStyle whileStyle = ExcelCommonUtil.getCellStyle(wb);
|
|
|
|
|
|
Sheet sheet1 = wb.getSheetAt(0);
|
|
|
//检查一下行数
|
|
|
|
|
|
//检查是不是有为空的
|
|
|
JSONObject ErrorBlankJO = ExcelCommonUtil.checkHaveBlankError(sheet1, ignoreRowCount, nowCols, redStyle, whileStyle);
|
|
|
|
|
|
//存在不存在空的都回写一下
|
|
|
FileOutputStream excelFileOutPutStream = new FileOutputStream(templateXls);
|
|
|
wb.write(excelFileOutPutStream);
|
|
|
excelFileOutPutStream.flush();
|
|
|
|
|
|
//2、检查是不是都完整填写
|
|
|
if (ErrorBlankJO.getBoolean("Error")) {
|
|
|
jo.put("success", false);
|
|
|
jo.put("message", "发现有信息为空的列,不能继续,请检查后重新提交!");
|
|
|
} else {
|
|
|
if (ErrorBlankJO.getInteger("count") == 0) {
|
|
|
jo.put("success", false);
|
|
|
jo.put("message", "检查发现是一个空的表格,不能上传!");
|
|
|
} else {
|
|
|
jo.put("success", true);
|
|
|
jo.put("message", "检查通过,不存在空值的项!");
|
|
|
}
|
|
|
}
|
|
|
if (in != null) {
|
|
|
in.close();
|
|
|
}
|
|
|
if (wb != null) {
|
|
|
wb.close();
|
|
|
}
|
|
|
return jo;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:获取样式
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-01-2
|
|
|
*
|
|
|
* @param wb
|
|
|
* @param color
|
|
|
* @return
|
|
|
*/
|
|
|
public static CellStyle getCellStyle(Workbook wb, short color) {
|
|
|
CellStyle style = getCellStyle(wb);
|
|
|
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
style.setFillForegroundColor(color);
|
|
|
return style;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:获取样式
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-01-2
|
|
|
*
|
|
|
* @param wb
|
|
|
* @return
|
|
|
*/
|
|
|
public static CellStyle getCellStyle(Workbook wb) {
|
|
|
CellStyle style = wb.createCellStyle();
|
|
|
style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
style.setWrapText(true);//设置自动换行
|
|
|
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
style.setBorderBottom(BorderStyle.THIN); // 底部边框
|
|
|
style.setBorderLeft(BorderStyle.THIN); // 左边边框
|
|
|
style.setBorderRight(BorderStyle.THIN); // 右边边框
|
|
|
style.setBorderTop(BorderStyle.THIN); // 上边边框
|
|
|
Font txtFont = wb.createFont();
|
|
|
txtFont.setFontHeightInPoints((short) 14); //字体大小
|
|
|
txtFont.setFontName("宋体"); //字体
|
|
|
style.setFont(txtFont);
|
|
|
style.setFillForegroundColor(IndexedColors.LIME.getIndex());
|
|
|
//设置文本格式
|
|
|
DataFormat format = wb.createDataFormat();
|
|
|
style.setDataFormat(format.getFormat("@"));
|
|
|
return style;
|
|
|
}
|
|
|
|
|
|
public static Kv ImportExcelPublicCheckFunction(UploadFile picFile, int ignoreRowCount, int needCols, boolean checkBlank) throws IOException {
|
|
|
String fileName = picFile.getFileName();
|
|
|
Kv kv = Kv.create();
|
|
|
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).trim();
|
|
|
if (!suffix.equals("xls")) {
|
|
|
kv.set("success", false);
|
|
|
kv.set("message", "上传文件类型错误!系统只允许上传xls格式!");
|
|
|
return kv;
|
|
|
}
|
|
|
//判断文件大小大于20mb则返回错误信息,并终止上传,删除上传文件
|
|
|
long size = picFile.getFile().length();
|
|
|
if (size > 1024 * 1024 * 20) {
|
|
|
kv.set("success", false);
|
|
|
kv.set("message", "xls文件大小大于20MB,请检查!");
|
|
|
return kv;
|
|
|
}
|
|
|
String basePath = PathKit.getRootClassPath() + PropKit.get("ExcelImportTemplatePathSuffix").replace("\\", "/");
|
|
|
String TemplatePath = basePath + "excelTemp/";
|
|
|
String uuidString = UUID.randomUUID().toString().toUpperCase();
|
|
|
String templateXls = TemplatePath + "/" + uuidString + ".xls";
|
|
|
//判断目录是不是存在
|
|
|
File file = new File(TemplatePath);
|
|
|
if (!file.exists()) {
|
|
|
file.mkdirs();// 创建文件夹
|
|
|
}
|
|
|
picFile.getFile().renameTo(new File(templateXls));
|
|
|
//1、是不是XLS格式,是不是我们的模板
|
|
|
JSONObject jo = ExcelCommonUtil.IsValidXls(templateXls, needCols, ignoreRowCount);
|
|
|
if (!jo.getBoolean("success")) {
|
|
|
kv.set("success", false);
|
|
|
return kv;
|
|
|
}
|
|
|
//2、检查一下是不是有空的
|
|
|
if (checkBlank) {
|
|
|
jo = ExcelCommonUtil.IsHaveBlank(templateXls, ignoreRowCount, needCols);
|
|
|
if (!jo.getBoolean("success")) {
|
|
|
kv.set("success", false);
|
|
|
return kv;
|
|
|
}
|
|
|
}
|
|
|
kv.set("uuid", uuidString);
|
|
|
kv.set("templateXls", templateXls);
|
|
|
kv.set("success", true);
|
|
|
return kv;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 功能:导入EXCEL通用检查函数(允许空值)
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-08-11
|
|
|
*
|
|
|
* @param picFile
|
|
|
* @param ignoreRowCount
|
|
|
* @param needCols
|
|
|
* @return
|
|
|
* @throws IOException
|
|
|
*/
|
|
|
public static Kv ImportExcelPublicCheckFunctionAllowBlank(UploadFile picFile, int ignoreRowCount, int needCols) throws IOException {
|
|
|
String fileName = picFile.getFileName();
|
|
|
Kv kv = Kv.create();
|
|
|
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).trim();
|
|
|
if (!suffix.equals("xls")) {
|
|
|
kv.set("success", false);
|
|
|
kv.set("message", "上传文件类型错误!系统只允许上传xls格式!");
|
|
|
return kv;
|
|
|
}
|
|
|
//判断文件大小大于20mb则返回错误信息,并终止上传,删除上传文件
|
|
|
long size = picFile.getFile().length();
|
|
|
if (size > 1024 * 1024 * 20) {
|
|
|
kv.set("success", false);
|
|
|
kv.set("message", "xls文件大小大于20MB,请检查!");
|
|
|
return kv;
|
|
|
}
|
|
|
String basePath = PathKit.getRootClassPath() + PropKit.get("ExcelImportTemplatePathSuffix").replace("\\", "/");
|
|
|
String TemplatePath = basePath + "excelTemp/";
|
|
|
String uuidString = UUID.randomUUID().toString().toUpperCase();
|
|
|
String templateXls = TemplatePath + "/" + uuidString + ".xls";
|
|
|
//判断目录是不是存在
|
|
|
File file = new File(TemplatePath);
|
|
|
if (!file.exists()) {
|
|
|
file.mkdirs();// 创建文件夹
|
|
|
}
|
|
|
picFile.getFile().renameTo(new File(templateXls));
|
|
|
//1、是不是XLS格式,是不是我们的模板
|
|
|
JSONObject jo = ExcelCommonUtil.IsValidXls(templateXls, needCols, ignoreRowCount);
|
|
|
if (!jo.getBoolean("success")) {
|
|
|
kv.set("success", false);
|
|
|
kv.set("message", jo.get("message"));
|
|
|
return kv;
|
|
|
}
|
|
|
kv.set("uuid", uuidString);
|
|
|
kv.set("templateXls", templateXls);
|
|
|
kv.set("success", true);
|
|
|
return kv;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:给定一个EXCEL的列名,转换为数字
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-09-05
|
|
|
*
|
|
|
* @param colStr
|
|
|
* @return
|
|
|
*/
|
|
|
public static int excelColStrToNum(String colStr) {
|
|
|
int length = colStr.length();
|
|
|
int num;
|
|
|
int result = 0;
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
char ch = colStr.charAt(length - i - 1);
|
|
|
num = ch - 'A' + 1;
|
|
|
num *= Math.pow(26, i);
|
|
|
result += num;
|
|
|
}
|
|
|
return result - 1;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:给定一个EXCEL的列序号,返回列名
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-09-05
|
|
|
*
|
|
|
* @param columnIndex
|
|
|
* @return
|
|
|
*/
|
|
|
public static String excelColIndexToStr(int columnIndex) {
|
|
|
if (columnIndex <= 0) {
|
|
|
return null;
|
|
|
}
|
|
|
String columnStr = "";
|
|
|
columnIndex--;
|
|
|
do {
|
|
|
if (columnStr.length() > 0) {
|
|
|
columnIndex--;
|
|
|
}
|
|
|
columnStr = ((char) (columnIndex % 26 + (int) 'A')) + columnStr;
|
|
|
columnIndex = (columnIndex - columnIndex % 26) / 26;
|
|
|
} while (columnIndex > 0);
|
|
|
return columnStr;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:创建Xssf的颜色
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-09-26
|
|
|
*
|
|
|
* @param hex
|
|
|
* @return
|
|
|
*/
|
|
|
public static XSSFColor createXssfColor(String hex) {
|
|
|
String colorStr = hex;
|
|
|
if (hex.startsWith("#")) {
|
|
|
colorStr = hex.substring(1);
|
|
|
}
|
|
|
if (StringUtils.length(colorStr) == 8) {
|
|
|
colorStr = hex.substring(2);
|
|
|
}
|
|
|
int r = Integer.valueOf(colorStr.substring(0, 2), 16);
|
|
|
int g = Integer.valueOf(colorStr.substring(2, 4), 16);
|
|
|
int b = Integer.valueOf(colorStr.substring(4, 6), 16);
|
|
|
|
|
|
int[] rgbColor = new int[]{r, g, b};
|
|
|
XSSFColor xssfColor = new XSSFColor(new java.awt.Color(rgbColor[0], rgbColor[1], rgbColor[2]), new DefaultIndexedColorMap());
|
|
|
return xssfColor;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:合并单元格成区域
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-09-28
|
|
|
*
|
|
|
* @param sheet
|
|
|
* @param firstCol
|
|
|
* @param lastCol
|
|
|
*/
|
|
|
public static void MergeRegion(XSSFSheet sheet, int first_row, int last_row, int firstCol, int lastCol) {
|
|
|
CellRangeAddress region = new CellRangeAddress(first_row, last_row, firstCol, lastCol);
|
|
|
sheet.addMergedRegion(region);
|
|
|
//边框
|
|
|
RegionUtil.setBorderBottom(BorderStyle.THIN, region, sheet);
|
|
|
RegionUtil.setBorderLeft(BorderStyle.THIN, region, sheet);
|
|
|
RegionUtil.setBorderRight(BorderStyle.THIN, region, sheet);
|
|
|
RegionUtil.setBorderTop(BorderStyle.THIN, region, sheet);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:合并单元格(相同单元格内容)
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-09-25
|
|
|
*
|
|
|
* @param size
|
|
|
* @param cellStyle
|
|
|
* @param sheet
|
|
|
* @param col
|
|
|
*/
|
|
|
public static List<Record> mergeCellBySameContent(int size, int startRow, CellStyle cellStyle, Sheet sheet, int col) {
|
|
|
List<Record> Mergelist = new ArrayList<>();
|
|
|
int totalRow = size + startRow;
|
|
|
for (int p = startRow; p < totalRow; p++) {// totalRow 总行数
|
|
|
Cell currentCell = sheet.getRow(p).getCell(col);
|
|
|
String current = ExcelCommonUtil.getStringValue(currentCell);
|
|
|
Cell nextCell;
|
|
|
String next = "";
|
|
|
if (p < totalRow + 1) {
|
|
|
Row nowRow = sheet.getRow(p + 1);
|
|
|
if (nowRow != null) {
|
|
|
nextCell = nowRow.getCell(col);
|
|
|
next = ExcelCommonUtil.getStringValue(nextCell);
|
|
|
} else {
|
|
|
next = "";
|
|
|
}
|
|
|
} else {
|
|
|
next = "";
|
|
|
}
|
|
|
if (current.equals(next)) {// 比对是否相同
|
|
|
currentCell.setCellValue("");
|
|
|
continue;
|
|
|
} else if (!current.equals(next)) {
|
|
|
if ((p) - startRow > 0 && current != "") {
|
|
|
sheet.addMergedRegion(new CellRangeAddress(startRow, p, col, col));// 合并单元格
|
|
|
Record record = new Record();
|
|
|
record.set("firstRow", startRow);
|
|
|
record.set("lastRow", p);
|
|
|
Mergelist.add(record);
|
|
|
Cell nowCell = sheet.getRow(startRow).getCell(col);
|
|
|
nowCell.setCellValue(current);
|
|
|
nowCell.setCellStyle(cellStyle);
|
|
|
}
|
|
|
startRow = p + 1;
|
|
|
}
|
|
|
}
|
|
|
return Mergelist;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:获取一个黄海常用的EXCEL中单元格的样式
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-09-27
|
|
|
*
|
|
|
* @param workbook
|
|
|
* @return
|
|
|
*/
|
|
|
public static XSSFCellStyle GenerateNormalCellStyle(XSSFWorkbook workbook, String fontName, int fontSize) {
|
|
|
//主表格的样式
|
|
|
Font txtFont = workbook.createFont();
|
|
|
txtFont.setFontHeightInPoints((short) fontSize); //字体大小
|
|
|
txtFont.setFontName(fontName); //字体
|
|
|
txtFont.setBold(false);
|
|
|
XSSFCellStyle cellStyleTxt = workbook.createCellStyle();
|
|
|
cellStyleTxt.setFont(txtFont);
|
|
|
cellStyleTxt.setAlignment(HorizontalAlignment.CENTER);
|
|
|
cellStyleTxt.setWrapText(true);//设置自动换行
|
|
|
cellStyleTxt.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
cellStyleTxt.setBorderBottom(BorderStyle.THIN); // 底部边框
|
|
|
cellStyleTxt.setBorderLeft(BorderStyle.THIN); // 左边边框
|
|
|
cellStyleTxt.setBorderRight(BorderStyle.THIN); // 右边边框
|
|
|
cellStyleTxt.setBorderTop(BorderStyle.THIN); // 上边边框
|
|
|
return cellStyleTxt;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:从一个标准的单元格样式复制出来一个背景色特殊的样式
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-09-28
|
|
|
*
|
|
|
* @param workbook
|
|
|
* @param sourceCellStyle
|
|
|
* @param hexColor
|
|
|
* @return
|
|
|
*/
|
|
|
public static XSSFCellStyle CopyColorCellStyle(XSSFWorkbook workbook,
|
|
|
XSSFCellStyle sourceCellStyle, String hexColor) {
|
|
|
XSSFCellStyle style = workbook.createCellStyle();
|
|
|
style.cloneStyleFrom(sourceCellStyle);
|
|
|
style.setFillPattern(FillPatternType.SOLID_FOREGROUND); //设置填充方案
|
|
|
style.setFillForegroundColor(ExcelCommonUtil.createXssfColor(hexColor)); //设置填充颜色
|
|
|
return style;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:移除合并好的单元格
|
|
|
* 作者:黄海
|
|
|
* 时间:2019-09-27
|
|
|
*
|
|
|
* @param sheet
|
|
|
* @param row
|
|
|
* @param column
|
|
|
*/
|
|
|
public static void removeMergedRegion(XSSFSheet sheet, int row, int column) {
|
|
|
int sheetMergeCount = sheet.getNumMergedRegions();//获取所有的单元格
|
|
|
int index = 0;//用于保存要移除的那个单元格序号
|
|
|
for (int i = 0; i < sheetMergeCount; i++) {
|
|
|
CellRangeAddress ca = sheet.getMergedRegion(i); //获取第i个单元格
|
|
|
int firstColumn = ca.getFirstColumn();
|
|
|
int lastColumn = ca.getLastColumn();
|
|
|
int firstRow = ca.getFirstRow();
|
|
|
int lastRow = ca.getLastRow();
|
|
|
if (row >= firstRow && row <= lastRow) {
|
|
|
if (column >= firstColumn && column <= lastColumn) {
|
|
|
index = i;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
sheet.removeMergedRegion(index);//移除合并单元格
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 将List<Record>数据写入到Excel中
|
|
|
*
|
|
|
* @param tableData
|
|
|
* @param filePath
|
|
|
* @throws IOException
|
|
|
*/
|
|
|
public static void writeExcel(List<Record> tableData, String filePath, boolean killIdColumns) throws IOException {
|
|
|
if (killIdColumns) {
|
|
|
//表tableData中如果有一列叫id,那么去掉这一列
|
|
|
for (Record tableDatum : tableData) {
|
|
|
tableDatum.remove("id");
|
|
|
}
|
|
|
}
|
|
|
// 创建Excel工作簿
|
|
|
Workbook workbook = new XSSFWorkbook();
|
|
|
// 创建一个Excel工作表
|
|
|
Sheet sheet = workbook.createSheet("Sheet1");
|
|
|
// 获取第一个Record的元数据以确定列名
|
|
|
int columnCount = tableData.getFirst().size();
|
|
|
// 创建标题行
|
|
|
Row titleRow = sheet.createRow(0);
|
|
|
// 设置标题行的样式
|
|
|
CellStyle titleStyle = workbook.createCellStyle();
|
|
|
Font font = workbook.createFont();
|
|
|
font.setBold(true);
|
|
|
font.setFontHeightInPoints((short) 14);
|
|
|
titleStyle.setFont(font);
|
|
|
titleStyle.setBorderBottom(BorderStyle.THIN);
|
|
|
titleStyle.setBorderLeft(BorderStyle.THIN);
|
|
|
titleStyle.setBorderRight(BorderStyle.THIN);
|
|
|
titleStyle.setBorderTop(BorderStyle.THIN);
|
|
|
|
|
|
// 填充标题行
|
|
|
for (int i = 1; i <= columnCount; i++) {
|
|
|
Cell cell = titleRow.createCell(i - 1);
|
|
|
cell.setCellValue(tableData.getFirst().getColumnNames()[i - 1]);
|
|
|
cell.setCellStyle(titleStyle);
|
|
|
}
|
|
|
|
|
|
// 创建数据行的样式
|
|
|
CellStyle dataStyle = workbook.createCellStyle();
|
|
|
font = workbook.createFont();
|
|
|
font.setFontHeightInPoints((short) 14);
|
|
|
dataStyle.setFont(font);
|
|
|
dataStyle.setBorderBottom(BorderStyle.THIN);
|
|
|
dataStyle.setBorderLeft(BorderStyle.THIN);
|
|
|
dataStyle.setBorderRight(BorderStyle.THIN);
|
|
|
dataStyle.setBorderTop(BorderStyle.THIN);
|
|
|
|
|
|
// 填充数据行
|
|
|
int rowNum = 1;
|
|
|
for (Record record : tableData) {
|
|
|
Row row = sheet.createRow(rowNum++);
|
|
|
int cellNum = 0;
|
|
|
for (int i = 1; i <= columnCount; i++) {
|
|
|
Cell cell = row.createCell(cellNum++);
|
|
|
Object value = record.get(tableData.getFirst().getColumnNames()[i - 1]);
|
|
|
cell.setCellValue(value == null ? "" : value.toString());
|
|
|
cell.setCellStyle(dataStyle);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 设置最小列宽
|
|
|
int minColumnWidth = 100 * 256 / 7; // 将像素转换为字符单位(Excel的单位是1/256个字符宽度)
|
|
|
for (int i = 0; i < tableData.getFirst().getColumnNames().length; i++) {
|
|
|
sheet.setColumnWidth(i, Math.max(minColumnWidth, sheet.getColumnWidth(i)));
|
|
|
}
|
|
|
|
|
|
// 自动调整列宽
|
|
|
for (int i = 0; i < tableData.getFirst().getColumnNames().length; i++) {
|
|
|
sheet.autoSizeColumn(i);
|
|
|
int columnWidth = sheet.getColumnWidth(i);
|
|
|
int newColumnWidth = Math.max(minColumnWidth, columnWidth);
|
|
|
sheet.setColumnWidth(i, newColumnWidth);
|
|
|
}
|
|
|
|
|
|
// 将工作簿写入文件
|
|
|
try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
|
|
|
workbook.write(fileOut);
|
|
|
}
|
|
|
// 关闭工作簿
|
|
|
workbook.close();
|
|
|
}
|
|
|
}
|