目录
一、效果展示
1、初始状态
导入前的页面显示:
此时对应的数据库表:
2、导入的Excel文件
3、导入后状态
导入后的页面显示:
导入后的数据库表:
4、文件信息过滤更新
倘若原始数据库中已存在 A 机构(将“结算代码”作为该机构的唯一标识),而我们新上传的文件中也包含了 A 机构的信息,则系统会检测出并直接更新该机构信息。
初始状态:
传入具有相同结算代码(意味着这两家其实为同一家机构)的数据:
上传后的页面数据:
可以看到新上传文件中的“new机构一号”与原始数据中的“机构三号”结算代码相同,因此判断出这两家实则为同一家机构,故而对“机构三号”信息进行更新(如:机构名称、地址等)。
二、实现
1、文件传递
由于项目的前端采用的是Layui框架,因此Excel在前端的接收将以该框架为例,也可以采用其它方式/框架接收文件,比如:
<input type="file">
以Layui为例:
<div class="layui-inline" style="float: right">
<button type="button" id="uploadExcel" class="layui-btn layui-btn-sm layui-btn-normal" >
<i class="layui-icon layui-icon-upload-drag"></i>
 上传文件
</button>
</div>
前端接收上传的文件:
<script type="text/javascript">
layui.use('upload', function(){
var $ = layui.jquery
,upload = layui.upload;
upload.render({
elem: '#uploadExcel' //先前定义的事件id
,url: '/department/InputExcel' //改成您自己的上传接口
,accept: 'file' //普通文件
,exts: 'xls|xlsx' //上传的文件类型
,done: function(res){
console.log(res);
if(res.msg=="ok"){
layer.msg("文件导入成功",{icon: 1, time: 1500},function(){location.reload();});
}else{
layer.msg("文件导入失败",{icon: 2, time: 1500},function(){location.reload();});
}
}
,error:function(){
layer.msg("文件导入失败",{icon: 2, time: 1500},function(){location.reload();});
}
});
})
</script>
2、Controller层
@RequestMapping(value = "/InputExcel")
@ResponseBody
public String InputExcel(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception {
String flag = "02";// 上传标志
System.out.println("进入controller层 导入excel");
System.out.println("file文件:"+file);
if (!file.isEmpty()) {
try {
String originalFilename = file.getOriginalFilename();// 原文件名字
System.out.println("文件名:" + originalFilename);
InputStream fileStream= file.getInputStream();// 获取输入流
flag = departmentService.InputExcel(fileStream, originalFilename);
System.out.println("controller层:上传成功,flag= "+flag);
return "{\"msg\":\"ok\"}";
} catch (Exception e) {
flag = "03";// 上传出错
e.printStackTrace();
System.out.println("controller层:上传失败,flag= "+flag);
}
}
return "{\"msg\":\"error\"}";
}
3、Service层
String InputExcel(InputStream fileStream, String originalFilename);
4、ServiceImplements
(1)下载并导入poi
Java中常见的用来操作 Excel 的方式有2种:JXL和POI。JXL只能对 Excel进行操作,且只支持到 Excel 95-2000的版本。Apache POI 是用Java编写的免费开源的跨平台的 Java API,其提供对Microsoft Office格式档案读和写的功能,支持处理Excel、Word、PPT等文件。借助POI,可以方便地完成生成数据报表,数据批量上传,数据备份等工作。
因此,需要先导入poi的jar包。
Apache POI下载官方网址: https://poi.apache.org/
POI使用相关讲解可参考博客:java Poi基础(一)
其次,需要编写一个ExcelUtil的工具类文件,使用poi中的函数来定义自己所需要实现的Excel的功能,以方便后续方法中进行调用。
可以参考博客:
1、java使用poi读取excel
2、Java之按行、列读excel笔记
(2)判断文件类型并读取信息
在获取到文件信息后,首先需要判断文件后缀是.xls还是.xlsx类型,并采用不同的方式读取字节流。由于在我们的ExcelUtil文件中定义的ReadExcel方法返回的是ArrayList<ArrayList>类型,因此在此处需要使用相同类型的变量进行接收。
ArrayList<ArrayList<Object>> list;
if (originalFilename.endsWith(".xls")) {
System.out.println("service层:是2003版的excel");
list = Excel.readExcel2003(fileStream);
System.out.println("list:"+list);
} else {
System.out.println("service层:是2007版的excel");
list = Excel.readExcel2007(fileStream);
System.out.println("list:"+list);
}
下图可见ReadExcel的返回类型为ArrayList<ArrayList>,里面的arraylist用于存储每一行的信息,外面的arraylist将每一行组成了一个新的数组。
此时,若对 list 中的内容进行调试输出,可以得到如下图所示的结果。
此处顺便附上java中 List 和 ArrayList 之间的区别:
1、Java中List和ArrayList的区别(加入了个人见解)
2、 java List与ArrayList区别
(3)将信息存储为键值并传递至数据库
// 导入excel
//建立Map<String,Map<String,Object>>
Map<String,Map<String,Object>> oneRowInputInfos= new HashMap<String,Map<String,Object>>();
Map<String,Object> oneRow= new HashMap<String,Object>();
// 遍历Excel表中的每一行
for (int i=0,j=list.size();i<(j-1);i++){
List<Object> row = list.get(i); //获取当前行的数据
// 将当前行数据存储进oneRow
// row.get(1).toString():当前行第二列的数据
oneRow.put("department_name", row.get(1).toString());
oneRow.put("department_phone_number", row.get(2).toString());
oneRow.put("department_address", row.get(3).toString());
// .......此处省略部分变量
oneRow.put("department_settlement_code", row.get(8).toString());
// .......此处省略部分变量
oneRow.put("depart_id", row.get(13).toString());
// 将当前行数据存储进oneRowinputInfos
oneRowInputInfos.put("keys", oneRow);
departmentDao.InputExcel(param);
System.out.println("service层:inputExcel成功");
}
return "01";
}
下图为某一行输出的oneRowInputInfos信息:
传入Dao层:
void InputExcel(Map<String, Map<String, Object>> param);
5、Mybatis:数据库信息更新
附上Mybatis中foreach语法的使用讲解:mybatis foreach标签的使用
<!--excel导入-->
<insert id="InputExcel" parameterType="hashmap" useGeneratedKeys="true">
insert into db_chx_department
<foreach collection="keys" index="key" item="value" open="(" close=")" separator=",">
${key}
</foreach>
values
<foreach collection="keys" item="value1" open="(" close=")" separator=",">
#{value1}
</foreach>
</insert>
至次即可完成文件的导入。
但如果要添加文件信息的过滤更新功能,则要增加一条语句,如下。该条语句是防止新增时有重复数据而重复插入,如果设置的字段出现了重复的数据,就会更新那条重复的数据而不是新增一条。
ON DUPLICATE key update
如此处就将选中参数(结算代码)设置为了唯一索引,因此如果出现重复的结算代码,当前数据只会被更新,而不会被重复增加。
SQL完整代码:
<!--excel导入-->
<insert id="InputExcel" parameterType="hashmap" useGeneratedKeys="true">
insert into db_chx_department
<foreach collection="keys" index="key" item="value" open="(" close=")" separator=",">
${key}
</foreach>
values
<foreach collection="keys" item="value1" open="(" close=")" separator=",">
#{value1}
</foreach>
ON DUPLICATE key update
department_settlement_code=values(department_settlement_code),department_name=values(department_name),
department_phone_number=values(department_phone_number),department_address=values(department_address),
department_settlement_scope=values(department_settlement_scope),depart_id=values(depart_id)
</insert>
阿巴阿巴阿巴...小萌新报道...如有错误,欢迎指正...