使用SpringMVC导入Excel文件到MySQL时,由于是第一次做,所以走了比较多弯路,希望这篇文章能够给和我一样新学的童鞋,一点启发~做这个的时候,参考了比较多的文章,特别是最后两个文件上传类和解析类的,然后根据自己的项目需要进行修改。现在找不到之前看的帖子了,所以未能贴上参考网址,如果有知道的童鞋也可以告诉我一下哈~
(关于前台上传部分,可以参考这里)
SpringMVC的配置文件,需要增加文件上传配置:
(我就是一开始没配置,一直上传不了,纠结了一个多小时)
<!-- 支持文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 默认编码 -->
<property name="defaultEncoding" value="utf-8" />
<!-- 文件大小最大值 -->
<property name="maxUploadSize" value="10485760000" />
<!-- 内存中的最大值 -->
<property name="maxInMemorySize" value="40960" />
</bean>
pom导入相关包:
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
controller层部分代码。
接收前台上传的文件用MultipartFile,返回用map,所以前台用json类型接收
@ResponseBody
@RequestMapping(value="/analyzeXml", method = RequestMethod.POST)
public Map<String,Object> analyzeXml(@RequestParam("excelFile") MultipartFile excelFile,HttpServletRequest request,HttpServletResponse response) {
//上传xml文件
InputStream inputs;
boolean result=false;//导入标志
Map<String,Object> map=new HashMap<String, Object>();
try {
//上传
inputs = excelFile.getInputStream();
String fileName = excelFile.getOriginalFilename();
String filePath=request.getSession().getServletContext().getRealPath("uploadFile");
String uploadFileName = FileUtil.uploadFile(inputs, fileName, filePath);
System.out.println(filePath+"/"+uploadFileName);
//解析Excel,导入MySQL
result=bbuService.addBbu(filePath+"/"+uploadFileName);
} catch (IOException e) {
e.printStackTrace();
}
if(result){
map.put("message", "成功");
}else{
map.put("message", "失败");
}
return map;
}
service层代码
这里主要是将解析后的信息转化为相关对象
public boolean addBbu(String filePath) {
int result=0;
//解析xml文件
ReadExcel readExcel=new ReadExcel();
List<List<String>> lList =readExcel.getExcelInfo(filePath);
Bbu bbu=null;
List<Bbu> bbuList=new ArrayList<Bbu>();
for(List<String> list : lList){
bbu=new Bbu();
bbu.setBranch(list.get(0));
bbu.setCity(list.get(1));
bbu.setGrid_no(list.get(2));
bbu.setBusiness_department_name(list.get(3));
bbu.setEngineering_station_no(list.get(4));
bbu.setSystem_type(list.get(5));
bbu.setBbu_name(list.get(6));
bbu.setAddress(list.get(7));
bbu.setLongitude(list.get(8));
bbu.setLatitude(list.get(9));
bbu.setBuilding_type(list.get(10));
bbu.setCover_type(list.get(11));
bbu.setIndoor_coverage_area(list.get(12));
bbu.setOutdoor_cover_building_num(list.get(13));
bbuList.add(bbu);
}
result=bbuMapper.addBbu(bbuList);
if(result>0){
return true;
}
return false;
}
Dao层代码
这里记得要加上@Param注解
/**
* 插入数据
* @param bbuList
*/
public int addBbu(@Param("list")List<Bbu> bbuList);
持久层用的是mybatis,写在mapper文件里的代码。因为要批量上传,所以使用了foreach语句,将list中的每一个对象逐条读取。
<insert id="addBbu" parameterType="java.util.List" >
insert into bbu
(branch,city,grid_no,business_department_name,engineering_station_no,
system_type,bbu_name,address,longitude,latitude,building_type,cover_type,indoor_coverage_area,outdoor_cover_building_num)
values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.branch},#{item.city},#{item.grid_no},#{item.business_department_name},
#{item.engineering_station_no},#{item.system_type},#{item.bbu_name},#{item.address},
#{item.longitude},#{item.latitude},#{item.building_type},#{item.cover_type},
#{item.indoor_coverage_area},#{item.outdoor_cover_building_num})
</foreach>
</insert>
最后是两个关键类
文件上传类:
package com.shenofusc.utils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
public class FileUtil {
/***
* <pre>uploadFile(springMVC文件上传 传inputStream)
* 修改备注:
* @param inputs
* @param fileName
* @param folderPath
* @return</pre>
*/
public static String uploadFile(InputStream inputs, String fileName, String folderPath) {
// 上传物理文件到服务器硬盘
BufferedInputStream bis = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
String uploadFileName = null;
try {
// 构建输入缓冲区,提高读取文件的速度
bis = new BufferedInputStream(inputs);
// 自动建立文件夹
File folder = new File(folderPath);
if (!folder.exists()) {
folder.mkdirs();
}
// 为了保证上传文件的唯一性,可以通过uuid来解决
// 为了避免中文乱码问题则新生成的文件名由uuid+原来文件名的后缀组成
uploadFileName = UUID.randomUUID().toString()+getSuffix(fileName);
// 构建写文件的流即输出流
fos = new FileOutputStream(new File(folderPath+"/"+uploadFileName));
// 构建输出缓冲区,提高写文件的性能
bos = new BufferedOutputStream(fos);
// 通过输入流读取数据并将数据通过输出流写到硬盘文件夹
byte[] buffer = new byte[4096];// 构建4k的缓冲区
int s = 0;
while ((s=bis.read(buffer)) != -1) {
bos.write(buffer, 0, s);
bos.flush();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
bos = null;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
fos = null;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (bis != null) {
try {
bis.close();
bis = null;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (inputs != null) {
try {
inputs.close();
inputs = null;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return uploadFileName;
}
/**
* 后缀名的获取
* @param fileName
* @return
*/
private static String getSuffix(String fileName) {
int index = fileName.lastIndexOf(".");
String suffix = fileName.substring(index);
return suffix;
}
}
解析Excel
主要思路是首先判断是2007还是2003的Excel文件,然后将表格进行每一行每个单元格读取,每一行的每一个单元格存入list中,而将这些行再存入list中,最后再service层进行赋值转成bean。这里的缺点是表格文件的列必须是固定好的,不够灵活。但是想用反射来做,通过实体类的setXXX方法,来截取每个方法的XXX字段名,与表格中的标题比较,但无奈表格是中文的。如果再弄个map相对应英文名,太麻烦了,所以就没弄了。
package com.shenofusc.utils;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ReadExcel {
private int totalRows = 0;//总行数
private int totalCells = 0;//构造方法
public ReadExcel(){}
public int getTotalRows() { return totalRows;}
public int getTotalCells() { return totalCells;}
/**
* 读EXCEL文件,获取集合
* @param fielName
* @return
*/
public List<List<String>> getExcelInfo(String filePath){
//初始化集合
List<List<String>> lList=new ArrayList<List<String>>();
//初始化输入流
InputStream is = null;
try{
//根据文件名判断文件是2003版本还是2007版本
boolean isExcel2003 = true;
if(filePath.matches("^.+\\.(?i)(xlsx)$")){
isExcel2003 = false;
}
//根据新建的文件实例化输入流
is = new FileInputStream(filePath);
Workbook wb = null;
//根据excel里面的内容读取客户信息
if(isExcel2003){//当excel是2003时
wb = new HSSFWorkbook(is);
}
else{//当excel是2007时
wb = new XSSFWorkbook(is);
}
//读取Excel里面客户的信息
lList=readExcelValue(wb);
is.close();
}catch(Exception e){
e.printStackTrace();
} finally{
if(is !=null)
{
try{
is.close();
}catch(IOException e){
is = null;
e.printStackTrace();
}
}
}
return lList;
}
/**
* 读取Excel里面客户的信息
* @param wb
* @return
*/
private List<List<String>> readExcelValue(Workbook wb){
//得到第一个shell
Sheet sheet=wb.getSheetAt(0);
//得到Excel的行数
this.totalRows=sheet.getPhysicalNumberOfRows();
//得到Excel的列数(前提是有行数)
if(totalRows>=1 && sheet.getRow(0) != null){
this.totalCells=sheet.getRow(0).getPhysicalNumberOfCells();
}
List<List<String>> lList=new ArrayList<List<String>>();
//循环Excel行数,从第二行开始。标题不入库
for(int r=1;r<totalRows;r++){
Row row = sheet.getRow(r);
if (row == null) continue;
List<String> sList=new ArrayList<String>();
//循环Excel的列
for(int c = 0; c <this.totalCells; c++){
Cell cell = row.getCell(c);
if (null != cell){
cell.setCellType(Cell.CELL_TYPE_STRING);
sList.add(cell.getStringCellValue());
}
}
//添加客户
lList.add(sList);
}
return lList;
}
}