Java實現(xiàn)批量導(dǎo)出導(dǎo)入數(shù)據(jù)及附件文件zip包
前言-應(yīng)用場景
某系統(tǒng)在不同單位使用時存在兩套生產(chǎn)環(huán)境,他們的數(shù)據(jù)不是互通的,所以這些單位的上一級領(lǐng)導(dǎo)部門在統(tǒng)計數(shù)據(jù)的時候希望將A系統(tǒng)的數(shù)據(jù)和附件信息導(dǎo)出到一個壓縮包里,然后把這個壓縮包一鍵導(dǎo)入到B系統(tǒng),這樣B系統(tǒng)就包含了全部的數(shù)據(jù),上級領(lǐng)導(dǎo)就能看到全部的業(yè)務(wù)信息,便于統(tǒng)計分析。
一、導(dǎo)出ZIP包
1. 列表數(shù)據(jù)導(dǎo)出到本地excel文件
String path = profile + "/temp/" + DateUtils.dateTimeNow();
File file = new File(path);
if (file.mkdirs()) {
System.out.println("文件夾創(chuàng)建成功!創(chuàng)建后的文件目錄為:" + file.getPath());
}
//1. 輸出Excel文件
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("sheet");
String fileName="XX數(shù)據(jù)導(dǎo)出.xls";
String savePath= file.getPath() + File.separator +fileName;
OutputStream os = new FileOutputStream(savePath);
//響應(yīng)到客戶端(即瀏覽器端直接彈出下載連接的方式)需要用response獲取流
//this.setResponseHeader(response, filename);
//OutputStream os = response.getOutputStream();
List<HashMap> dataList = new ArrayList<>();
try{
// 表頭
this.createExcelTitle(workbook, sheet);
// 查詢條件
HashMap param = this.buildQueryParams(params);
dataList = shareRegisterMapper.shareList(param);
if (CollectionUtils.isEmpty(dataList)){
return;
}
this.dealAssetData(dataList, sheet);
// 處理子表數(shù)據(jù)
this.dealAssetDetailData(dataList,workbook);
workbook.write(os);
os.flush();
os.close();
}catch(Exception e) {
e.printStackTrace();
??????? }finally {
if (os != null) {
os.flush();
os.close();
}
workbook.close();
}2. 下載附件信息
在上一步生成的Excel文件路徑下新建files文件夾,里面存放附件
public void downloadFile(List<HashMap> dataList) throws Exception {
String urlPrefix = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
String savePath = file.getPath() + File.separator + "/files";
OutputStream os = null;
InputStream is = null;
int i=0;
try {
for (HashMap data : dataList) {
if (data == null || data.get("FILES") == null){
continue;
}
List<ZsglFileEntity> entityList = new ArrayList<>();
String[] fileArray = data.get("FILES").toString().split(",");
List idList = Arrays.asList(fileArray);
entityList.addAll(fileMapper.selectByIds(idList));
if (CollectionUtils.isNotEmpty(entityList)){
for (ZsglFileEntity file : entityList){
if ( file.getFssFileId() == null){
continue;
}
String fileUrl = urlPrefix + "/fss/download/" + file.getFssFileId();
// 構(gòu)造URL
URL url = new URL(fileUrl);
// 打開連接
URLConnection con = url.openConnection();
//設(shè)置請求超時為5s
con.setConnectTimeout(5 * 1000);
// 輸入流
is = con.getInputStream();
File tempFile = new File(savePath + "/"+file.getFileName());
// 校驗文件夾目錄是否存在,不存在就創(chuàng)建一個目錄
if (!tempFile.getParentFile().exists()) {
tempFile.getParentFile().mkdirs();
}
os = new FileOutputStream(tempFile);
is = con.getInputStream();
con.getHeaderFields();
IOUtils.copy(is, os);
System.out.println("下載完成");
}
entityList.clear();
}
}
}catch (IOException e){
System.err.println(e);
}finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
}3. 生成壓縮文件(瀏覽器下載)
response.setCharacterEncoding("UTF-8");
response.setContentType("multipart/form-data");
response.setHeader("content-disposition", "attachment;filename=" + "XX數(shù)據(jù)導(dǎo)出.zip");
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
try {
File[] sourceFiles = file.listFiles();
if (null == sourceFiles || sourceFiles.length < 1) {
System.out.println("待壓縮的文件目錄:" + "里面不存在文件,無需壓縮.");
} else {
for (int i = 0; i < sourceFiles.length;i++){
File srcFile = sourceFiles[i];
if (srcFile.isDirectory()){
File[] imageSourceFiles = srcFile.listFiles();
if (null == imageSourceFiles || imageSourceFiles.length < 1){
continue;
}
for (File imageFile : imageSourceFiles){
compress(zos,imageFile,srcFile.getName()+"/");
}
} else {
compress(zos,srcFile,"");
}
}
}
}catch (Exception e){
e.printStackTrace();
} finally {
//關(guān)閉流
try {
if(null != zos) {
zos.close();
}
} catch (IOException e){
e.printStackTrace();
}
}其中的壓縮方法如下:
public void compress(ZipOutputStream out,File sourceFile,String base) throws Exception
{
out.putNextEntry( new ZipEntry(base+sourceFile.getName()) );
FileInputStream fos = new FileInputStream(sourceFile);
BufferedInputStream bis = new BufferedInputStream(fos);
int tag;
System.out.println(base);
//將源文件寫入到zip文件中
while((tag=bis.read())!=-1) {
out.write(tag);
out.flush();
}
out.closeEntry();
bis.close();
fos.close();
}4. 刪除臨時目錄
public void deleteDirectory(File file) {
File[] list = file.listFiles(); //無法做到list多層文件夾數(shù)據(jù)
if (list != null) {
for (File temp : list) { //先去遞歸刪除子文件夾及子文件
deleteDirectory(temp); //注意這里是遞歸調(diào)用
}
}
if (!file.delete()) { //再刪除自己本身的文件夾
logger.error("文件刪除失敗 : %s%n", file);
}
}
二、導(dǎo)入ZIP包
1. 上傳zip包,解壓到臨時目錄
這里開始想著在不解壓的情況下讀取里面的文件,結(jié)果沒有走通。因為zip里面包含了子文件夾里面的附件信息需要解析。不解壓直接解析文件適用于只需要解析zip包中第一層文件的場景,如果子文件夾下的文件也需要處理的話,最好解壓后再處理。
public void unzip(ZipInputStream zipIn, String destDirectory) throws IOException {
File destDir = new File(destDirectory);
if (!destDir.exists()) {
destDir.mkdirs();
}
ZipEntry entry = zipIn.getNextEntry();
// 遍歷Zip文件中的條目
while (entry != null) {
String filePath = destDirectory + File.separator + entry.getName();
if (!entry.isDirectory()) {
int index = entry.getName().indexOf("/");
if (index > -1 && entry.getName().length() > index){
File tempFile = new File(destDirectory + File.separator +entry.getName().substring(0,index));
if (!tempFile.exists()){
tempFile.mkdir();
}
}
File checkFile = new File(filePath);
if (!checkFile.exists()) {
checkFile.createNewFile();// 創(chuàng)建目標文件
}
// 如果條目是文件直接解壓
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
byte[] bytesIn = new byte[1024];
int read = 0;
while ((read = zipIn.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
bos.close();
} else {
File dir = new File(filePath);
if (!dir.exists()){
dir.mkdirs();
}
}
zipIn.closeEntry();
entry = zipIn.getNextEntry();
}
zipIn.close();
}這里解壓遇到了一個問題,之前導(dǎo)出生成的zip包直接導(dǎo)入沒問題,但是我把導(dǎo)出的包手動解壓后修改了部分數(shù)據(jù)重新壓縮后再導(dǎo)入報錯:ZipInputStream解壓遠程文件報錯,java.lang.IllegalArgumentException: MALFORMED
原因:文件名含有中文,zip解析出錯
解決方案,如下行代碼,在生成ZipInputStream的時候指定編碼格式。
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(inputStream), Charset.forName(“GBK”));
2. 讀取附件信息上傳到文件服務(wù)器
public List<HashMap> readLocalFile() throws Exception {
File file= new File(destDirectory+"/files");
List<HashMap> fssList = new ArrayList<>();
if (file.exists()) {
File[] sourceFiles = file.listFiles();
if (null == sourceFiles || sourceFiles.length < 1) {
System.out.println(file.getName()+"目錄里面不存在文件,無需處理.");
return fssList;
} else {
for (int i = 0; i < sourceFiles.length;i++){
File srcFile = sourceFiles[i];
FileItemFactory factory = new DiskFileItemFactory(16, null);
FileItem item = factory.createItem(srcFile.getName(), "text/plain", true, srcFile.getName());
int bytesRead = 0;
byte[] buffer = new byte[8192];
try {
FileInputStream fis = new FileInputStream(srcFile);
OutputStream os = item.getOutputStream();
while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
MultipartFile mfile = new CommonsMultipartFile(item);
AjaxResult fileResult = this.fssFileService.uploadFile(mfile);
String filePath = fileResult.get("url") == null ? "" : fileResult.get("url").toString();
if (fileResult.get("fileId") != null){
HashMap tempMap = new HashMap();
String fileId = this.fileService.saveFileInfo(fileResult.get("fileId").toString(),mfile, filePath, "");
tempMap.put(srcFile.getName(), fileId);
fssList.add(tempMap);
}
}
}
}
return fssList;
}注意:這里有個小難點就是File轉(zhuǎn)換成MultipartFile的方法,因為項目中已經(jīng)有的上傳文件是MultipartFile格式的,轉(zhuǎn)換一下就不用在實現(xiàn)一遍上傳方法了。
3. 讀取Excel文件存入數(shù)據(jù)庫
我是用EasyExcel導(dǎo)入Excel文件的,代碼很簡單,需要注意用EasyExcel導(dǎo)入的Excel文件如果包含多個sheet頁,需要寫多個導(dǎo)入監(jiān)聽文件。
4. 刪除臨時文件
這一步實現(xiàn)方法跟導(dǎo)出時相同,去掉臨時文件。
以上就是Java實現(xiàn)批量導(dǎo)出導(dǎo)入數(shù)據(jù)及附件文件zip包的詳細內(nèi)容,更多關(guān)于Java導(dǎo)出導(dǎo)入數(shù)據(jù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
IDEA生成patch和使用patch的方法實現(xiàn)
比如你本地修復(fù)的 bug,需要把增量文件發(fā)給客戶,很多場景下大家都需要手工整理修改的文件,并整理好目錄,這個很麻煩,那有沒有簡單的技巧呢?本文主要介紹了IDEA生成patch和使用patch的方法實現(xiàn),感興趣的可以了解一下2023-08-08
java正則表達式獲取指定HTML標簽的指定屬性值且替換的方法
下面小編就為大家?guī)硪黄猨ava正則表達式獲取指定HTML標簽的指定屬性值且替換的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-12-12
Java8新特性stream和parallelStream區(qū)別
這篇文章主要介紹了Java8新特性stream和parallelStream區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
spring-cloud入門之eureka-client(服務(wù)注冊)
本篇文章主要介紹了spring-cloud入門之eureka-client(服務(wù)注冊),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
詳解SpringMVC組件之HandlerMapping(一)
這篇文章主要介紹了詳解SpringMVC組件之HandlerMapping(一),HandlerMapping組件是Spring?MVC核心組件,用來根據(jù)請求的request查找對應(yīng)的Handler,在Spring?MVC中,有各式各樣的Web請求,每個請求都需要一個對應(yīng)的Handler來處理,需要的朋友可以參考下2023-08-08
詳解SpringBoot如何實現(xiàn)多環(huán)境配置
在實際的軟件開發(fā)過程中,一個應(yīng)用程序通常會有多個環(huán)境,pring?Boot?提供了一個非常靈活和強大的方式來管理這些環(huán)境配置,下面就跟隨小編一起學(xué)習(xí)一下吧2023-07-07
IDEA項目的依賴(pom.xml文件)導(dǎo)入問題及解決
這篇文章主要介紹了IDEA項目的依賴(pom.xml文件)導(dǎo)入問題及解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08

