¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.common.utils.excel; |
| | | |
| | | import com.alibaba.fastjson2.JSONArray; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import org.apache.poi.hssf.usermodel.HSSFDataValidation; |
| | | import org.apache.poi.hssf.usermodel.HSSFWorkbook; |
| | | import org.apache.poi.poifs.filesystem.POIFSFileSystem; |
| | | import org.apache.poi.ss.usermodel.*; |
| | | import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType; |
| | | import org.apache.poi.ss.util.CellRangeAddress; |
| | | import org.apache.poi.ss.util.CellRangeAddressList; |
| | | import org.apache.poi.xssf.streaming.SXSSFWorkbook; |
| | | import org.apache.poi.xssf.usermodel.XSSFClientAnchor; |
| | | import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import javax.servlet.ServletOutputStream; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.*; |
| | | import java.lang.reflect.Field; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.net.URL; |
| | | import java.text.NumberFormat; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.*; |
| | | import java.util.Map.Entry; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * Excel导å
¥å¯¼åºå·¥å
·ç±» |
| | | * åæé¾æ¥ï¼ä¸å®æ¶å¢å æ°åè½ï¼: https://zyqok.blog.csdn.net/article/details/121994504 |
| | | * |
| | | * @author sunnyzyq |
| | | * @date 2021/12/17 |
| | | */ |
| | | @SuppressWarnings("unused") |
| | | public class ExcelUtils { |
| | | |
| | | private static final String XLSX = ".xlsx"; |
| | | private static final String XLS = ".xls"; |
| | | public static final String ROW_MERGE = "row_merge"; |
| | | public static final String COLUMN_MERGE = "column_merge"; |
| | | private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; |
| | | private static final String ROW_NUM = "rowNum"; |
| | | private static final String ROW_DATA = "rowData"; |
| | | private static final String ROW_TIPS = "rowTips"; |
| | | private static final int CELL_OTHER = 0; |
| | | private static final int CELL_ROW_MERGE = 1; |
| | | private static final int CELL_COLUMN_MERGE = 2; |
| | | private static final int IMG_HEIGHT = 30; |
| | | private static final int IMG_WIDTH = 30; |
| | | private static final char LEAN_LINE = '/'; |
| | | private static final int BYTES_DEFAULT_LENGTH = 10240; |
| | | private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance(); |
| | | |
| | | |
| | | public static <T> List<T> readFile(File file, Class<T> clazz) throws Exception { |
| | | JSONArray array = readFile(file); |
| | | return getBeanList(array, clazz); |
| | | } |
| | | |
| | | public static <T> List<T> readMultipartFile(MultipartFile mFile, Class<T> clazz) throws Exception { |
| | | JSONArray array = readMultipartFile(mFile); |
| | | return getBeanList(array, clazz); |
| | | } |
| | | |
| | | public static JSONArray readFile(File file) throws Exception { |
| | | return readExcel(null, file); |
| | | } |
| | | |
| | | public static JSONArray readMultipartFile(MultipartFile mFile) throws Exception { |
| | | return readExcel(mFile, null); |
| | | } |
| | | |
| | | public static Map<String, JSONArray> readFileManySheet(File file) throws Exception { |
| | | return readExcelManySheet(null, file); |
| | | } |
| | | |
| | | public static Map<String, JSONArray> readFileManySheet(MultipartFile file) throws Exception { |
| | | return readExcelManySheet(file, null); |
| | | } |
| | | |
| | | private static <T> List<T> getBeanList(JSONArray array, Class<T> clazz) throws Exception { |
| | | List<T> list = new ArrayList<>(); |
| | | Map<Integer, String> uniqueMap = new HashMap<>(16); |
| | | for (int i = 0; i < array.size(); i++) { |
| | | list.add(getBean(clazz, array.getJSONObject(i), uniqueMap)); |
| | | } |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * è·åæ¯ä¸ªå¯¹è±¡çæ°æ® |
| | | */ |
| | | private static <T> T getBean(Class<T> c, JSONObject obj, Map<Integer, String> uniqueMap) throws Exception { |
| | | T t = c.newInstance(); |
| | | Field[] fields = c.getDeclaredFields(); |
| | | List<String> errMsgList = new ArrayList<>(); |
| | | boolean hasRowTipsField = false; |
| | | StringBuilder uniqueBuilder = new StringBuilder(); |
| | | int rowNum = 0; |
| | | for (Field field : fields) { |
| | | // è¡å· |
| | | if (field.getName().equals(ROW_NUM)) { |
| | | rowNum = obj.getInteger(ROW_NUM); |
| | | field.setAccessible(true); |
| | | field.set(t, rowNum); |
| | | continue; |
| | | } |
| | | // æ¯å¦éè¦è®¾ç½®å¼å¸¸ä¿¡æ¯ |
| | | if (field.getName().equals(ROW_TIPS)) { |
| | | hasRowTipsField = true; |
| | | continue; |
| | | } |
| | | // åå§æ°æ® |
| | | if (field.getName().equals(ROW_DATA)) { |
| | | field.setAccessible(true); |
| | | field.set(t, obj.toString()); |
| | | continue; |
| | | } |
| | | // 设置对åºå±æ§å¼ |
| | | setFieldValue(t, field, obj, uniqueBuilder, errMsgList); |
| | | } |
| | | // æ°æ®å¯ä¸æ§æ ¡éª |
| | | if (uniqueBuilder.length() > 0) { |
| | | if (uniqueMap.containsValue(uniqueBuilder.toString())) { |
| | | Set<Integer> rowNumKeys = uniqueMap.keySet(); |
| | | for (Integer num : rowNumKeys) { |
| | | if (uniqueMap.get(num).equals(uniqueBuilder.toString())) { |
| | | errMsgList.add(String.format("æ°æ®å¯ä¸æ§æ ¡éªå¤±è´¥,(%s)ä¸ç¬¬%sè¡éå¤)", uniqueBuilder, num)); |
| | | } |
| | | } |
| | | } else { |
| | | uniqueMap.put(rowNum, uniqueBuilder.toString()); |
| | | } |
| | | } |
| | | // 失败å¤ç |
| | | if (errMsgList.isEmpty() && !hasRowTipsField) { |
| | | return t; |
| | | } |
| | | StringBuilder sb = new StringBuilder(); |
| | | int size = errMsgList.size(); |
| | | for (int i = 0; i < size; i++) { |
| | | if (i == size - 1) { |
| | | sb.append(errMsgList.get(i)); |
| | | } else { |
| | | sb.append(errMsgList.get(i)).append(";"); |
| | | } |
| | | } |
| | | // 设置éè¯¯ä¿¡æ¯ |
| | | for (Field field : fields) { |
| | | if (field.getName().equals(ROW_TIPS)) { |
| | | field.setAccessible(true); |
| | | field.set(t, sb.toString()); |
| | | } |
| | | } |
| | | return t; |
| | | } |
| | | |
| | | private static <T> void setFieldValue(T t, Field field, JSONObject obj, StringBuilder uniqueBuilder, List<String> errMsgList) { |
| | | // è·å ExcelImport æ³¨è§£å±æ§ |
| | | ExcelImport annotation = field.getAnnotation(ExcelImport.class); |
| | | if (annotation == null) { |
| | | return; |
| | | } |
| | | String cname = annotation.value(); |
| | | if (cname.trim().length() == 0) { |
| | | return; |
| | | } |
| | | // è·åå
·ä½å¼ |
| | | String val = null; |
| | | if (obj.containsKey(cname)) { |
| | | val = getString(obj.getString(cname)); |
| | | } |
| | | if (val == null) { |
| | | return; |
| | | } |
| | | field.setAccessible(true); |
| | | // 夿æ¯å¦å¿
å¡« |
| | | boolean require = annotation.required(); |
| | | if (require && val.isEmpty()) { |
| | | errMsgList.add(String.format("[%s]ä¸è½ä¸ºç©º", cname)); |
| | | return; |
| | | } |
| | | // æ°æ®å¯ä¸æ§è·å |
| | | boolean unique = annotation.unique(); |
| | | if (unique) { |
| | | if (uniqueBuilder.length() > 0) { |
| | | uniqueBuilder.append("--").append(val); |
| | | } else { |
| | | uniqueBuilder.append(val); |
| | | } |
| | | } |
| | | // 夿æ¯å¦è¶
è¿æå¤§é¿åº¦ |
| | | int maxLength = annotation.maxLength(); |
| | | if (maxLength > 0 && val.length() > maxLength) { |
| | | errMsgList.add(String.format("[%s]é¿åº¦ä¸è½è¶
è¿%s个å符(å½å%s个å符)", cname, maxLength, val.length())); |
| | | } |
| | | // 夿å½å屿§æ¯å¦ææ å°å
³ç³» |
| | | LinkedHashMap<String, String> kvMap = getKvMap(annotation.kv()); |
| | | if (!kvMap.isEmpty()) { |
| | | boolean isMatch = false; |
| | | for (String key : kvMap.keySet()) { |
| | | if (kvMap.get(key).equals(val)) { |
| | | val = key; |
| | | isMatch = true; |
| | | break; |
| | | } |
| | | } |
| | | if (!isMatch) { |
| | | errMsgList.add(String.format("[%s]çå¼ä¸æ£ç¡®(å½åå¼ä¸º%s)", cname, val)); |
| | | return; |
| | | } |
| | | } |
| | | // å
¶ä½æ
嵿 ¹æ®ç±»åèµå¼ |
| | | String fieldClassName = field.getType().getSimpleName(); |
| | | try { |
| | | if ("String".equalsIgnoreCase(fieldClassName)) { |
| | | field.set(t, val); |
| | | } else if ("boolean".equalsIgnoreCase(fieldClassName)) { |
| | | field.set(t, Boolean.valueOf(val)); |
| | | } else if ("int".equalsIgnoreCase(fieldClassName) || "Integer".equals(fieldClassName)) { |
| | | try { |
| | | field.set(t, Integer.valueOf(val)); |
| | | } catch (NumberFormatException e) { |
| | | errMsgList.add(String.format("[%s]ç弿 ¼å¼ä¸æ£ç¡®(å½åå¼ä¸º%s)", cname, val)); |
| | | } |
| | | } else if ("double".equalsIgnoreCase(fieldClassName)) { |
| | | field.set(t, Double.valueOf(val)); |
| | | } else if ("long".equalsIgnoreCase(fieldClassName)) { |
| | | field.set(t, Long.valueOf(val)); |
| | | } else if ("BigDecimal".equalsIgnoreCase(fieldClassName)) { |
| | | field.set(t, new BigDecimal(val)); |
| | | } else if ("Date".equalsIgnoreCase(fieldClassName)) { |
| | | try { |
| | | field.set(t, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(val)); |
| | | } catch (Exception e) { |
| | | field.set(t, new SimpleDateFormat("yyyy-MM-dd").parse(val)); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | private static Map<String, JSONArray> readExcelManySheet(MultipartFile mFile, File file) throws IOException { |
| | | Workbook book = getWorkbook(mFile, file); |
| | | if (book == null) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | Map<String, JSONArray> map = new LinkedHashMap<>(); |
| | | for (int i = 0; i < book.getNumberOfSheets(); i++) { |
| | | Sheet sheet = book.getSheetAt(i); |
| | | JSONArray arr = readSheet(sheet); |
| | | map.put(sheet.getSheetName(), arr); |
| | | } |
| | | book.close(); |
| | | return map; |
| | | } |
| | | |
| | | private static JSONArray readExcel(MultipartFile mFile, File file) throws IOException { |
| | | Workbook book = getWorkbook(mFile, file); |
| | | if (book == null) { |
| | | return new JSONArray(); |
| | | } |
| | | JSONArray array = readSheet(book.getSheetAt(0)); |
| | | book.close(); |
| | | return array; |
| | | } |
| | | |
| | | private static Workbook getWorkbook(MultipartFile mFile, File file) throws IOException { |
| | | boolean fileNotExist = (file == null || !file.exists()); |
| | | if (mFile == null && fileNotExist) { |
| | | return null; |
| | | } |
| | | // è§£æè¡¨æ ¼æ°æ® |
| | | InputStream in; |
| | | String fileName; |
| | | if (mFile != null) { |
| | | // ä¸ä¼ æä»¶è§£æ |
| | | in = mFile.getInputStream(); |
| | | fileName = getString(mFile.getOriginalFilename()).toLowerCase(); |
| | | } else { |
| | | // æ¬å°æä»¶è§£æ |
| | | in = new FileInputStream(file); |
| | | fileName = file.getName().toLowerCase(); |
| | | } |
| | | Workbook book; |
| | | if (fileName.endsWith(XLSX)) { |
| | | book = new XSSFWorkbook(in); |
| | | } else if (fileName.endsWith(XLS)) { |
| | | POIFSFileSystem poifsFileSystem = new POIFSFileSystem(in); |
| | | book = new HSSFWorkbook(poifsFileSystem); |
| | | } else { |
| | | return null; |
| | | } |
| | | in.close(); |
| | | return book; |
| | | } |
| | | |
| | | private static JSONArray readSheet(Sheet sheet) { |
| | | // é¦è¡ä¸æ |
| | | int rowStart = sheet.getFirstRowNum(); |
| | | // å°¾è¡ä¸æ |
| | | int rowEnd = sheet.getLastRowNum(); |
| | | // è·åè¡¨å¤´è¡ |
| | | Row headRow = sheet.getRow(rowStart); |
| | | if (headRow == null) { |
| | | return new JSONArray(); |
| | | } |
| | | int cellStart = headRow.getFirstCellNum(); |
| | | int cellEnd = headRow.getLastCellNum(); |
| | | Map<Integer, String> keyMap = new HashMap<>(); |
| | | for (int j = cellStart; j < cellEnd; j++) { |
| | | // è·åè¡¨å¤´æ°æ® |
| | | String val = getCellValue(headRow.getCell(j)); |
| | | if (val != null && val.trim().length() != 0) { |
| | | keyMap.put(j, val); |
| | | } |
| | | } |
| | | // å¦æè¡¨å¤´æ²¡ææ°æ®åä¸è¿è¡è§£æ |
| | | if (keyMap.isEmpty()) { |
| | | return (JSONArray) Collections.emptyList(); |
| | | } |
| | | // è·åæ¯è¡JSON对象çå¼ |
| | | JSONArray array = new JSONArray(); |
| | | // 妿é¦è¡ä¸å°¾è¡ç¸åï¼è¡¨æåªæä¸è¡ï¼è¿åè¡¨å¤´æ°æ® |
| | | if (rowStart == rowEnd) { |
| | | JSONObject obj = new JSONObject(); |
| | | // æ·»å è¡å· |
| | | obj.put(ROW_NUM, 1); |
| | | for (int i : keyMap.keySet()) { |
| | | obj.put(keyMap.get(i), ""); |
| | | } |
| | | array.add(obj); |
| | | return array; |
| | | } |
| | | for (int i = rowStart + 1; i <= rowEnd; i++) { |
| | | Row eachRow = sheet.getRow(i); |
| | | JSONObject obj = new JSONObject(); |
| | | // æ·»å è¡å· |
| | | obj.put(ROW_NUM, i + 1); |
| | | StringBuilder sb = new StringBuilder(); |
| | | for (int k = cellStart; k < cellEnd; k++) { |
| | | if (eachRow != null) { |
| | | String val = getCellValue(eachRow.getCell(k)); |
| | | // æææ°æ®æ·»å å°éé¢ï¼ç¨äºå¤æè¯¥è¡æ¯å¦ä¸ºç©º |
| | | sb.append(val); |
| | | obj.put(keyMap.get(k), val); |
| | | } |
| | | } |
| | | if (sb.length() > 0) { |
| | | array.add(obj); |
| | | } |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | private static String getCellValue(Cell cell) { |
| | | // ç©ºç½æç©º |
| | | if (cell == null || cell.getCellType() == CellType.BLANK) { |
| | | return ""; |
| | | } |
| | | // Stringç±»å |
| | | if (cell.getCellType() == CellType.STRING) { |
| | | String val = cell.getStringCellValue(); |
| | | if (val == null || val.trim().length() == 0) { |
| | | return ""; |
| | | } |
| | | return val.trim(); |
| | | } |
| | | // æ°åç±»å |
| | | if (cell.getCellType() == CellType.NUMERIC) { |
| | | String s = cell.getNumericCellValue() + ""; |
| | | // 廿尾巴ä¸çå°æ°ç¹0 |
| | | if (Pattern.matches(".*\\.0*", s)) { |
| | | return s.split("\\.")[0]; |
| | | } else { |
| | | return s; |
| | | } |
| | | } |
| | | // å¸å°å¼ç±»å |
| | | if (cell.getCellType() == CellType.BOOLEAN) { |
| | | return cell.getBooleanCellValue() + ""; |
| | | } |
| | | // é误类å |
| | | return cell.getCellFormula(); |
| | | } |
| | | |
| | | public static <T> void exportTemplate(HttpServletResponse response, String fileName, Class<T> clazz) { |
| | | exportTemplate(response, fileName, fileName, clazz, false); |
| | | } |
| | | |
| | | public static <T> void exportTemplate(HttpServletResponse response, String fileName, String sheetName, |
| | | Class<T> clazz) { |
| | | exportTemplate(response, fileName, sheetName, clazz, false); |
| | | } |
| | | |
| | | public static <T> void exportTemplate(HttpServletResponse response, String fileName, Class<T> clazz, |
| | | boolean isContainExample) { |
| | | exportTemplate(response, fileName, fileName, clazz, isContainExample); |
| | | } |
| | | |
| | | public static <T> void exportTemplate(HttpServletResponse response, String fileName, String sheetName, |
| | | Class<T> clazz, boolean isContainExample) { |
| | | // è·åè¡¨å¤´åæ®µ |
| | | List<ExcelClassField> headFieldList = getExcelClassFieldList(clazz); |
| | | // è·åè¡¨å¤´æ°æ®åç¤ºä¾æ°æ® |
| | | List<List<Object>> sheetDataList = new ArrayList<>(); |
| | | List<Object> headList = new ArrayList<>(); |
| | | List<Object> exampleList = new ArrayList<>(); |
| | | Map<Integer, List<String>> selectMap = new LinkedHashMap<>(); |
| | | for (int i = 0; i < headFieldList.size(); i++) { |
| | | ExcelClassField each = headFieldList.get(i); |
| | | headList.add(each.getName()); |
| | | exampleList.add(each.getExample()); |
| | | LinkedHashMap<String, String> kvMap = each.getKvMap(); |
| | | if (kvMap != null && kvMap.size() > 0) { |
| | | selectMap.put(i, new ArrayList<>(kvMap.values())); |
| | | } |
| | | } |
| | | sheetDataList.add(headList); |
| | | if (isContainExample) { |
| | | sheetDataList.add(exampleList); |
| | | } |
| | | // å¯¼åºæ°æ® |
| | | export(response, fileName, sheetName, sheetDataList, selectMap); |
| | | } |
| | | |
| | | private static <T> List<ExcelClassField> getExcelClassFieldList(Class<T> clazz) { |
| | | // è§£æææåæ®µ |
| | | Field[] fields = clazz.getDeclaredFields(); |
| | | boolean hasExportAnnotation = false; |
| | | Map<Integer, List<ExcelClassField>> map = new LinkedHashMap<>(); |
| | | List<Integer> sortList = new ArrayList<>(); |
| | | for (Field field : fields) { |
| | | ExcelClassField cf = getExcelClassField(field); |
| | | if (cf.getHasAnnotation() == 1) { |
| | | hasExportAnnotation = true; |
| | | } |
| | | int sort = cf.getSort(); |
| | | if (map.containsKey(sort)) { |
| | | map.get(sort).add(cf); |
| | | } else { |
| | | List<ExcelClassField> list = new ArrayList<>(); |
| | | list.add(cf); |
| | | sortList.add(sort); |
| | | map.put(sort, list); |
| | | } |
| | | } |
| | | Collections.sort(sortList); |
| | | // è·å表头 |
| | | List<ExcelClassField> headFieldList = new ArrayList<>(); |
| | | if (hasExportAnnotation) { |
| | | for (Integer sort : sortList) { |
| | | for (ExcelClassField cf : map.get(sort)) { |
| | | if (cf.getHasAnnotation() == 1) { |
| | | headFieldList.add(cf); |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | headFieldList.addAll(map.get(0)); |
| | | } |
| | | return headFieldList; |
| | | } |
| | | |
| | | private static ExcelClassField getExcelClassField(Field field) { |
| | | ExcelClassField cf = new ExcelClassField(); |
| | | String fieldName = field.getName(); |
| | | cf.setFieldName(fieldName); |
| | | ExcelExport annotation = field.getAnnotation(ExcelExport.class); |
| | | // æ ExcelExport 注解æ
åµ |
| | | if (annotation == null) { |
| | | cf.setHasAnnotation(0); |
| | | cf.setName(fieldName); |
| | | cf.setSort(0); |
| | | return cf; |
| | | } |
| | | // æ ExcelExport 注解æ
åµ |
| | | cf.setHasAnnotation(1); |
| | | cf.setName(annotation.value()); |
| | | String example = getString(annotation.example()); |
| | | if (!example.isEmpty()) { |
| | | if (isNumeric(example) && example.length() < 8) { |
| | | cf.setExample(Double.valueOf(example)); |
| | | } else { |
| | | cf.setExample(example); |
| | | } |
| | | } else { |
| | | cf.setExample(""); |
| | | } |
| | | cf.setSort(annotation.sort()); |
| | | // è§£ææ å° |
| | | String kv = getString(annotation.kv()); |
| | | cf.setKvMap(getKvMap(kv)); |
| | | return cf; |
| | | } |
| | | |
| | | private static LinkedHashMap<String, String> getKvMap(String kv) { |
| | | LinkedHashMap<String, String> kvMap = new LinkedHashMap<>(); |
| | | if (kv.isEmpty()) { |
| | | return kvMap; |
| | | } |
| | | String[] kvs = kv.split(";"); |
| | | if (kvs.length == 0) { |
| | | return kvMap; |
| | | } |
| | | for (String each : kvs) { |
| | | String[] eachKv = getString(each).split("-"); |
| | | if (eachKv.length != 2) { |
| | | continue; |
| | | } |
| | | String k = eachKv[0]; |
| | | String v = eachKv[1]; |
| | | if (k.isEmpty() || v.isEmpty()) { |
| | | continue; |
| | | } |
| | | kvMap.put(k, v); |
| | | } |
| | | return kvMap; |
| | | } |
| | | |
| | | /** |
| | | * 导åºè¡¨æ ¼å°æ¬å° |
| | | * |
| | | * @param file æ¬å°æä»¶å¯¹è±¡ |
| | | * @param sheetData å¯¼åºæ°æ® |
| | | */ |
| | | public static void exportFile(File file, List<List<Object>> sheetData) { |
| | | if (file == null) { |
| | | System.out.println("æä»¶å建失败"); |
| | | return; |
| | | } |
| | | if (sheetData == null) { |
| | | sheetData = new ArrayList<>(); |
| | | } |
| | | Map<String, List<List<Object>>> map = new HashMap<>(); |
| | | map.put(file.getName(), sheetData); |
| | | export(null, file, file.getName(), map, null); |
| | | } |
| | | |
| | | /** |
| | | * 导åºè¡¨æ ¼å°æ¬å° |
| | | * |
| | | * @param <T> å¯¼åºæ°æ®ç±»ä¼¼ï¼åKç±»åä¿æä¸è´ |
| | | * @param filePath æä»¶ç¶è·¯å¾ï¼å¦ï¼D:/doc/excel/ï¼ |
| | | * @param fileName æä»¶åç§°ï¼ä¸å¸¦å°¾ç¼ï¼å¦ï¼å¦çè¡¨ï¼ |
| | | * @param list å¯¼åºæ°æ® |
| | | * @throws IOException IOå¼å¸¸ |
| | | */ |
| | | public static <T> File exportFile(String filePath, String fileName, List<T> list) throws IOException { |
| | | File file = getFile(filePath, fileName); |
| | | List<List<Object>> sheetData = getSheetData(list); |
| | | exportFile(file, sheetData); |
| | | return file; |
| | | } |
| | | |
| | | /** |
| | | * è·åæä»¶ |
| | | * |
| | | * @param filePath filePath æä»¶ç¶è·¯å¾ï¼å¦ï¼D:/doc/excel/ï¼ |
| | | * @param fileName æä»¶åç§°ï¼ä¸å¸¦å°¾ç¼ï¼å¦ï¼ç¨æ·è¡¨ï¼ |
| | | * @return æ¬å°Fileæä»¶å¯¹è±¡ |
| | | */ |
| | | private static File getFile(String filePath, String fileName) throws IOException { |
| | | String dirPath = getString(filePath); |
| | | String fileFullPath; |
| | | if (dirPath.isEmpty()) { |
| | | fileFullPath = fileName; |
| | | } else { |
| | | // å¤å®æä»¶å¤¹æ¯å¦åå¨ï¼å¦æä¸åå¨ï¼å级èå建 |
| | | File dirFile = new File(dirPath); |
| | | if (!dirFile.exists()) { |
| | | boolean mkdirs = dirFile.mkdirs(); |
| | | if (!mkdirs) { |
| | | return null; |
| | | } |
| | | } |
| | | // è·åæä»¶å¤¹å
¨å |
| | | if (dirPath.endsWith(String.valueOf(LEAN_LINE))) { |
| | | fileFullPath = dirPath + fileName + XLSX; |
| | | } else { |
| | | fileFullPath = dirPath + LEAN_LINE + fileName + XLSX; |
| | | } |
| | | } |
| | | System.out.println(fileFullPath); |
| | | File file = new File(fileFullPath); |
| | | if (!file.exists()) { |
| | | boolean result = file.createNewFile(); |
| | | if (!result) { |
| | | return null; |
| | | } |
| | | } |
| | | return file; |
| | | } |
| | | |
| | | private static <T> List<List<Object>> getSheetData(List<T> list) { |
| | | // è·åè¡¨å¤´åæ®µ |
| | | List<ExcelClassField> excelClassFieldList = getExcelClassFieldList(list.get(0).getClass()); |
| | | List<String> headFieldList = new ArrayList<>(); |
| | | List<Object> headList = new ArrayList<>(); |
| | | Map<String, ExcelClassField> headFieldMap = new HashMap<>(); |
| | | for (ExcelClassField each : excelClassFieldList) { |
| | | String fieldName = each.getFieldName(); |
| | | headFieldList.add(fieldName); |
| | | headFieldMap.put(fieldName, each); |
| | | headList.add(each.getName()); |
| | | } |
| | | // æ·»å 表头åç§° |
| | | List<List<Object>> sheetDataList = new ArrayList<>(); |
| | | sheetDataList.add(headList); |
| | | // è·åè¡¨æ°æ® |
| | | for (T t : list) { |
| | | Map<String, Object> fieldDataMap = getFieldDataMap(t); |
| | | Set<String> fieldDataKeys = fieldDataMap.keySet(); |
| | | List<Object> rowList = new ArrayList<>(); |
| | | for (String headField : headFieldList) { |
| | | if (!fieldDataKeys.contains(headField)) { |
| | | continue; |
| | | } |
| | | Object data = fieldDataMap.get(headField); |
| | | if (data == null) { |
| | | rowList.add(""); |
| | | continue; |
| | | } |
| | | ExcelClassField cf = headFieldMap.get(headField); |
| | | // 夿æ¯å¦ææ å°å
³ç³» |
| | | LinkedHashMap<String, String> kvMap = cf.getKvMap(); |
| | | if (kvMap == null || kvMap.isEmpty()) { |
| | | rowList.add(data); |
| | | continue; |
| | | } |
| | | String val = kvMap.get(data.toString()); |
| | | if (isNumeric(val)) { |
| | | rowList.add(Double.valueOf(val)); |
| | | } else { |
| | | rowList.add(val); |
| | | } |
| | | } |
| | | sheetDataList.add(rowList); |
| | | } |
| | | return sheetDataList; |
| | | } |
| | | |
| | | private static <T> Map<String, Object> getFieldDataMap(T t) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | Field[] fields = t.getClass().getDeclaredFields(); |
| | | try { |
| | | for (Field field : fields) { |
| | | String fieldName = field.getName(); |
| | | field.setAccessible(true); |
| | | Object object = field.get(t); |
| | | map.put(fieldName, object); |
| | | } |
| | | } catch (IllegalArgumentException | IllegalAccessException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | public static void exportEmpty(HttpServletResponse response, String fileName) { |
| | | List<List<Object>> sheetDataList = new ArrayList<>(); |
| | | List<Object> headList = new ArrayList<>(); |
| | | headList.add("å¯¼åºæ æ°æ®"); |
| | | sheetDataList.add(headList); |
| | | export(response, fileName, sheetDataList); |
| | | } |
| | | |
| | | public static void export(HttpServletResponse response, String fileName, List<List<Object>> sheetDataList) { |
| | | export(response, fileName, fileName, sheetDataList, null); |
| | | } |
| | | |
| | | public static void exportManySheet(HttpServletResponse response, String fileName, Map<String, List<List<Object>>> sheetMap) { |
| | | export(response, null, fileName, sheetMap, null); |
| | | } |
| | | |
| | | |
| | | public static void export(HttpServletResponse response, String fileName, String sheetName, |
| | | List<List<Object>> sheetDataList) { |
| | | export(response, fileName, sheetName, sheetDataList, null); |
| | | } |
| | | |
| | | public static void export(HttpServletResponse response, String fileName, String sheetName, |
| | | List<List<Object>> sheetDataList, Map<Integer, List<String>> selectMap) { |
| | | |
| | | Map<String, List<List<Object>>> map = new HashMap<>(); |
| | | map.put(sheetName, sheetDataList); |
| | | export(response, null, fileName, map, selectMap); |
| | | } |
| | | |
| | | public static <T, K> void export(HttpServletResponse response, String fileName, List<T> list, Class<K> template) { |
| | | // list æ¯å¦ä¸ºç©º |
| | | boolean lisIsEmpty = list == null || list.isEmpty(); |
| | | // å¦ææ¨¡æ¿æ°æ®ä¸ºç©ºï¼ä¸å¯¼å
¥çæ°æ®ä¸ºç©ºï¼å导åºç©ºæä»¶ |
| | | if (template == null && lisIsEmpty) { |
| | | exportEmpty(response, fileName); |
| | | return; |
| | | } |
| | | // 妿 list æ°æ®ï¼åå¯¼åºæ¨¡æ¿æ°æ® |
| | | if (lisIsEmpty) { |
| | | exportTemplate(response, fileName, template); |
| | | return; |
| | | } |
| | | // å¯¼åºæ°æ® |
| | | List<List<Object>> sheetDataList = getSheetData(list); |
| | | export(response, fileName, sheetDataList); |
| | | } |
| | | |
| | | public static void export(HttpServletResponse response, String fileName, List<List<Object>> sheetDataList, Map<Integer, List<String>> selectMap) { |
| | | export(response, fileName, fileName, sheetDataList, selectMap); |
| | | } |
| | | |
| | | private static void export(HttpServletResponse response, File file, String fileName, |
| | | Map<String, List<List<Object>>> sheetMap, Map<Integer, List<String>> selectMap) { |
| | | // æ´ä¸ª Excel è¡¨æ ¼ book 对象 |
| | | SXSSFWorkbook book = new SXSSFWorkbook(); |
| | | // æ¯ä¸ª Sheet 页 |
| | | Set<Entry<String, List<List<Object>>>> entries = sheetMap.entrySet(); |
| | | for (Entry<String, List<List<Object>>> entry : entries) { |
| | | List<List<Object>> sheetDataList = entry.getValue(); |
| | | Sheet sheet = book.createSheet(entry.getKey()); |
| | | Drawing<?> patriarch = sheet.createDrawingPatriarch(); |
| | | // è®¾ç½®è¡¨å¤´èæ¯è²ï¼ç°è²ï¼ |
| | | CellStyle headStyle = book.createCellStyle(); |
| | | headStyle.setFillForegroundColor(IndexedColors.GREY_80_PERCENT.index); |
| | | headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); |
| | | headStyle.setAlignment(HorizontalAlignment.CENTER); |
| | | headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index); |
| | | // è®¾ç½®è¡¨èº«èæ¯è²ï¼é»è®¤è²ï¼ |
| | | CellStyle rowStyle = book.createCellStyle(); |
| | | rowStyle.setAlignment(HorizontalAlignment.CENTER); |
| | | rowStyle.setVerticalAlignment(VerticalAlignment.CENTER); |
| | | // è®¾ç½®è¡¨æ ¼å宽度ï¼é»è®¤ä¸º15个åèï¼ |
| | | sheet.setDefaultColumnWidth(15); |
| | | // å建åå¹¶ç®æ³æ°ç» |
| | | int rowLength = sheetDataList.size(); |
| | | int columnLength = sheetDataList.get(0).size(); |
| | | int[][] mergeArray = new int[rowLength][columnLength]; |
| | | for (int i = 0; i < sheetDataList.size(); i++) { |
| | | // æ¯ä¸ª Sheet 页ä¸çè¡æ°æ® |
| | | Row row = sheet.createRow(i); |
| | | List<Object> rowList = sheetDataList.get(i); |
| | | for (int j = 0; j < rowList.size(); j++) { |
| | | // æ¯ä¸ªè¡æ°æ®ä¸çåå
æ ¼æ°æ® |
| | | Object o = rowList.get(j); |
| | | int v = 0; |
| | | if (o instanceof URL) { |
| | | // 妿è¦å¯¼åºå¾ççè¯, 龿¥éè¦ä¼ é URL 对象 |
| | | setCellPicture(book, row, patriarch, i, j, (URL) o); |
| | | } else { |
| | | Cell cell = row.createCell(j); |
| | | if (i == 0) { |
| | | // 第ä¸è¡ä¸ºè¡¨å¤´è¡ï¼éç¨ç°è²åºèæ¯ |
| | | v = setCellValue(cell, o, headStyle); |
| | | } else { |
| | | // å
¶ä»è¡ä¸ºæ°æ®è¡ï¼é»è®¤ç½åºè² |
| | | v = setCellValue(cell, o, rowStyle); |
| | | } |
| | | } |
| | | mergeArray[i][j] = v; |
| | | } |
| | | } |
| | | // åå¹¶åå
æ ¼ |
| | | mergeCells(sheet, mergeArray); |
| | | // è®¾ç½®ä¸æå表 |
| | | setSelect(sheet, selectMap); |
| | | } |
| | | // åæ°æ® |
| | | if (response != null) { |
| | | // åç«¯å¯¼åº |
| | | try { |
| | | write(response, book, fileName); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } else { |
| | | // æ¬å°å¯¼åº |
| | | FileOutputStream fos; |
| | | try { |
| | | fos = new FileOutputStream(file); |
| | | ByteArrayOutputStream ops = new ByteArrayOutputStream(); |
| | | book.write(ops); |
| | | fos.write(ops.toByteArray()); |
| | | fos.close(); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åå¹¶å½åSheet页çåå
æ ¼ |
| | | * |
| | | * @param sheet å½å sheet 页 |
| | | * @param mergeArray åå¹¶åå
æ ¼ç®æ³ |
| | | */ |
| | | private static void mergeCells(Sheet sheet, int[][] mergeArray) { |
| | | // 横ååå¹¶ |
| | | for (int x = 0; x < mergeArray.length; x++) { |
| | | int[] arr = mergeArray[x]; |
| | | boolean merge = false; |
| | | int y1 = 0; |
| | | int y2 = 0; |
| | | for (int y = 0; y < arr.length; y++) { |
| | | int value = arr[y]; |
| | | if (value == CELL_COLUMN_MERGE) { |
| | | if (!merge) { |
| | | y1 = y; |
| | | } |
| | | y2 = y; |
| | | merge = true; |
| | | } else { |
| | | merge = false; |
| | | if (y1 > 0) { |
| | | sheet.addMergedRegion(new CellRangeAddress(x, x, (y1 - 1), y2)); |
| | | } |
| | | y1 = 0; |
| | | y2 = 0; |
| | | } |
| | | } |
| | | if (y1 > 0) { |
| | | sheet.addMergedRegion(new CellRangeAddress(x, x, (y1 - 1), y2)); |
| | | } |
| | | } |
| | | // 纵ååå¹¶ |
| | | int xLen = mergeArray.length; |
| | | int yLen = mergeArray[0].length; |
| | | for (int y = 0; y < yLen; y++) { |
| | | boolean merge = false; |
| | | int x1 = 0; |
| | | int x2 = 0; |
| | | for (int x = 0; x < xLen; x++) { |
| | | int value = mergeArray[x][y]; |
| | | if (value == CELL_ROW_MERGE) { |
| | | if (!merge) { |
| | | x1 = x; |
| | | } |
| | | x2 = x; |
| | | merge = true; |
| | | } else { |
| | | merge = false; |
| | | if (x1 > 0) { |
| | | sheet.addMergedRegion(new CellRangeAddress((x1 - 1), x2, y, y)); |
| | | } |
| | | x1 = 0; |
| | | x2 = 0; |
| | | } |
| | | } |
| | | if (x1 > 0) { |
| | | sheet.addMergedRegion(new CellRangeAddress((x1 - 1), x2, y, y)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static void write(HttpServletResponse response, SXSSFWorkbook book, String fileName) throws IOException { |
| | | response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); |
| | | response.setCharacterEncoding("utf-8"); |
| | | String name = new String(fileName.getBytes("GBK"), "ISO8859_1") + XLSX; |
| | | response.addHeader("Content-Disposition", "attachment;filename=" + name); |
| | | ServletOutputStream out = response.getOutputStream(); |
| | | book.write(out); |
| | | out.flush(); |
| | | out.close(); |
| | | } |
| | | |
| | | private static int setCellValue(Cell cell, Object o, CellStyle style) { |
| | | // è®¾ç½®æ ·å¼ |
| | | cell.setCellStyle(style); |
| | | // æ°æ®ä¸ºç©ºæ¶ |
| | | if (o == null) { |
| | | cell.setCellType(CellType.STRING); |
| | | cell.setCellValue(""); |
| | | return CELL_OTHER; |
| | | } |
| | | // æ¯å¦ä¸ºå符串 |
| | | if (o instanceof String) { |
| | | String s = o.toString(); |
| | | // 彿°åç±»åé¿åº¦è¶
è¿8使¶ï¼æ¹ä¸ºåç¬¦ä¸²ç±»åæ¾ç¤ºï¼Excelæ°åè¶
è¿ä¸å®é¿åº¦ä¼æ¾ç¤ºä¸ºç§å¦è®¡æ°æ³ï¼ |
| | | if (isNumeric(s) && s.length() < 8) { |
| | | cell.setCellType(CellType.NUMERIC); |
| | | cell.setCellValue(Double.parseDouble(s)); |
| | | return CELL_OTHER; |
| | | } else { |
| | | cell.setCellType(CellType.STRING); |
| | | cell.setCellValue(s); |
| | | } |
| | | if (s.equals(ROW_MERGE)) { |
| | | return CELL_ROW_MERGE; |
| | | } else if (s.equals(COLUMN_MERGE)) { |
| | | return CELL_COLUMN_MERGE; |
| | | } else { |
| | | return CELL_OTHER; |
| | | } |
| | | } |
| | | // æ¯å¦ä¸ºå符串 |
| | | if (o instanceof Integer || o instanceof Long || o instanceof Double || o instanceof Float) { |
| | | cell.setCellType(CellType.NUMERIC); |
| | | cell.setCellValue(Double.parseDouble(o.toString())); |
| | | return CELL_OTHER; |
| | | } |
| | | // æ¯å¦ä¸ºBoolean |
| | | if (o instanceof Boolean) { |
| | | cell.setCellType(CellType.BOOLEAN); |
| | | cell.setCellValue((Boolean) o); |
| | | return CELL_OTHER; |
| | | } |
| | | // 妿æ¯BigDecimalï¼åé»è®¤3ä½å°æ° |
| | | if (o instanceof BigDecimal) { |
| | | cell.setCellType(CellType.NUMERIC); |
| | | cell.setCellValue(((BigDecimal) o).setScale(3, RoundingMode.HALF_UP).doubleValue()); |
| | | return CELL_OTHER; |
| | | } |
| | | // 妿æ¯Dateæ°æ®ï¼åæ¾ç¤ºæ ¼å¼åæ°æ® |
| | | if (o instanceof Date) { |
| | | cell.setCellType(CellType.STRING); |
| | | cell.setCellValue(formatDate((Date) o)); |
| | | return CELL_OTHER; |
| | | } |
| | | // 妿æ¯å
¶ä»ï¼åé»è®¤å符串类å |
| | | cell.setCellType(CellType.STRING); |
| | | cell.setCellValue(o.toString()); |
| | | return CELL_OTHER; |
| | | } |
| | | |
| | | private static void setCellPicture(SXSSFWorkbook wb, Row sr, Drawing<?> patriarch, int x, int y, URL url) { |
| | | // 设置å¾çå®½é« |
| | | sr.setHeight((short) (IMG_WIDTH * IMG_HEIGHT)); |
| | | // ï¼jdk1.7çæ¬tryä¸å®ä¹æµå¯èªå¨å
³éï¼ |
| | | try (InputStream is = url.openStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { |
| | | byte[] buff = new byte[BYTES_DEFAULT_LENGTH]; |
| | | int rc; |
| | | while ((rc = is.read(buff, 0, BYTES_DEFAULT_LENGTH)) > 0) { |
| | | outputStream.write(buff, 0, rc); |
| | | } |
| | | // 设置å¾çä½ç½® |
| | | XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, y, x, y + 1, x + 1); |
| | | // 设置è¿ä¸ªï¼å¾çä¼èªå¨å¡«æ»¡åå
æ ¼çé¿å®½ |
| | | anchor.setAnchorType(AnchorType.MOVE_AND_RESIZE); |
| | | patriarch.createPicture(anchor, wb.addPicture(outputStream.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG)); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | private static String formatDate(Date date) { |
| | | if (date == null) { |
| | | return ""; |
| | | } |
| | | SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT); |
| | | return format.format(date); |
| | | } |
| | | |
| | | private static void setSelect(Sheet sheet, Map<Integer, List<String>> selectMap) { |
| | | if (selectMap == null || selectMap.isEmpty()) { |
| | | return; |
| | | } |
| | | Set<Entry<Integer, List<String>>> entrySet = selectMap.entrySet(); |
| | | for (Entry<Integer, List<String>> entry : entrySet) { |
| | | int y = entry.getKey(); |
| | | List<String> list = entry.getValue(); |
| | | if (list == null || list.isEmpty()) { |
| | | continue; |
| | | } |
| | | String[] arr = new String[list.size()]; |
| | | for (int i = 0; i < list.size(); i++) { |
| | | arr[i] = list.get(i); |
| | | } |
| | | DataValidationHelper helper = sheet.getDataValidationHelper(); |
| | | CellRangeAddressList addressList = new CellRangeAddressList(1, 65000, y, y); |
| | | DataValidationConstraint dvc = helper.createExplicitListConstraint(arr); |
| | | DataValidation dv = helper.createValidation(dvc, addressList); |
| | | if (dv instanceof HSSFDataValidation) { |
| | | dv.setSuppressDropDownArrow(false); |
| | | } else { |
| | | dv.setSuppressDropDownArrow(true); |
| | | dv.setShowErrorBox(true); |
| | | } |
| | | sheet.addValidationData(dv); |
| | | } |
| | | } |
| | | |
| | | private static boolean isNumeric(String str) { |
| | | if(StringUtils.isEmpty(str)){ |
| | | return false; |
| | | } |
| | | if (Objects.nonNull(str) && "0.0".equals(str)) { |
| | | return true; |
| | | } |
| | | for (int i = str.length(); --i >= 0; ) { |
| | | if (!Character.isDigit(str.charAt(i))) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | private static String getString(String s) { |
| | | if (s == null) { |
| | | return ""; |
| | | } |
| | | if (s.isEmpty()) { |
| | | return s; |
| | | } |
| | | return s.trim(); |
| | | } |
| | | |
| | | } |