Excel文件一鍵上傳並解析完成數據批量導入數據庫

原來做文件上傳的時候,都是有一個輸入框,點擊上傳按鈕,先瀏覽文件,選擇文件後,把文件的路徑保存到form表單中,最後通過form表單提交到服務端。這樣的界面不是很美觀。爲了用戶有更好地體驗(UE),現在的大多數系統都是採用一鍵文件上傳,用戶點擊上傳按鈕,選擇要上傳的文件,確定之後,文件就直接上傳了,不需要提供額外的form表單,而且可以實現頁面文件上傳無刷新。

文件上傳和一鍵文件上傳的原理

文件上傳需要具備的條件:

客戶端:
1、 Form 表單編碼方式 multipart/form-data
2、 提交方式必須爲 post
3、 上傳文件對應 input type=”file” 元素要提供 name 屬性

服務端:

使用Struts2進行文件上傳

struts2-default.xml 配置

在這裏插入圖片描述

FileUploadInterceptor攔截器已經被配置 defaultStack 中,這個攔截器對Apache commons-fileupload文件上傳工具包進行了封裝,使用更便捷。

客戶端–使用jQuery ocupload插件實現一鍵上傳

Ocupload即One-click upload,一鍵上傳。

一鍵上傳原理

在這裏插入圖片描述

插件下載的官網現在不能正常訪問,插件在文章末提供的示例項目中。示例項目僅供大家參考!

首先在項目中導入這個插件,並在頁面中進行引用。

注:由於這個插件是jQuery的插件,所在需要在引入這個插件之前,先在頁面中引入jQuery文件。

插件的使用

官方示例:

$(element).upload({ 
        name: 'file',  //<input type='file' name='file'/> 插件的默認值是file
        action: '',   //請求服務器的路徑
        enctype: 'multipart/form-data',  //mime類型 ,插件默認的即可
        params: {},   //請求額外傳遞的參數,一般不用設置
        autoSubmit: true,   //是否在選擇文件後自動提交form表單
        onSubmit: function() {},  //在提交form表單之前進行的操作
        onComplete: function() {},  //完成文件上傳後,進行的操作
        onSelect: function() {}   //選擇文件後,進行的操作
}); 

代碼演示:

//爲按鈕綁定一鍵上傳插件
	$("#ocupload").upload({ 
        action: '../ocupload_batchImport.action',   //請求服務端的路徑
        //完成上傳後,觸發的事件,response參數是響應到頁面的json字符串
        onComplete: function(response) {
        	//將返回的json字符串response轉換成json對象
        	var data = JSON.parse(response);
        	if(data.result){
        		alert("文件上傳成功!");
        	}else{
        		alert("文件上傳失敗!");
        	}
        },
        //選擇文件後,觸發的事件
        onSelect: function() {
        	this.autoSubmit = false;    //這個是一鍵上傳插件中的屬性
        	//定義一個正則表達式,用來限定只能上傳以.xls或以.xlsx結尾的Excel文件
        	var regex = /^.*\.(xls|xlsx)$/ ;
        	
        	//獲得上傳文件的名字
        	var filename = this.filename();    //這個方法是由一鍵上傳的插件提供
        	if(regex.test(filename)){
        		//符合條件,提交form表單
        		this.submit();            //這個方法是由一鍵上傳的插件提供
        	}else{
        		//不符合條件,給出提示
        		alert("只能上傳以.xls或以.xlsx結尾的文件!");
        	}
        }

服務端–使用Apache POI解析Excel數據

編寫 OcuploadAction類 接收上傳文件

由於Struts2的FileUploadInterceptor攔截器對文件上傳工具包進行了封裝,我們只需要按照這個攔截器中定義的規範,即可完成文件的上傳。

在 Action 定義三個成員變量
private File [頁面元素 name]
private String [頁面元素 name]ContentType;
private String [頁面元素 name]FileName;

並在Action中提供set方法

Apache POI

POI的功能可以解析微軟的Office組件的文檔格式。
企業中通常使用其解析Excel文檔或生成Excel文檔(SS)。
POI支持HSSF解析(.xls–Excel97-2007之前版本,僅支持65535行記錄)和XSSF解析(.xlsx–Excel2007及以後版本)。

1,在項目中引入POI的座標(根據需要可以引入HSSF和XSSF的)

<poi.version>3.12</poi.version>
<!-- 解析HSSF的包  就是解析Excel 97-2007格式的Excel文檔(以.xls結尾的)-->
  	<dependency>
  		<groupId>org.apache.poi</groupId>
  		<artifactId>poi</artifactId>
  		<version>${poi.version}</version>
  	</dependency>
  	<!-- 解析XSSF的包  解析Excel 2007格式的Excel文檔(以.xlsx結尾的) 這個包依賴poi包-->
  	<dependency>
  		<groupId>org.apache.poi</groupId>
  		<artifactId>poi-ooxml</artifactId>
  		<version>${poi.version}</version>
  	</dependency>
  	<dependency>
  		<groupId>org.apache.poi</groupId>
  		<artifactId>poi-ooxml-schemas</artifactId>
  		<version>${poi.version}</version>
  	</dependency>

2.解析Excel工作簿

POI解析的基本過程:打開WorkBook工作簿文件—》找到Sheet工作表—》遍歷讀取Rows行—》讀取行中的cell單元格。

@ParentPackage("json-default")
@Namespace("/")
@Controller
@Scope("prototype")
public class OcuploadAction extends BaseAction {

	// 屬性驅動,獲取客戶端請求過來的file文件
	private File file; // 屬性名對應客戶端form表單中設置的name屬性的值

	private String fileContentType; // 上傳文件的類型

	private String fileFileName; // 上傳文件的名稱

	public void setFile(File file) {
		this.file = file;
	}

	public void setFileContentType(String fileContentType) {
		this.fileContentType = fileContentType;
	}

	public void setFileFileName(String fileFileName) {
		this.fileFileName = fileFileName;
	}

	private String JSON = "json";

	@Autowired
	private OcuploadService ocuploadService;

	@Action(value = "ocupload_batchImport", results = { @Result(name = "json", type = "json") })
	public String batchImport() {

		// 定義一個存放返回結果集的map
		Map<String, Object> resultMap = new HashMap<>();

		// 定義一個list集合,用戶存放實體對象
		List<Area> list = new ArrayList<>();

		FileInputStream inputStream = null;

		Workbook book = null;
		try {
			// Excel文件解析

			// 1.創建文件輸入流對象,讀取文件
			inputStream = new FileInputStream(file);

			// 2.創建Excel工作簿文件(包括.xls和.xlsx格式)
			book = WorkbookFactory.create(inputStream);

			// 3.打開需要進行解析的工作表sheet
			Sheet sheet = book.getSheetAt(0);

			// 4.遍歷工作表對象sheet,獲取到工作表中的每一行數據,對應一個實體對象(Area)
			for (Row row : sheet) {
				// 跳過第一行比表頭數據
				if (row.getRowNum() == 0) {
					continue;
				}

				// 一般來說,每一行的第一列都是標識列,如果第一列的單元格沒有數據,則認爲這一行數據無效,跳過
				if (StringUtils.isNotBlank(row.getCell(0).getStringCellValue())) {
					// 設置Area實體的部分屬性
					Area area = setEntity(row);

					// ============================================================

					// 使用PinYin4j把字符串轉成拼音

					// 去掉省份,城市,區域最後一個字(省,市,區)

					// 省份
					String province = area.getProvince().substring(0, area.getProvince().length() - 1);

					// 城市
					String city = area.getCity().substring(0, area.getCity().length() - 1);

					// 區域
					String district = area.getDistrict().substring(0, area.getDistrict().length() - 1);

					hanziTopinyin(area, province, city, district);

					// 把對象添加到list集合中
					list.add(area);
				}
			}

			// 5.調用業務層,批量導入數據
			ocuploadService.batchImport(list);
			// 解析成功
			resultMap.put("result", true);
		} catch (Exception e) {
			System.out.println(e.getMessage());
			// 解析失敗
			resultMap.put("result", false);

		} finally {
			try {
				// 關閉資源
				book.close();
				inputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		// 把map集合壓入值棧,struts-json-plugin插件包,會把map自動轉換成json數據
		pushToValueStack(resultMap);
		// 返回json數據
		return JSON;

	}

	// 把漢字轉換成拼音
	public void hanziTopinyin(Area area, String province, String city, String district) {
		// 得到區域簡碼 例如:北京市北京市海淀區 簡碼:BJBJHD

		String[] headStr = PinYin4jUtils.getHeadByString(province + city + district);

		// 進行字符串拼接
		StringBuffer buffer = new StringBuffer();

		for (String str : headStr) {
			buffer.append(str);
		}

		// 把buffer轉換成string,得到區域簡碼
		String shortcode = buffer.toString();

		// 設置區域簡碼
		area.setShortcode(shortcode);

		// 設置城市編碼
		area.setCitycode(PinYin4jUtils.hanziToPinyin(city, ""));
	}

	/**
	 * @param row
	 * @return
	 */
	public Area setEntity(Row row) {
		// 創建一個Area對象,把數據存放到這個對象中,
		Area area = new Area();
		// 設置數據時,要對應上傳文件的Excel表格中的列進行設置
		// 設置區域編號
		area.setId(row.getCell(0).getStringCellValue());
		// 設置省份
		area.setProvince(row.getCell(1).getStringCellValue());
		// 設置城市
		area.setCity(row.getCell(2).getStringCellValue());
		// 設置區域
		area.setDistrict(row.getCell(3).getStringCellValue());
		// 設置郵編
		area.setPostcode(row.getCell(4).getStringCellValue());
		return area;
	}

}

業務操作,添加數據到數據庫就不在這裏敘述,完整源碼在文章末的示例項目中!

在上述代碼中,還有關於PinYin4j的用法,下面做簡單的介紹

Pinyin4j是一個流行的Java庫,支持中文字符和拼音之間的轉換,拼音輸出格式可以定製。

Pinyin4j的使用

在項目中導入Pinyin4j的座標

<pinyin4j.version>2.5.0</pinyin4j.version>
<!-- 支持字符串轉換拼音 -->
  	<dependency>
  		<groupId>pinyin4j</groupId>
  		<artifactId>pinyin4j</artifactId>
  		<version>${pinyin4j.version}</version>
  	</dependency>

在示例項目裏,提供了一個Pinyin4jUtils工具類,它對Pinyin4j的一些操作進行了封裝。

支持的方法:

1.獲得每個漢字拼音首字母
2.把漢字轉成拼音,去掉每個字拼音之間的空格

例如:北京市
獲得每個漢字拼音首字母 [B, J, S]
把漢字轉成拼音,去掉每個字拼音之間的空格 beijingshi

public static void main(String[] args) {
		// pin4j 簡碼 和 城市編碼 
		String s1 = "北京市"; 
		String[] headArray = getHeadByString(s1); // 獲得每個漢字拼音首字母
		System.out.println(Arrays.toString(headArray));
		
		String s2 = hanziToPinyin(s1,"");  //把漢字轉成拼音,去掉每個字拼音之間的空格
		System.out.println(s2);
	}

最後分享示例項目在GitHub上的地址:https://github.com/xiaoguige/ocupload

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