一、效果如下
二、写代码前要引入依赖
1. commons-fileupload
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
文件上传是项目开发中最常见的功能,为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data
,只有这样浏览器才会把用户选择的文件以二进制数据发送给服务器。 Spring MVC为文件上传提供了直接的支持(即插即用的MultipartResolver),Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver
。因此,SpringMVC的文件上传需要依赖Apache Commons FileUpload的组件。
SpringMVC.xml配置
<!-- 多部分文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--定义上传的最大大小,单位为byte-->
<property name="maxUploadSize" value="104857600" />
<property name="maxInMemorySize" value="4096" />
<!-- 设置默认编码 -->
<property name="defaultEncoding" value="UTF-8"></property>
</bean>
2. Apache POI
此外需要添加Apache POI依赖,Apache POI是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。
<!--添加ApachePOI依赖-->
<!--导出03excel支持-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.11</version>
</dependency>
<!--导出07支持-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.11</version>
</dependency>
三、前端JSP页面
<div class="box-tools">
<form method="post" enctype="multipart/form-data" action="/product/upload">
<input type="file" id="upload" name="mulFile" class="btn bg-olive btn-xs" style="width:180px"/>
<br />
<input type="submit" value="导入" class="btn bg-olive btn-xs" style="width:80px"/>
</form>
</div>
使用的是Spring Mvc框架提供对象MultipartFile
,该对象可以作为控制器方法的参数,参数的名称必须和表单file元素的name
属性取值一致。
四、Controller层
编写Ctroller层,Ctroller使用Excel工具类,读取Excel数据封装为实体类对象,再调用Service插入方法,实现导入功能。
/**
* @param request 请求对象
* @param mulFile 参数名称必须与页面元素名称一致:<input type="file" name="mulFile">
* @throws Exception
*/
@RequestMapping("/upload")
public String upload(HttpServletRequest request, MultipartFile mulFile) throws Exception {
InputStream in = mulFile.getInputStream();
//判断是否上传文件
if (in != null) {
String fileName = mulFile.getOriginalFilename();
//判断是否为excel类型文件
if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
throw new Exception("文件不是excel类型");
}
else {
List<List<Object>> lists = ReadExcelUtil.getDataFromExcel_07(in);
for (List<Object> list : lists) {
Product product = new Product();
product.setId(Long.valueOf(list.get(0).toString()));
product.setProductNum((String) list.get(1));
product.setProductName((String) list.get(2));
product.setCityName((String) list.get(3));
product.setDepartureTime(Timestamp.valueOf(list.get(4).toString()));
product.setProductPrice(Double.valueOf(list.get(5).toString()));
product.setProductDesc((String) list.get(6));
product.setProductStatus(Integer.valueOf(list.get(7).toString()));
// 调用service,保存
productService.saveProduct(product);
}
}
return "redirect:/product/findAll";
}
return "";
}
注意list<Object>
如何封装为实体类,Object->String, Object->Long, Object->Double, Obejct->Integer, Object->Timestamp
五、工具类
1. 2003 Excel
/**
* @Description(2003 Excel 导入)
* @Param: [in]
* @return: java.util.List<java.util.List < java.lang.Object>>
* @Date: 2019/5/18
*/
public static List<List<Object>> getDataFromExcel(InputStream in) throws Exception {
List<List<Object>> list = new ArrayList<List<Object>>();
Workbook workbook = new HSSFWorkbook(in);
//遍历sheet
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
Sheet sheet = workbook.getSheetAt(i);
if (sheet == null) {
continue;
}
//遍历某个sheet行
for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {
Row row = sheet.getRow(j);
//跳过空行和每个sheet第一行,如果没有表头需要修改
if (row == null || row.getFirstCellNum() == j) {
continue;
}
List<Object> li = new ArrayList<Object>();
for (int m = row.getFirstCellNum(); m < row.getLastCellNum(); m++) {
Cell cell = row.getCell(m);
li.add(getRightTypeCell(cell));
}
list.add(li);
}
}
return list;
}
2. 2007 Excel
/**
* @Description(2007 Excel 导入)
* @Param: [in]
* @return: java.util.List<java.util.List < java.lang.Object>>
* @Date: 2019/5/18
*/
public static List<List<Object>> getDataFromExcel_07(InputStream in) throws Exception {
List<List<Object>> list = new ArrayList<List<Object>>();
Workbook workbook = new XSSFWorkbook(in);
//遍历sheet
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
Sheet sheet = workbook.getSheetAt(i);
if (sheet == null) {
continue;
}
//遍历某个sheet行
for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {
Row row = sheet.getRow(j);
//跳过空行和每个sheet第一行,如果没有表头需要修改
if (row == null || row.getFirstCellNum() == j) {
continue;
}
List<Object> li = new ArrayList<Object>();
for (int m = row.getFirstCellNum(); m < row.getLastCellNum(); m++) {
Cell cell = row.getCell(m);
li.add(getRightTypeCell(cell));
}
list.add(li);
}
}
return list;
}
3. 读取Excel单元格的值(03/07都可用)
/**
* @Description(把Cell原有数据转换成String类型 2003/2007 都可用)
* @Param: [cell]
* @return: java.lang.String
* @Date: 2019/5/18
*/
public static String getRightTypeCell(Cell cell) {
if (cell == null) {
return "";
}
String cellString = "";
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_STRING: // 字符串
cellString = cell.getStringCellValue();
break;
case HSSFCell.CELL_TYPE_NUMERIC: // 数字
if (HSSFDateUtil.isCellDateFormatted(cell)) {
//用于转化为日期格式
Date d = cell.getDateCellValue();
DateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
cellString = formater.format(d);
} else {
//DecimalFormat df = new DecimalFormat("###"); 只保留数字的整数部分
// 用于格式化数字,只保留两位小数
DecimalFormat df = new DecimalFormat("#.##");
cellString = df.format(cell.getNumericCellValue());
}
break;
case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
cellString = String.valueOf(cell.getBooleanCellValue());
break;
case HSSFCell.CELL_TYPE_FORMULA: // 公式
cellString = String.valueOf(cell.getCellFormula());
break;
case HSSFCell.CELL_TYPE_BLANK: // 空值
cellString = "";
break;
case HSSFCell.CELL_TYPE_ERROR: // 故障
cellString = "";
break;
default:
cellString = "ERROR";
break;
}
return cellString;
}
六、补充
1. DecimalFormat 保留小数
0:
比实际数字的位数多,不足的地方用0补上。
new DecimalFormat("00.00").format(3.14) //结果:03.14
new DecimalFormat("0.000").format(3.14) //结果: 3.140
new DecimalFormat("00.000").format(3.14) //结果:03.140
比实际数字的位数少:整数部分不改动,小数部分,四舍五入
new DecimalFormat("0.000").format(13.146) //结果:13.146
new DecimalFormat("00.00").format(13.146) //结果:13.15
new DecimalFormat("0.00").format(13.146) //结果:13.15
#:
比实际数字的位数多,不变。
new DecimalFormat("##.##").format(3.14) //结果:3.14
new DecimalFormat("#.###").format(3.14) //结果: 3.14
new DecimalFormat("##.###").format(3.14) //结果:3.14
比实际数字的位数少:整数部分不改动,小数部分,四舍五入
new DecimalFormat("#.###").format(13.146) //结果:13.146
new DecimalFormat("##.##").format(13.146) //结果:13.15
new DecimalFormat("#.##").format(13.146) //结果:13.15