Java使用Jxls 導入導出Excel

簡介

官網:http://jxls.sourceforge.net/

Jxls是一個小型Java庫,可以輕鬆生成Excel報告。Jxls在Excel模板中使用特殊標記來定義輸出格式和數據佈局。
許多具有某種報告功能的Java應用程序都需要生成Excel。
Java有很好的開源和商業庫來創建Excel文件(值得一提的是開源軟件,包括Apache POI和Java Excel API)。
從某種意義上說,這些庫是非常低級的,它們要求你編寫大量的Java代碼,甚至創建簡單的Excel文件。

總結:
1,Jxls比poi使用代碼少,有官方使用說明,易於學習和使用。
2,Jxls使用模板批註的表達式,使得導出數據時實體類字段順序無需對應excle模板字段順序。
3,導出Jxls有缺陷,但第一列爲空時,會造成後面的數據無法讀取,下面再具體說。

依賴

<!-- JXLS 核心 -->
<dependency>
    <groupId>org.jxls</groupId>
    <artifactId>jxls</artifactId>
    <version>2.6.0</version>
</dependency>
<!-- 基於poi實現 -->
<dependency>
    <groupId>org.jxls</groupId>
    <artifactId>jxls-poi</artifactId>
    <version>1.2.0</version>
</dependency>
<!-- 讀取Excle -->
<dependency>
    <groupId>org.jxls</groupId>
    <artifactId>jxls-reader</artifactId>
    <version>2.0.5</version>
</dependency> 

工具類

package test.poi;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Map;
import java.util.Map.Entry;
import org.jxls.common.Context;
import org.jxls.reader.ReaderBuilder;
import org.jxls.reader.XLSReadStatus;
import org.jxls.reader.XLSReader;
import org.jxls.util.JxlsHelper;

/**
 * JXLS Excel 工具類
 */
public class JXLSExcelUtil {
	
	/**
	 * 導出 Excle
	 * @param templateRelativePathAndName 模板相對路徑和文件名
	 * @param data Excle模板數據
	 * @return
	 * @throws Exception
	 */
	public static ByteArrayOutputStream export(String templateRelativePathAndName, Map<String, Object> data) throws Exception {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		InputStream in = JXLSExcelUtil.class.getClassLoader().getResourceAsStream(templateRelativePathAndName);
		if (in == null) {
			throw new Exception("模板文件未找到:" + templateRelativePathAndName);
		}
		Context context = new Context();
		for (Entry<String, Object> d : data.entrySet()) {
			if (d.getKey() != null && d.getValue() != null) {
				context.putVar(d.getKey(), d.getValue());
			}
		}
		JxlsHelper.getInstance().processTemplate(in, out, context);
		return out;
	} 
	
	/**
	 * 讀取Excle數據到bean 
	 * @param readConfigXmlRelativePathAndName 讀取配置文件
	 * @param inputExcelStream 輸入的excle inputSream
	 * @param beans 要封裝數據的bean
	 * @return
	 * @throws Exception
	 */
	public static boolean readExcelData(String readConfigXmlRelativePathAndName, InputStream inputExcelStream, Map<String, Object> beans) throws Exception {
		InputStream in = JXLSExcelUtil.class.getClassLoader().getResourceAsStream(readConfigXmlRelativePathAndName);
		if (in == null) {
			throw new Exception("配置文件未找到:" + readConfigXmlRelativePathAndName);
		}
		InputStream inputXML = new BufferedInputStream(in);
		XLSReader reader = ReaderBuilder.buildFromXML(inputXML);
	    XLSReadStatus readStatus = reader.read(inputExcelStream, beans);
		return readStatus.isStatusOK();
	}
	
	/**
	 * 讀取Excle數據到bean 
	 * @param readConfigXmlRelativePathAndName 讀取配置文件
	 * @param file 輸入的excle文件
	 * @param beans 要封裝數據的bean
	 * @return
	 * @throws Exception
	 */
	public static boolean readExcelData(String readConfigXmlRelativePathAndName, File file, Map<String, Object> beans) throws Exception {
		if (file == null) {
			throw new Exception("Excel文件爲空");
		}
		InputStream inputExcelStream = new FileInputStream(file);
		return readExcelData(readConfigXmlRelativePathAndName, inputExcelStream, beans);
	}
}

模板 這個是重點

在這裏插入圖片描述

批註一:

jx:area(lastCell=”C3”)
定義模板的根區域,可以理解爲需要處理數據的區域

在這裏插入圖片描述

批註二:

Administrator:
jx:each(items=”dataList” var=”data” lastCell=”C3”)
循環表達式

在這裏插入圖片描述

導入配置文件:

上面提到的缺陷就在這裏
“讀取終止條件, 當第一列爲空值會終止讀取數據”
暫時沒有找到理想的解決方案,可以使用poi代替。

readExcelConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<workbook>
	<worksheet name="Sheet1">
	    <!-- section 表示固定的行數,不需要讀取的行 -->
	    <!-- 下標都是從0開始 -->
		<section startRow="0" endRow="1"></section>
		<!-- 行列與實體數據對應關係映射 -->
		<loop startRow="2" endRow="2" items="dataList" var="data"
			varType="test.domain.ExcelDataTest">
			<section startRow="2" endRow="2">
				<mapping row="2" col="0">data.column1</mapping>
				<mapping row="2" col="1">data.column2</mapping>
				<mapping row="2" col="2">data.column3</mapping>
			</section>
			<!-- 讀取終止條件, 當第一列爲空值會終止讀取數據 -->
			<loopbreakcondition>
				<rowcheck offset="0">
					<cellcheck offset="9"></cellcheck>
				</rowcheck>
			</loopbreakcondition>
		</loop>
	</worksheet>
</workbook>

控制類

package test.controller;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import test.domain.ExcelDataTest;
import test.poi.JXLSExcelUtil;
import test.util.DownloadUtil;
import test.util.FileUtil;

@RestController
@RequestMapping("/excel")
public class ExcelController {
	
	/**
	 * 導出Excel數據
	 * @param response
	 * @throws Exception
	 */
	@RequestMapping(value = "/export" , method = RequestMethod.GET, produces = "application/json")
	public void export(HttpServletResponse response) throws Exception{
		ByteArrayOutputStream baos = null;
		OutputStream out = null;
		try {
			// excel數據  實際運用從數據庫中查詢
			List<ExcelDataTest> dataList = new ArrayList<ExcelDataTest>();
			ExcelDataTest data = new ExcelDataTest();
			data.setColumn1(123456);
			data.setColumn2("測試測試");
			data.setColumn3("測試測試測試測測試測試測試");
			dataList.add(data);
			
			Map<String, Object> datas = new HashMap<>();
			datas.put("dataList", dataList); // dataList與批註表達式中的items=”dataList”相同
			baos = JXLSExcelUtil.export("templates/jxls測試模板.xlsx", datas);
			DownloadUtil.generalDownload(response, baos, "excle導出測試.xlsx");
		} catch (Exception e) {
			e.printStackTrace();
		    throw new Exception("導出失敗:" + e.getMessage());
		} finally {
			if(baos != null){
				baos.close();
			}
			if(out != null){
				out.close();
			}
		}
	}
	
	/**
	 * 導入Excel數據
	 * @param file
	 */
	@RequestMapping(value = "/import", method = RequestMethod.POST)
	public void importExcel(MultipartFile file) {
		File f = null;
		try {
			// MultipartFile 轉  file
			f = FileUtil.multipartFileToFile(file);
			List<ExcelDataTest> list = new ArrayList<>();
			Map<String, Object> beans = new HashMap<>();
			beans.put("dataList", list); // dataList 來自配置文件readExcelConfig.xml的items=”dataList”
			JXLSExcelUtil.readExcelData("templates/readExcelConfig.xml", f , beans);
			for (ExcelDataTest data : list) {
				System.out.println(data.toString());
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (f != null) {
				f.delete();
			}
		}
	}
}

下載工具類 DownloadUtil

package test.util;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

/**
 * 下載工具類
 */
public class DownloadUtil {
	
	/**
	 * 通用下載設置
	 * @param response
	 * @param outData 輸出數據 ByteArrayOutputStream
	 * @param fileName 文件名
	 * @throws Exception
	 */
	public static void generalDownload(HttpServletResponse response, ByteArrayOutputStream outData, String fileName) throws Exception{
		response.setContentType( "application/x-msdownload");
		response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
		ServletOutputStream out = response.getOutputStream();
		outData.writeTo(out);
		out.flush();
		out.close();
	}
	
	/**
	 * 通用下載設置
	 * @param response 
	 * @param outData 輸出數據 InputStream
	 * @param fileName 文件名
	 * @throws Exception
	 */
	public static void generalDownload(HttpServletResponse response, InputStream outData, String fileName) throws Exception{
		response.setContentType( "application/x-msdownload");
		response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
		ServletOutputStream out = response.getOutputStream();
		byte[] bffer = new byte[1024];
		int r = outData.read(bffer, 0, 1024);
		while (r != -1) {
			out.write(bffer);
			r = outData.read(bffer, 0, 1024);
		}
		out.flush();
		out.close();
	}
	
	/**
	 * 通用下載設置
	 * @param response 
	 * @param outData 輸出數據 byte[]
	 * @param fileName 文件名
	 * @throws Exception
	 */
	public static void generalDownload(HttpServletResponse response, byte[] outData, String fileName) throws Exception{
		response.setContentType( "application/x-msdownload");
		response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
		ServletOutputStream out = response.getOutputStream();
		out.write(outData);
		out.flush();
		out.close();
	}
}

文件工具類 FileUtil

package test.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import org.springframework.web.multipart.MultipartFile;

/**
 * 文件工具類
 */
public class FileUtil {
	
	/**
	 * MultipartFile 轉  File
	 * @param file
	 * 注意:轉換的文件保存在項目的根目錄,因此使用完要及時清理
	 * @throws Exception
	 */
	public static File multipartFileToFile(MultipartFile multipartFile) throws Exception {
	    File toFile = null;
	    if (multipartFile != null) {
            InputStream in = multipartFile.getInputStream();
            toFile = new File(multipartFile.getOriginalFilename());
            
            OutputStream os = new FileOutputStream(toFile);
	        int r = 0;
	        byte[] buffer = new byte[1024];
	        while ((r = in.read(buffer, 0, 1024)) != -1) {
	            os.write(buffer, 0, r);
	        }
	        try {
	        	if (os != null) {
	        		os.close();
	        	}
			} catch (Exception e) {
			}
	        try {
	        	if (in != null) {
	        		in.close();
	        	}
			} catch (Exception e) {
			}
	    }
	    return toFile;
	}
	
}

結果

導出:

在這裏插入圖片描述

導入:

在這裏插入圖片描述

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章