【Springboot+mybatis】 解析Excel並批量導入到數據庫
置頂 2018年01月16日 20:05:52 冉野丶 閱讀數:4060 標籤: excel導入數據庫 文件上傳 excel解析 更多
個人分類: POI 工作問題歸納
版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/hanerer1314/article/details/79077663
一個很簡單的需求,從後臺中選取一個的Excel文件,並直接導入到數據庫,然後根據導入的表查詢個人信息,由於表的數據內容還挺多,有好幾萬條,所幸是單表。
一個很愚蠢的做法是每解析一個Row,然後構建一個新的對象,再把每個cell的值賦給該對象,直到循環結束,再通過mabatis的insert語句入庫,這樣很low,有沒有???但是數據也能跑的過去,能完成入庫,不過兩萬條數據,連解析帶入庫一共花了將近20分鐘,天啦嚕,這樣客戶會炸毛的。沒辦法,還得修改,看了很多辦法,一種最直接的就是把解析和入庫分開,然後重新構建sql批量插入,因爲mybatis用的是generator插件自動生成的代碼,想把自己構建的mapper接口內容放在mybatis自己的目錄下,但是每次重新執行插件時候,自己新寫的接口文件就會被清除掉,無奈之舉,只能重新構建一個文件夾(excelmapper)來存儲我的查詢接口,這才逃過一劫,當我進行測試時候又報錯了,無法掃描到excelmapper下面的接口內容,嘗試在單元測試類上面配置@componentScan("com.net.excelmapper")註解,如果啓動類在根包下面,則你可以在該類上添加@ComponentScan註解而不需要添加任何參數,Spring Boot會在根包下面搜索注有@Component, @Service, @Repository, @Controller註解的所有類,並將他們註冊爲Spring Beans,否則,你需要在@ComponentScan註解上定義basePackages或者其他屬性。最後的解決辦法是在啓動類上添加了對應excelmapper文件夾下的掃描路徑,@MapperScan({"com.neo.mapper","com.neo.excelmapper"}),合法化測試終於通過了,可是還有一個問題,上傳超過了限制的默認值,只好在配置文件添加了配置項:
spring.http.multipart.max-file-size = 2048KB //支持文件上傳最大的限制
spring.http.multipart.max-request-size = 10240kB //最大支持請求
spring.http.multipart.enabled = true#默認支持文件上傳。
spring.http.multipart.file-size-threshold = 0#支持文件寫入磁盤。
spring.http.multipart.location =#上傳文件的臨時目錄
因爲用的是表單進行提交,<input type =“file”>這種情況下在form標籤下需要特殊的指定屬性文件爲formdata文件,例如:<form role =“form”action =“/ importExcel”method =“post” enctype =“multipart / form-data”>,這下終於可以完成數據導入了,不料,兩萬條數據果然還是花了20分鐘,修改意見也就上面提到的,分開操作,先把解析的數據封裝到一個對象上,並且存儲到列表集合中,在從幾何中批量插入。
excelmapper接口:
公共接口ExcelMapper {
void batchInsert(List <Tbagent> tbagentList);
}
excelmapper.xml中主要的SQL語句,也就是執行批量操作的SQL,
<insert id =“batchInsert”parameterType =“java.util.List”>
INSERT INTO代理(job_number,部門,地區,用戶名,idcard,company_rankings,department_rankings,region_rankings,
distance_first_company,distance_first_department,distance_first_region)
VALUES
<foreach collection =“list”item =“item”index =“index”separator =“,”>
(#{item.job_number},{#} item.department,#{item.region},{#} item.username,#{item.idcard},{#} item.company_rankings,
#{item.department_rankings},{#} item.region_rankings,#{item.distance_first_company},{#} item.distance_first_department,#{item.distance_first_region})
</的foreach>
</插入>
主要的服務層:
/ **
*由管理員於2018/1/11創建。
* /
@服務
公共類IimportServiceImpl實現IimportService {
private final static String XLS =“xls”;
public static final String XLSX =“xlsx”;
私人最終靜態記錄器記錄器= LoggerFactory.getLogger(IimportServiceImpl.class);
@Autowired私人TbagentMapper tbagentMapper;
@Autowired私人SqlSessionTemplate sqlSessionTemplate;
@Autowired私有ExcelMapper excelMapper;
@覆蓋
public Integer importExcel(MultipartFile myFile){
// 1。使用HSSFWorkbook打開或者創建“Excel對象”
// 2。用HSSFWorkbook返回對象或者創建片對象
// 3。用片材返回行對象,用行對象得到細胞對象
// 4。對細胞對象進行讀寫
List <Tbagent> tbagents = new ArrayList <>();
工作簿工作簿=空;
String fileName = myFile.getOriginalFilename(); //獲取文件名
logger.info( “【文件名】{}”,文件名);
if(fileName.endsWith(XLS))
{
嘗試{
workbook = new HSSFWorkbook(myFile.getInputStream()); // 2003版本
} catch(IOException e){
e.printStackTrace();
}
} else if(fileName.endsWith(XLSX)){
嘗試{
workbook = new XSSFWorkbook(myFile.getInputStream()); // 2007版本
} catch(IOException e){
e.printStackTrace();
}
}其他{
拋出新的LianjiaException(ResultEnum.FILE_IS_NOT_EXCEL); //文件不是Excel文件
}
工作表=工作簿.getSheet(“sheet1”);
int rows = sheet.getLastRowNum();
logger.info( “【行】{}”,行);
if(rows == 0){
拋出new LianjiaException(ResultEnum.DATA_IS_NULL); //數據爲空請填寫數據
}
long startTime = System.currentTimeMillis();
for(int i = 1; i <= rows + 1; i ++){
行排= sheet.getRow(i);
if(row!= null){
Tbagent tbagent = new Tbagent();
//部門
String department = getCellValue(row.getCell(0));
tbagent.setDepartment(部門);
//用戶姓名
String username = getCellValue(row.getCell(1));
tbagent.setUsername(用戶名);
//工號
String jobNumer = getCellValue(row.getCell(2));
如果(!StringUtils.isEmpty(jobNumer)){
Integer job_number = Integer.parseInt(jobNumer);
tbagent.setJob_number(Integer.valueOf(jobNumer));
}
//身份證後六位
String idcard = getCellValue(row.getCell(3));
tbagent.setIdcard(idcard);
//公司排名
String companyRankings = getCellValue(row.getCell(4));
如果(!StringUtils.isEmpty(companyRankings)){
整數new_companyRankings = Integer.parseInt(companyRankings);
tbagent.setCompany_rankings(new_companyRankings);
}
//事業部排名
String departmenRanks = getCellValue(row.getCell(5));
如果(!StringUtils.isEmpty(departmenRanks)){
整數new_departmentRanks = Integer.parseInt(departmenRanks);
tbagent.setDepartment_rankings(new_departmentRanks);
}
//大區排名
String region_Ranks = getCellValue(row.getCell(6));
如果(!StringUtils.isEmpty(region_Ranks)){
整數new_region_Rankings = Integer.parseInt(region_Ranks);
//logger.info( “【大區排名】{}”,new_region_Rankings);
tbagent.setRegion_rankings(new_region_Rankings);
} //距離公司第一名差距
String distance_first_company = getCellValue(row.getCell(7));
如果(!StringUtils.isEmpty(distance_first_company)){
long new_distance_first_company = Long.parseLong(distance_first_company);
tbagent.setDistance_first_company(new_distance_first_company);
}
//距離事業部第一名差距
String distance_first_deparment = getCellValue(row.getCell(8));
如果(!StringUtils.isEmpty(distance_first_deparment)){
Long new_distance_first_deparment = Long.parseLong(distance_first_deparment);
tbagent.setDistance_first_department(new_distance_first_deparment);
}
//距離大區第一名差距
String distance_first_region = getCellValue(row.getCell(9));
如果(!StringUtils.isEmpty(distance_first_region)){
Long new_distance_first_region = Long.parseLong(distance_first_region);
tbagent.setDistance_first_region(new_distance_first_region);
}
//System.out.println(JSON.toJSON(tbagent));
//tbagentMapper.insert(tbagent);
tbagents.add(tbagent);
//logger.info( “插入數據完成”);
}
}
excelMapper.batchInsert(tbagents); //批量插入五秒完成
long endTime = System.currentTimeMillis();
long totaltime = endTime - startTime;
logger.info( “【消耗時間爲】{}”,TOTALTIME); //將近兩萬條數據3秒解析完成
logger.info( “【第一條數據爲】{}”,JSON.toJSON(tbagents.get(0)));
返回行;
}
public String getCellValue(Cell cell){
String value =“”;
if(cell!= null){
開關(cell.getCellType()){
case HSSFCell.CELL_TYPE_NUMERIC://數字
value = cell.getNumericCellValue()+“”;
如果(HSSFDateUtil.isCellDateFormatted(小區)){
Date date = cell.getDateCellValue();
if(date!= null){
value = new SimpleDateFormat(“yyyy-MM-dd”)。format(date); //日期格式化
}其他{
value =“”;
}
} else {
//解析cell時候數字類型默認是double類型的但是想要獲取整數類型需要格式化很重要很重要
value = new DecimalFormat(“0”)。format(cell.getNumericCellValue());
}
打破;
大小寫HSSFCell.CELL_TYPE_STRING://字符串
value = cell.getStringCellValue();
打破;
大小寫HSSFCell.CELL_TYPE_BOOLEAN://布爾類型
value = cell.getBooleanCellValue()+“”;
打破;
大小寫HSSFCell.CELL_TYPE_BLANK://空值
value =“”;
打破;
case HSSFCell.CELL_TYPE_ERROR://錯誤類型
value =“非法字符”;
打破;
默認:
value =“未知類型”;
打破;
}
}
返回value.trim();
}
}
部分效果圖:
登錄效果圖如上。
不太完美的地方就是沒有一個進度條給客戶看,後期需要做處理。清空數據用的是MySQL的的截斷語句,直接清空所有的數據。然後讓用戶在導入到數據庫。
源碼地址 importexcel 分支