實現思路:
- 用戶在瀏覽器上傳xlsx或者xls文件
- servlet或controller將文件上傳到servlet或controller將文件上傳到項目文件夾
- 後端工具類將Excel文件解析並轉換爲csv文件並輸出到系統數據庫安全路徑("/var/lib/mysql-files/")
- 通過mybatis拼接sql語句將csv數據導入數據庫表中
瀏覽器界面:
Excel模板
jsp中
<!-- 上傳考勤表的表單 -->
<form id="excel" method="post" enctype="multipart/form-data">
<input id="file" class="easyui-filebox" name="file" style="width:300px" buttonText="選擇本地考勤表" data-options="prompt:'請選擇Excel文件'">
<input type="submit" value="確認上傳">
<input type="reset" value="重置">
</form>
js中
$(function(){
$('#excel').form({
url:"<%=basePath%>attendance/upload",
onSubmit: function() {
var fileName= $('#file').filebox('getValue');
//對文件格式進行校驗
var d1=/\.[^\.]+$/.exec(fileName);
if (fileName == "") {
$.messager.alert('請選擇將要上傳的文件!');
return false;
}else if(d1!=".xls" && d1!=".xlsx"){
$.messager.alert('提示','請選擇xls或者xlsx格式文件!','info');
return false;
}
return true;
},
success:function(data){
var data = eval('(' + data + ')');
if(!data["state"]){
console.log(data)
console.log(data.state);
$.messager.alert('失敗','文件格式是否規範呢?')
}else{
$.messager.alert('成功','請刷新考勤表')
}
},
error:function(err){
console.log(err)
}
});
// 規定爲Excel文件類型
$('#file').filebox({
accept:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel'
})
easyui中文件上傳表單設置accept可以規定文件類型,但是用戶可以強行上傳其他類型的文件。所以還需要在onsubmit方法中再判斷一次。
controller中
**
*
* <p>Title: upload</p>
* <p>Description: </p>
上傳考勤表
* @param files 上傳的文件數組
* @param req request
* @return
* <p> @date 2018年12月10日 </p>
*/
@RequestMapping("upload")
@SystemControllerLog(type=2,description="上傳考勤表")
@ResponseBody
public JsonData upload(@RequestParam("file")MultipartFile[] files, HttpServletRequest req){
String upDirRealPath = req.getServletContext().getRealPath("/uploadDir/");
String msg = null;
Boolean state = null;
Integer value = null;
// 從session中獲取操作者
Admin admin = (Admin)(req.getSession().getAttribute("admin"));
// 上傳到指定路徑
for(MultipartFile file : files){
// 將項目下的uploaddir文件夾絕對路徑,連接文件名,得到文件的絕對路徑
String src = upDirRealPath.concat(file.getOriginalFilename());
try {
// 傳進絕對路徑,上傳
file.transferTo(new File(src));
// 上傳成功後,調用service中的方法,進行轉換csv和導入數據庫
value = as.fileInsert(src, admin.getAdminId());
state = true;
} catch (IllegalStateException e) {
msg = "IllegalStateException";
e.printStackTrace();
} catch (IOException e) {
msg = "IOException";
e.printStackTrace();
}
}
return new JsonData("上傳文件", value, msg, state);
}
Service中
public Integer fileInsert(String src, Long adminId) {
// 調用csvutil工具類,轉換成csv文件並獲取csv文件在安全路徑下的絕對路徑
String csvPath = CsvUtil.excel(src, adminId);
// 調用dao層的方法上傳到數據庫
return ad.csvInsert(csvPath);
}
CsvUtil中
寫了三個方法。
前兩個方法基本相同,是xls與xlsx格式的表格轉換成csv文件並返回csv文件路徑,
最後一個方法供調用,傳入文件名後匹配後綴,決定執行前面的哪一個方法
所以,只需要搞定第一個方法即可
幾個特別注意的地方:
- 數據庫安全路徑。linux系統中mysql默認安全上傳路徑是 “/var/lib/mysql-files/”
- linux系統和windows系統中路徑用的斜槓符號不同。處理路徑字符串時一定要用File.separator
- Excel 日期格式的判斷。先判斷是不是數值型,再判斷是否爲日期型
- 如果excel表第一行不是數據,而是表頭,則要跳過第一行。
package com.bs.admin.util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/* *
* <p>Title: CsvUtil</p>
* <p>Description: </p>
用於將excel文件轉換成csv文件
* @author zhengjian
* <p> @date 2018年12月11日</p>
*/
public class CsvUtil {
// 輸出路徑(mysql安全路徑。本地默認路徑是在c盤ProgramData裏面。而linux系統默認路徑爲"/var/lib/mysql-files/"。這裏在枚舉中獲取到linux系統默認路徑"/var/lib/mysql-files/")
// private static String csvDir = "C:/ProgramData/MySQL/MySQL Server 5.7/Uploads/";
private static String csvDir = PropertyUtil.CSVDIR.getName();
/**
*
*
* <p>
* Title: excelToCsv
* </p>
*
* <p>
* Description:
* </p>
* 將上傳的xlsx錶轉爲csv格式,然後將Excel文件刪除
*
* @param src
* <p>
* @return
* @date 2018年12月7日
* </p>
*/
public static String xlsxToCsv(String src, Long adminId) {
XSSFWorkbook workbook = null;
BufferedWriter bw = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
File file = new File(src);
FileInputStream fis = null;
// linux與windows中的斜槓不同。這裏一定要用File.separator。切割文件的絕對路徑獲取文件名
String filename = src.substring(src.lastIndexOf(File.separator)+1,src.lastIndexOf("."));
try {
fis = new FileInputStream(file);
workbook = new XSSFWorkbook(fis);
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(csvDir.concat(filename).concat(".csv")), "UTF-8"));
XSSFSheet sheet = workbook.getSheetAt(0);
// System.out.println(sheet.getLastRowNum());
// 第一行表頭跳過。一定要跳過,不然格式錯誤
for (int i = 1; i < sheet.getLastRowNum() + 1; i++) {
XSSFRow row = sheet.getRow(i);
if(row == null){
System.out.println("空行");
continue;
}
for (Cell cell : row) {
if (cell.getCellType() == XSSFCell.CELL_TYPE_STRING){
bw.write(cell.getStringCellValue());
}
else if (cell.getCellType() == XSSFCell.CELL_TYPE_NUMERIC){
// Excel 日期格式的判斷。先判斷是不是數值型,再判斷是否爲日期型
if(DateUtil.isCellDateFormatted(cell)){
bw.write(sdf.format(cell.getDateCellValue()));
}else{
bw.write("" + cell.getNumericCellValue());
}
}
else if (cell.getCellType() == XSSFCell.CELL_TYPE_BOOLEAN){
bw.write("" + cell.getBooleanCellValue());
}
bw.write(",");
}
// 操作者id
bw.write(adminId+",");
bw.newLine();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (null != bw) {
bw.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (null != fis) {
fis.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//刪除Excel文件,返回csv文件路徑
boolean delete = file.delete();
// System.out.println(delete);
return csvDir.concat(filename).concat(".csv");
}
/**
*
* <p>Title: xlsToCsv</p>
* <p>Description: </p>
將xls文件轉換爲csv文件
* @param fileName
* <p> @date 2018年12月10日 </p>
*/
public static String xlsToCsv(String src, Long adminId) {
HSSFWorkbook workbook = null;
BufferedWriter bw = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String filename = src.substring(src.lastIndexOf("\\")+1,src.lastIndexOf("."));
// String csvPath = csvDir.concat(fileName.substring(0,fileName.indexOf("."))).concat(".csv");
File file = new File(src);
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
workbook = new HSSFWorkbook();
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(csvDir.concat(filename).concat(".csv")), "UTF-8"));
HSSFSheet sheet = workbook.getSheetAt(0);
// 第一行表頭跳過 int i = 0; i < sheet.getLastRowNum(); i++
for (int i = 1; i < sheet.getLastRowNum() + 1; i++) {
HSSFRow row = sheet.getRow(i);
for (Cell cell : row) {
if (cell.getCellType() == XSSFCell.CELL_TYPE_STRING){
bw.write(cell.getStringCellValue());
}
else if (cell.getCellType() == XSSFCell.CELL_TYPE_NUMERIC){
if(DateUtil.isCellDateFormatted(cell)){
bw.write(sdf.format(cell.getDateCellValue()));
}else{
bw.write("" + cell.getNumericCellValue());
}
}
else if (cell.getCellType() == XSSFCell.CELL_TYPE_BOOLEAN){
bw.write("" + cell.getBooleanCellValue());
}
bw.write(",");
}
// 操作者id
bw.write(adminId+",");
bw.newLine();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (null != bw) {
bw.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (null != fis) {
fis.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//刪除Excel文件,返回csv文件路徑
boolean delete = file.delete();
return csvDir.concat(filename).concat(".csv");
}
/**
*
* <p>Title: excel</p>
* <p>Description: </p>
傳入路徑+文件全名(如“c://excel/data.xlsx”)根據文件後綴判斷需要執行哪個方法。返回csv文件路徑
* @param fileName
* <p> @date 2018年12月10日 </p>
*/
public static String excel(String src, Long adminId){
String suffix = src.substring(src.lastIndexOf(".")+1);
if(suffix.equals("xlsx")){
return xlsxToCsv(src, adminId);
}else{
return xlsToCsv(src, adminId);
}
}
}
dao層
public Integer csvInsert(String src) {
return am.csvInsert(src);
}
mapper接口層
Integer csvInsert(@Param("src") String src);
mapper.xml中
<select id="csvInsert" parameterType="map">
load data local infile #{src}
into table t_attendance character set gb2312
fields terminated by ',' optionally enclosed by '"' escaped by '"'
lines terminated by '\r\n'
(emp_id,work_day,leave_day,late_day,early_day,att_date,admin_id);
</select>