Bootstrap

Excel操作之工具类

需求:根据指定的路径下模版进行解析 将模版上传到指定的文件服务器。
1:将路径下的excel文件进行解析 下载

A:创建excel表格对应的字段注解 ExcelColumn

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelColumn {
    int index() default -1; // 列的索引,从0开始

    String name() default ""; // 列名,可以与Excel中的标题对应

}

B:建立一个excel映射的实体对象

@ExcelColumn(index = 1, name = "A")
private String A;
@ExcelColumn(index = 2, name = "B")
private String B;

上述的属性A B的index对应excel的标题头的第几列的字段值
C:为了方便后续解析任意的excel文件 故创建一个文件解析工具 ExcelParserUtil.java

/**
     * excel解析工具类
     *
     * @param inputStream
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> parseExcel(InputStream inputStream, Class<T> clazz) throws Exception {
        List<T> result = new ArrayList<>();
        List<String> failReasonList = new ArrayList<>();
        int execRow = 1;
        try (Workbook workbook = new XSSFWorkbook(inputStream)) {
            Sheet sheet = workbook.getSheetAt(0); //第一个工作表
            Row headerRow = sheet.getRow(0); //第一行是标题行
            // 读取实体类的字段注解,构建字段名和列索引的映射
            Map<String, Integer> fieldIndexMap = new HashMap<>();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                ExcelColumn excelColumn = field.getAnnotation(ExcelColumn.class);
                if (excelColumn != null && excelColumn.index() >= 0) {
                    field.setAccessible(true);
                    fieldIndexMap.put(field.getName(), excelColumn.index());
                }
            }

            // 跳过标题行,从第二行开始解析数据
            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                T instance = clazz.getDeclaredConstructor().newInstance();
                for (Map.Entry<String, Integer> entry : fieldIndexMap.entrySet()) {
                    try {
                        String fieldName = entry.getKey();
                        int columnIndex = entry.getValue();
                        Cell cell = row.getCell(columnIndex);
                        if (cell != null) {
                            Field field = clazz.getDeclaredField(fieldName);
                            setFieldValue(instance, field, cell);
                        }
                    } catch (Exception e) {
                        failReasonList.add("第" + execRow + "行解析错误:" + e.getMessage());
                    }
                }
                execRow++;
                result.add(instance);
            }
        } catch (Exception e) {
            throw new Exception("parseExcel->数据解析错误:", e);
        }
        if (CollectionUtils.isNotEmpty(failReasonList)) {
            throw new Exception(JSON.toJSONString(failReasonList.subList(0, failReasonList.size() > 20 ? 20 : failReasonList.size())));
        }
        return result;
    }
/**
     * 方法setFieldValue 主要用于给每个单元格进行设置对应的值。
     * @param instance
     * @param field
     * @param cell
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */

    private static void setFieldValue(Object instance, Field field, Cell cell) throws IllegalAccessException, InvocationTargetException {
        Class<?> fieldType = field.getType();
        field.setAccessible(true);
        // 总是将Cell设置为STRING类型,以确保我们可以获取字符串值
        cell.setCellType(CellType.STRING);
        String cellValue = cell.getStringCellValue();
        if (String.class.equals(fieldType)) {
            field.set(instance, cell.getStringCellValue());
        } else if (Integer.class.equals(fieldType) || int.class.equals(fieldType)) {
            field.setInt(instance, Integer.parseInt(cellValue));
        } else if (Long.class.equals(fieldType) || long.class.equals(fieldType)) {
            field.setLong(instance, Long.parseLong(cellValue));
        } else if (Double.class.equals(fieldType) || double.class.equals(fieldType)) {
            field.setDouble(instance, Double.parseDouble(cellValue));
        } else if (Boolean.class.equals(fieldType) || boolean.class.equals(fieldType)) {
            field.setBoolean(instance, Boolean.parseBoolean(cellValue));
        } else {
            throw new RuntimeException("Unsupported field type: " + fieldType.getName());
        }
    }

  /**
     * 指定下载的文件路径 将文件流保存到执行的的位置
     *
     * @param url
     * @param savePath
     * @return
     */
    public static String download(String url, String savePath) {
        InputStream inputStream = null;
        FileOutputStream fos = null;
        try {
            URL u = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) u.openConnection();
            //设置超时间为3秒
            conn.setConnectTimeout(HTTP_CONNECT_TIMEOUT);
            //防止屏蔽程序抓取而返回403错误
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            //得到输入流
            inputStream = conn.getInputStream();
            //获取自己数组
            byte[] getData = readInputStream(inputStream);
            File file = new File(savePath);
//            文件保存位置
            createDir(file);
            fos = new FileOutputStream(file);
            fos.write(getData);
        } catch (IOException e) {
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
            }
        }
        return savePath;
    }


  /**
     * 从输入流中获取字节数组
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    private static byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }


 /**
     * 根据文件创建目录
     *
     * @param file
     */
    public static void createDir(File file) {
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
    }

D:使用上述工具类进行文件的解析和下载功能演练

//下载路径
    private static final String downloadUrl = "https://xxx.com.cn/files/";
    //模版位置
    private static final String templateUrl = "E:/source";
    //下载文件存放位置
    private static final String saveUrl = "E:/source/downlod";
    private static final String handCompany = "1-A.xlsx";
    private static final String company = "2-B.xlsx";
    private static final String industry = "3-C.xlsx";

public static void main(String[] args) {
        ExcelParserUtil parser = new ExcelParserUtil();
        try {
            File file = new File(templateUrl); // 替换为你的文件路径
            File[] files = file.listFiles();
            for (File fileItem : files) {
                if (fileItem.isFile()) {
                    InputStream inputStream = new FileInputStream(fileItem);
                    if (inputStream != null) {
                        String fileName = fileItem.getName();
                        List<ExcelEntity> excelEntities = parser.parseExcel(inputStream, ExcelEntity.class);
                        exec(excelEntities, parser, fileName);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

private static void exec(List<ExcelEntity> entityList, ExcelParserUtil parser, String fileName) {
        List<String> list = new ArrayList<>();
        // 输出解析结果
        System.out.println("解析了数据:" + entityList.size());
        for (ExcelEntity entity : entityList) {
            //得到解析的文件数据做自己的业务逻辑处理。
            String finalUrl = downloadUrl + fileUrl;
            //处理投资池证券导入模板文件路径字段
            String download = parser.download(finalUrl, saveUrl + File.separator + "新的文件名称");
         
        }
    }

2:上传文件到执行服务器

/**
	 * 上传文件
	 * @param filePath
	 * @param typeId
	 * @return
	 */
	public static R upload(String filePath, String typeId) {
		
		CloseableHttpClient httpClient = HttpClientBuilder.create().build();
		CloseableHttpResponse httpResponse = null;
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(200000).setSocketTimeout(200000000).build();
		HttpPost httpPost = new HttpPost(baseUrl + PREFIX + "/service/files/upload");
		httpPost.setConfig(requestConfig);
		MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
		multipartEntityBuilder.setCharset(Charset.forName("UTF-8"));
		File file = new File(filePath);
		if (FrameStringUtil.isNotEmpty(typeId)) {
			multipartEntityBuilder.addPart("typeId", new StringBody(typeId, ContentType.create("text/plain", Consts.UTF_8)));
		}
		
	
		HttpEntity httpEntity = multipartEntityBuilder.build();
		httpPost.setEntity(httpEntity);

		try {
			httpResponse = httpClient.execute(httpPost);
			HttpEntity responseEntity = httpResponse.getEntity();
			int statusCode= httpResponse.getStatusLine().getStatusCode();
			if(statusCode == 200) {
				BufferedReader reader = new BufferedReader(new InputStreamReader(responseEntity.getContent()));
				StringBuffer buffer = new StringBuffer();
				String str = "";
				while(FrameStringUtil.isNotEmpty(str = reader.readLine())) {
					buffer.append(str);
				}

				String result = buffer.toString();
				R.setBody(result);
				R.setSucc();
				
				
				//post(url, params);
			}
			httpClient.close();
			if(httpResponse != null) {
				httpResponse.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
			R.setCode(-1001);
			R.setMessage("上传文件到文件管理服务失败: " + e.getMessage());
		}
		return R;
	}

3:文件基础相关操作

/**
     * 删除指定零时目录下的文件
     *
     * @param sourceUrl
     * @param destinationUrl
     * @param fileName
     * @return
     */
public static Boolean deleteFilesInDirectory(String tempUrl) {
        Boolean delFlag = false;
        File directory = new File(tempUrl);
        if (directory.exists() && directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isFile()) {
                        file.delete();
                        delFlag = true;
                        log.info("Deleted file: {}", file.getName());
                    }
                }
            } else {
                log.info("The directory is empty.....");
                delFlag = false;
            }
        } else {
            delFlag = false;
            log.info("The directory does not exist or is not a directory.");
        }
        return delFlag;
    }
/**
     * 将byte[]转成File
     *
     * @param sourceUrl
     * @param destinationUrl
     * @param fileName
     * @return
     */
    public static File byteToFile(byte[] bytes, String path, String name) throws IOException {
        File dir = new File(path);
        if (!dir.exists() && !dir.isDirectory()) {//判断文件目录是否存在
            dir.mkdirs();
        }

        File file = new File(path + File.separator + name);
        FileOutputStream fout = new FileOutputStream(file);
        BufferedOutputStream bout = new BufferedOutputStream(fout);
        bout.write(bytes);
        return file;
    }
 /**
     * 文件复制转移
     *
     * @param sourceUrl
     * @param destinationUrl
     * @param fileName
     * @return
     */
    public static String copyFile(String sourceUrl, String destinationUrl, String fileName) {
        String fileTempUrl = "";
        File sourceFile = new File(sourceUrl);
        fileTempUrl = destinationUrl + File.separator + fileName;
        File destinationFile = new File(fileTempUrl);
        try {
            FileUtils.copyFile(sourceFile, destinationFile);
            log.info("文件复制成功!");
        } catch (IOException e) {
            log.info("文件复制失败!");
            System.out.println("文件复制失败!" + e.getMessage());
        }
        return fileTempUrl;
    }

4:文件相关操作工具类

/**
	 * 创建指定路径的文件夹[不存在,则创建]
	 * @param destDirName
	 */
	public static void createDir(String destDirName) {
		File dir = new File(destDirName);
		if(dir.exists()) {
			LOGGER.info("目录" + destDirName + "已存在!");
		} else {
			if(!destDirName.endsWith(File.separator)) {
				destDirName = destDirName + File.separator;
			}
			//创建目录
			dir.mkdirs();
		}
	}
/**
	 * 读取文件[不存在,则创建]
	 * @param destFileName 文件名
	 * @return 创建成功返回true,否则返回false
	 * @throws IOException
	 */
	public static File readFile(String destFileName) throws IOException {
		File file = new File(destFileName);
		if (file.exists()) {
			//LOGGER.info("目标文件已存在: " + destFileName);
			return file;
		}
		if (!file.getParentFile().exists()) {
			if (!file.getParentFile().mkdirs()) {
				LOGGER.info("创建目录文件所在的目录失败!");
			}
		}
		//创建目标文件
		if (file.createNewFile()) {
			LOGGER.info("创建单个文件成功: " + destFileName);
		} else {
			LOGGER.info("创建单个文件失败: " + destFileName);
		}
		return file;
	}
/**
	 * 读取文件为byte[]
	 * @param destFileName
	 * @return
	 */
	public static byte[] readFileBytes(String destFileName) {
		try {
			BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(destFileName));
			int len = bufferedInputStream.available();
			byte[] bytes = new byte[len];
			int r = bufferedInputStream.read(bytes);
			if (len != r) {
				bytes = null;
				LOGGER.error("读取文件不正确");
			}
			bufferedInputStream.close();
			return bytes;
		} catch (FileNotFoundException e) {
			LOGGER.error(e.getMessage(), e);
		}
		catch (IOException e) {
			LOGGER.error(e.getMessage(), e);
		}
		return null;
	}
/**
	 * 根据目录获取下面为指定文件名的文件
	 * @param dir
	 * @param filename
	 * @return
	 */
	public static List<String> getFiles(String dir, String filename) {
		List<String> list = new ArrayList<String>();
		Map<String, List<String>> map = getDirFile(dir, true);
		List<String> allList = map.get("files");
		if(allList == null) {
			list = new ArrayList<String>();
		} else {
			for (String string : allList) {
				if(string.endsWith(File.separator + filename)) {
					list.add(string);
				}
			}
		}
		return list;
	}
/**
	 * 获取目录下的文件和文件夹
	 * @param dir
	 * @param isRecursion	是否递归,true是 false否
	 * @return {"files":["文件地址",""],"dirs":["目录地址",""]}
	 */
	public static Map<String, List<String>> getDirFile(String dir, boolean isRecursion) {
		Map<String, List<String>> map = new HashMap<String, List<String>>();
		File file = new File(dir);
		getDirFileDtl(file, map, isRecursion);
		return map;
	}
/*
	 * 获取目录的指定内容
	 * @param file
	 * @param map
	 */
	private static void getDirFileDtl(File file, Map<String, List<String>> map, boolean isRecursion) {
		File[] t = file.listFiles();
		if(t == null) {
			return;
		}
		for(int i = 0; i < t.length; i++){
			//判断文件列表中的对象是否为文件夹对象,如果是则执行tree递归,直到把此文件夹中所有文件输出为止
			if(t[i].isDirectory()) {
				List<String> dirs = map.get("dirs");
				if(dirs == null) {
					dirs = new ArrayList<String>();
				}
				dirs.add(t[i].getAbsolutePath());
				//System.out.println(t[i].getAbsolutePath()+"\n");
				map.put("dirs", dirs);
				if(isRecursion) {
					getDirFileDtl(t[i], map, isRecursion);
				}
			} else{
				List<String> files = map.get("files");
				if(files == null) {
					files = new ArrayList<String>();
				}
				files.add(t[i].getAbsolutePath());
				//System.out.println(t[i].getAbsolutePath()+"\n");
				map.put("files", files);
				getDirFileDtl(t[i], map, isRecursion);
			}
		}
	}

/**
	 * 读取http地址的文件到指定位置
	 * @param url
	 * @param savePath
	 * @param saveName
	 * @return
	 */
	public static File readFile(String url, String savePath, String saveName) {
		try {
			//new一个URL对象
			URL u = new URL(url);
			//打开链接
			HttpURLConnection conn = (HttpURLConnection)u.openConnection();
			//设置请求方式为"GET"
			conn.setRequestMethod("GET");
			//超时响应时间为5秒
			conn.setConnectTimeout(5 * 1000);
			//通过输入流获取图片数据
			InputStream inStream = conn.getInputStream();
			//得到图片的二进制数据,以二进制封装得到数据,具有通用性
			byte[] data = readFileBytes(inStream);

			//new一个文件对象用来保存图片,默认保存当前工程根目录
			createDir(savePath);
			File file = new File(savePath + saveName);
			if(file.exists()) {
				file.delete();
			}
			file = new File(savePath + saveName);
			//创建输出流
			FileOutputStream outStream = new FileOutputStream(file);
			//写入数据
			outStream.write(data);
			//关闭输出流
			outStream.close();
			return file;
		} catch (IOException e) {
			LOGGER.error("读取异常", e);
		}
		return null;
	}

/**
     * 创建ZIP文件
     * @param sourcePath 文件或文件夹路径
     * @param zipPath 生成的zip文件存在路径(包括文件名)
     */
    public static boolean createZip(String sourcePath, String zipPath) {
        FileOutputStream fos = null;
        ZipOutputStream zos = null;
        try {
            fos = new FileOutputStream(zipPath);
            zos = new ZipOutputStream(fos);
            writeZip(new File(sourcePath), "", zos);
        } catch (FileNotFoundException e) {
        	LOGGER.error("创建ZIP文件失败", e);
        	return false;
        } finally {
            try {
                if (zos != null) {
                    zos.close();
                }
            } catch (IOException e) {
            	LOGGER.error("创建ZIP文件失败",e);
            }

        }
        return true;
    }
private static void writeZip(File file, String parentPath, ZipOutputStream zos) {
        if(file.exists()){
            if(file.isDirectory()){//处理文件夹
                parentPath+=file.getName()+File.separator;
                File [] files=file.listFiles();
                for(File f:files){
                    writeZip(f, parentPath, zos);
                }
            }else{
                FileInputStream fis=null;
                DataInputStream dis=null;
                try {
                    fis=new FileInputStream(file);
                    dis=new DataInputStream(new BufferedInputStream(fis));
                    ZipEntry ze = new ZipEntry(parentPath + file.getName());
                    zos.putNextEntry(ze);
                    byte [] content=new byte[1024];
                    int len;
                    while((len=fis.read(content))!=-1){
                        zos.write(content,0,len);
                        zos.flush();
                    }

                } catch (FileNotFoundException e) {
                    LOGGER.error("创建ZIP文件失败",e);
                } catch (IOException e) {
                	LOGGER.error("创建ZIP文件失败",e);
                }finally{
                    try {
                        if(dis!=null){
                            dis.close();
                        }
                    }catch(IOException e) {
                    	LOGGER.error("创建ZIP文件失败",e);
                    }
                }
            }
        }
    }    
/**
	 * 公用下载文件<br>
	 * frame 返回路径和文件名称
	 * 		fileName:下载文件的名称
	 * 		downloadPath:下载文件的路径
	 * @param request
	 * @param response
	 * @param frame
	 * @throws IOException 
	 */
	public void download(HttpServletRequest request, HttpServletResponse response,
			String fileName, String downloadPath) throws IOException {
		response.setContentType("text/html;charset=UTF-8");
		try {
			request.setCharacterEncoding("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		
		if(FrameStringUtil.isEmpty(fileName) || FrameStringUtil.isEmpty(downloadPath)) {
			return;
		}

		long fileLength = new File(downloadPath).length();
		response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes("utf-8"),"iso-8859-1"));
		response.setHeader("Content-Length", String.valueOf(fileLength));

		bis = new BufferedInputStream(new FileInputStream(downloadPath));
		bos = new BufferedOutputStream(response.getOutputStream());
		byte[] buff = new byte[2048];
		int bytesRead;
		while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
			bos.write(buff, 0, bytesRead);
		}
		bis.close();
		bos.close();
	}
 /**
     * @param workbook      Excel
     * @param sheetName     工作簿名称
     * @param cellFieldList 字段列表
     * @param rowList       数据列表
     * @throws Exception
     * @description: 向Excel中写入数据
     */
    public static <T> void writeExcel(XSSFWorkbook workbook, String sheetName, List<CellField> cellFieldList, List<T> rowList, Map<String, Object> rowData, int type)  {
        if (StringUtils.isRealEmpty(sheetName)) {
            sheetName = "Sheet1";
        }
        Sheet sheet = workbook.createSheet(sheetName);
        Font boldFont = createFont(workbook, true, "宋体", false, (short) 200);
        Font normalFont = createFont(workbook, false, "宋体", false, (short) 200);

        try {
            // 标题(第一行)
            Row titleRow = sheet.createRow(0);
            int cellNumber = cellFieldList.size();
            for (int i = 0; i < cellNumber; i++) {
                CellField cellField = cellFieldList.get(i);
                createCell(workbook, titleRow, i, cellField.getName(), CellType.STRING, boldFont);

                // 设置单元格宽带
                sheet.setColumnWidth(i, 256 * cellField.getWidth() + 184);
            }

            if (type == 0) {
                // 内容(第1-N行)
                Integer rowNumber = 1;
                for (int i = 0, length = rowList.size(); i < length; i++) {
                    T t = rowList.get(i);
                    Row row = sheet.createRow(rowNumber);
                    for (int j = 0; j < cellNumber; j++) {
                        Field field = getDeclaredField(t, cellFieldList.get(j).getCode());
                        field.setAccessible(true);
                        createCell(workbook, row, j, field.get(t), CellType.STRING, normalFont);
                    }
                    rowNumber++;
                }
            } else if (type == 1) {
                // 内容(第1-N行)
                Integer rowNumber = 1;
                Row row = sheet.createRow(rowNumber);
                for (int i = 0; i < cellNumber; i++) {
                    CellField cellField = cellFieldList.get(i);
                    createCell(workbook, row, i, rowData.get(cellField.getCode()), CellType.STRING, normalFont);
                }
            }
        } catch (Exception e) {
        //    e.printStackTrace();
            throw new CustomException(e.getMessage(), e);
        }
    }
    //上述方法在调用是使用如下的参考
    @RequestMapping("/trms/exportRedisStatis")
    public ResponseEntity<byte[]> exportRedisStatis() {
        ResponseEntity<byte[]> output = null;
        ByteArrayOutputStream byteOutputStream = null;
        try (XSSFWorkbook workbook = new XSSFWorkbook()) {
            List<RedisStatis> redisStatis = dbSyncBuilder.redisStatis();
            byteOutputStream = new ByteArrayOutputStream();
            List<CellField> cellFieldList = new ArrayList<>();
            cellFieldList.add(new CellField("表名", "table"));
            cellFieldList.add(new CellField("名称", "desc"));
            cellFieldList.add(new CellField("总条数", "cnt"));
            cellFieldList.add(new CellField("占用内存(单位:字节)", "memory"));
            ExcelUtils.writeExcel(workbook, "shut名称", cellFieldList, redisStatis, null, 0);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentDispositionFormData("attachment",
                    new String("shut-key数据统计".getBytes("GBK"), StandardCharsets.ISO_8859_1) + ".xlsx");
            workbook.write(byteOutputStream);
            output = new ResponseEntity<>(byteOutputStream.toByteArray(), headers, HttpStatus.OK);
        } catch (Exception ex) {
            log.error("导出shut统计结果异常", ex);
            throw new CustomException("导出shut统计结果异常");
        } finally {
            try {
                if (byteOutputStream != null) {
                    byteOutputStream.close();
                }
            } catch (IOException e) {
                log.error("关闭输出流失败", e);
            }
        }
        return output;
    }

以上的是Excel操作之工具类 若需完整代码 可识别二维码后 给您发代码。
在这里插入图片描述

;