一、准备工作
前言:
近期 本人在开发《订单管理系统》项目的时候,需要从SAP系统中导出物料编码信息,然后利用Excel导入数据到订单管理系统数据库中。本篇使用SSM+BootStrap-InputFile+poi的结合方式,写一个完整的导入Excel的例子。有需要的同学可以参考。
1.1、POI依赖
如果是maven项目,在pom.xml中添加下面的依赖:
<!--POI 实现Excel的导入导出-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
workbook需要引入的jar包下载:https://download.youkuaiyun.com/download/kay523393/85404288
1.2、bootstrap-fileinput插件下载:
bootstrap-fileinput中文文档:
http://www.bootstrap-fileinput.com/examples.html
bootstrap-fileinput插件下载:
https://download.youkuaiyun.com/download/kay523393/85404018
二、代码部分
2.1、在html页面中引入BootStrap-InputFile所需要的js和css,并在html中添加Bootstrap的model弹框。
<!-- 导入excel fileinput.css-->
<link href="${pageContext.request.contextPath}/static/css/bootstrap-fileinput/fileinput.css" rel="stylesheet">
<!-- 导入excel fileinput.js -->
<script type="text/javascript" src="${pageContext.request.contextPath}/static/js/bootstrap-fileinput/fileinput.js"></script>
<!-- 导入Excel模态框(Modal) -->
<div class="modal fade" id="importTpl">
<div class="modal-dialog" style="width:800px">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" onclick="clear_batchAdd()" id="btn_close_batchAdd">×</button>
<h3 class="modal-title" id="batchAddOilDailyLabel">导入Excel</h3>
</div>
<div class="modal-body">
<div class="col-md-9 input-group">
<input id="excelUpload" type="file" name="file" class="form-control"/>
</div>
</div>
<div class="modal-body">
<input type="checkbox" id="updateSupport" name="updateSupport" title="如果数据已经存在,更新这条数据。">是否更新已经存在的数据
<a onclick="$.table.importTemplate()" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> 下载模板</a>
<p><font color="red">提示:仅允许导入“xls”或“xlsx”格式文件!</font></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
2.2、js代码中增加点击按钮弹出模态框功能和文件上传功能,增加的代码如下:
$(function(){
initUpload();
$("#upload").on("click",function(){
$("#myModal").modal("show");
});
})
function initUpload(){
//使用bootstrap-fileinput渲染
$('#excelUpload').fileinput({
language:'zh', //设置语言
uploadUrl:'${pageContext.request.contextPath}/skd/importData.action', //上传的地址
allowedFileExtensions:['xls','xlsx'], //接收的文件后缀
theme:'fa', //主题设置
dropZoneTitle:'可以将文件拖放到这里',
uploadAsync:true, //默认异步上传
showPreview:true, //是否显示预览
showUpload: true,//是否显示上传按钮
showRemove: true, //显示移除按钮
showCancel:true, //是否显示文件上传取消按钮。默认为true。只有在AJAX上传过程中,才会启用和显示
showCaption: true,//是否显示文件标题,默认为true
browseClass: "btn btn-success", //文件选择器/浏览按钮的CSS类。默认为btn btn-primary
dropZoneEnabled: true,//是否显示拖拽区域
maxFileSize: 0,//最大上传文件数限制,单位为kb,如果为0表示不限制文件大小
minFileCount: 1, //每次上传允许的最少文件数。如果设置为0,则表示文件数是可选的。默认为0
maxFileCount: 1, //每次上传允许的最大文件数。如果设置为0,则表示允许的文件数是无限制的。默认为0
previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",//当检测到用于预览的不可读文件类型时,将在每个预览文件缩略图中显示的图标。默认为<i class="glyphicon glyphicon-file"></i>
previewFileIconSettings: {
'docx': '<i ass="fa fa-file-word-o text-primary"></i>',
'xlsx': '<i class="fa fa-file-excel-o text-success"></i>',
'xls': '<i class="fa fa-file-excel-o text-success"></i>',
'pptx': '<i class="fa fa-file-powerpoint-o text-danger"></i>',
'jpg': '<i class="fa fa-file-photo-o text-warning"></i>',
'pdf': '<i class="fa fa-file-archive-o text-muted"></i>',
'zip': '<i class="fa fa-file-archive-o text-muted"></i>',
},
msgFilesTooMany: "选择上传的文件数量({n}) 超过允许的最大数值{m}!",//字符串,当文件数超过设置的最大计数时显示的消息 maxFileCount。默认为:选择上传的文件数({n})超出了允许的最大限制{m}。请重试您的上传!
elErrorContainer:'#kartik-file-errors'
}).on('change',function () {
}).on('fileuploaded',function (event,data,previewId,index) {//异步上传成功处理
swal('系统提示',data.response.result,data.response.type);
//关闭文件上传的模态对话框
$('#importTpl').modal('hide');
//重新刷新bootstrap-table数据
$('#bootstrap-table').bootstrapTable('refresh');
//清除文件输入 此方法清除所有未上传文件的预览,清除ajax文件堆栈,还清除本机文件输入
$('#excelUpload').fileinput('clear');
$('#excelUpload').fileinput('clear').fileinput('disable');
}).on('fileerror',function (event,data,msg) { //异步上传失败处理
swal('系统提示','文件上传失败','error');
});
}
2.3、Controller增加导入excel功能
/**
* 导入excel
*
*/
@RequestMapping(value = "/importData",method = {RequestMethod.GET,RequestMethod.POST},produces = "text/html;charset=UTF-8")
@ResponseBody
public String importData(@RequestParam(value = "file",required = false) MultipartFile[] file, Map<String, Integer> map){
//System.out.println("请求路径正确");
//获取文件名
//String fileName= file[0].getOriginalFilename();
//System.out.println("=========》文件名称是:"+fileName);
try{
map=materialService.batchAddMaterial(file[0]);
}catch (Exception e){
e.printStackTrace();
return "{\"result\":\"文件处理异常,您导入的模板格式不正确\", \"type\":\"error\" }";
}
if(map.get("successNum")>0) {
return "{\"result\":\"恭喜您,Excel数据导入成功!您总共导入"+map.get("total")+"条,成功"+map.get("successNum")+"条\", \"type\":\"success\" }";
}else{
return "{\"result\":\"很抱歉,Excel数据导入失败!"+map.get("repeatNum")+"条数据已存在\", \"type\":\"warning\" }";
}
}
2.4、Service增加使用poi处理Excel方法
Service接口类:
/**
* 导入Excel
*/
Map<String, Integer> batchAddMaterial(MultipartFile multipartFile) throws IOException;
ServiceImpl实现类:
/**
* 导入EXCEL
* 错误说明:poi导入excel表格数据时报java.lang.IllegalStateException: Cannot get a STRING value from a NUMERIC cell异常是因为在读取cell单元格字符串时,
* 有number类型的数据,因此需要把它转化为纯String类型,这样就不会报错了
*/
@Override
public Map<String,Integer> batchAddMaterial(MultipartFile file) throws IOException{
Map<String,Integer> map = new HashMap<>();
int total = 0; //总共上传的条数
int successNum = 0; //成功的条数
int repeatNum = 0; //重复的条数
int count = 0;
//存放excel表中所有user数据
List<SkdMaterial> skdMaterialList = new ArrayList<>();
//file.getOriginalFilename()方法 得到上传时的文件名
String fileName = file.getOriginalFilename();
//截取文件名的后缀
String suffix = fileName.substring(fileName.lastIndexOf(".")+1);
//file.getInputStream()方法 返回InputStream对象 读取文件的内容
InputStream ins = file.getInputStream();
Workbook wb = null;
/*判断文件后缀
XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。
HSSF - 提供读写Microsoft Excel XLS格式档案的功能。*/
if(suffix.equals("xlsx")){
wb = new XSSFWorkbook(ins);
}else{
wb = new HSSFWorkbook(ins);
}
//获取excel表单的sheet对象
Sheet sheet = wb.getSheetAt(0);
//总共多少列
total=sheet.getLastRowNum()-sheet.getFirstRowNum();
//如果sheet不为空,就开始遍历表中的数据
if(null != sheet){
//line = 1 :从表的第2行开始获取记录
for(int line = 1; line <= sheet.getLastRowNum();line++){
//excel表单的sheet的行对象
Row row = sheet.getRow(line);
//如果某行为空,跳出本行
if(null == row){
continue;
}
//row.getCell(3).setCellType(CellType.NUMERIC);
//BigDecimal outFluid=new BigDecimal(NumberToTextConverter.toText(row.getCell(3).getNumericCellValue()));
//获取第一个单元格的内容
row.getCell(0).setCellType(CellType.STRING);
String po = row.getCell(0).getStringCellValue();
//获取第二个单元格的内容
//String itemNumber = row.getCell(1).getStringCellValue();
row.getCell(1).setCellType(CellType.STRING);
String itemNumber = row.getCell(1).getStringCellValue();
//Integer itemNumber=new Integer(NumberToTextConverter.toText(row.getCell(1).getNumericCellValue()));
//获取第三个单元格的内容
String materielNumber = row.getCell(2).getStringCellValue();
//获取第四个单元格的内容
String materielName = row.getCell(3).getStringCellValue();
//获取第五个单元格的内容
String purchaseDate = row.getCell(4).getStringCellValue();
//获取第六个单元格的内容
String quantity = row.getCell(5).getStringCellValue();
//获取第七个单元格的内容
String unit = row.getCell(6).getStringCellValue();
//获取第八个单元格的内容
String price = row.getCell(7).getStringCellValue();
//获取第九个单元格的内容
String totalPrice = row.getCell(8).getStringCellValue();
//获取第十个单元格的内容
String currency = row.getCell(9).getStringCellValue();
SkdMaterial material = new SkdMaterial();
material.setPo(po);
material.setItemNumber(itemNumber);
material.setMaterielNumber(materielNumber);
material.setMaterielName(materielName);
material.setPurchaseDate(purchaseDate); //采购日期
material.setQuantity(quantity);
material.setUnit(unit); //单位
material.setPrice(price); //单价
material.setTotalPrice(totalPrice);//总价
material.setCurrency(currency); //币种
skdMaterialList.add(material);
}
for(SkdMaterial skdMaterial:skdMaterialList){
/**
* 判断数据库表中是否存在用户记录,若存在,则更新,不存在,则保存记录
*/
count = skdMaterialMapper.selectCount(skdMaterial.getPo(),skdMaterial.getItemNumber());
if(count == 0){
successNum++; //成功的条数
skdMaterialMapper.insertSelective(skdMaterial);
}else{
repeatNum++;//重复的条数
skdMaterialMapper.updateByPrimaryKeySelective(skdMaterial);
}
}
}
map.put("total", total); //总共导入的条数
map.put("successNum", successNum); //成功导入的条数
map.put("repeatNum", repeatNum); //重复的的条数
return map;
}
2.4、使用
前端页面
准备导入的excel数据
点击“选择“按钮,弹出弹框,选择刚刚创建的文件,并上传文件。
实现的效果如下: