POI读取Excel数据保存到数据库,并反馈给用户处理信息(导入带模板的数据)
今天遇到这么一个需求,将课程信息以Excel的形式导入数据库,并且课程编号再数据库中不能重复,也就是我们需要先读取Excel提取信息之后保存到数据库,并将处理的信息反馈给用户。于是想到了POI读取文件提取数据,也可以利用Jxl读取Excel提取数据。
最终效果:
对于下面的Excel,总共20条数据。18条在数据库已经存在,最后两条是在同一个excel文件中重复在数据库不存在。

反馈结果:(也就是最后两个X6511只保存了一条)

思路:
1.先将Excel文件上传到本地,保存到本地磁盘
2.读取本地磁盘的Excel,并且提取数据封装成集合。
3.对提取的信息进行处理,也就是保存数据库,保存数据库之前先判断是否已经存在相同的编号,如果存在就不保存数据库,并且将存在的编号记录到一个集合中,最后根据此集合返回给用户信息。
前端文件上传是layui,后端接收文件是springMVC,处理Excel是POI
0.界面准备文件上传的button
<button class="layui-btn layui-btn-warm" type="button" id="importCoursesBtn" style="float: right"><i class="layui-icon"></i>导入课程</button>
1.前端:layui的文件上传JS
/********S 导入课程相关操作******/
layui.use(['layer','upload'],function () {//使用文件上传和layer模块
var layer =layui.layer,upload = layui.upload;
var uploadInst = upload.render({
elem: '#importCoursesBtn',//绑定的元素
url: contextPath+'/uploadCourseExcel.do',//提交的url
auto:true,//是否自动上传
accept:"file",//指定允许上传的文件类型
multiple:false,//支持多文件上传
exts:'xls|xlsx',
done: function(res, index, upload){ //假设code=0代表上传成功
layer.close(layer.index); //它获取的始终是最新弹出的某个层,值是由layer内部动态递增计算的
layer.alert(res.msg);
}
}); })
/********E 导入课程相关操作******/
2.后端Controller层代码:
主要就是:
保存文件到本地
读取本地的excel文件,提取数据
处理提取之后的数据(也就是调用service层对提取的数据集合进行保存)
根据Service返回的重复的编号的集合以及提取的数据集合判断添加结果并反馈给用户。
package cn.xm.jwxt.controller.trainScheme; import cn.xm.jwxt.bean.trainScheme.TCourseBaseInfo;
import cn.xm.jwxt.service.trainScheme.CourseBaseInfoService;
import cn.xm.jwxt.utils.FileHandleUtil;
import cn.xm.jwxt.utils.ResourcesUtil;
import cn.xm.jwxt.utils.ResposeResult;
import cn.xm.jwxt.utils.UUIDUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile; import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List; /**
* @Author: qlq
* @Description 导入课程信息(以Excel模板的形式导入)
* @Date: 11:04 2018/5/5
*/ /**
* 导入课程(以Excel的形式导入)
* 1.导入文件,将文件保存到本地
* 2.读取Excel提取课程信息
* 3.进行数据库保存
* 4.反馈导入信息
*/
@Controller
public class ImportCourseExcel {
private Logger logger = Logger.getLogger(ImportCourseExcel.class);//日志记录器
@Autowired
private CourseBaseInfoService courseBaseInfoService;//课程service
/**
* 导入课程信息(以课程信息导入)
* @param file
* @return
*/
@RequestMapping("/uploadCourseExcel")
public @ResponseBody
ResposeResult uploadCourseExcel(MultipartFile file){
ResposeResult resposeResult = new ResposeResult();
String fileOriName = null;
String fileNowName = null;
if(file == null){
resposeResult.setMsg("请上传正确的Excel文件");
return resposeResult;
}
//1.保存文件到本地
fileOriName = file.getOriginalFilename();//获取原名称
fileNowName = UUIDUtil.getUUID2()+"."+ FilenameUtils.getExtension(fileOriName);//生成唯一的名字 try {
fileNowName = FileHandleUtil.uploadSpringMVCFile(file, "courseExcelFileImport", fileNowName);//保存文件
} catch (Exception e) {
resposeResult.setMsg("请上传正确的Excel文件");
logger.error("导入课程信息失败失败",e);
}
//2.读取文件
String fileQualifyName = ResourcesUtil.getValue("path","courseExcelFileImport")+fileNowName;//生成文件全路径
List<TCourseBaseInfo> tCourseBaseInfos = this.readExcelData(fileQualifyName);//读取的Excel数据
if(tCourseBaseInfos == null || tCourseBaseInfos.size()==0){
resposeResult.setMsg("您上传的文件没有课程信息,请重新编辑");
return resposeResult;
}
//3.保存数据库
List<String> repeatCourseNums = null;
try {
repeatCourseNums = courseBaseInfoService.addCourseBaseInfoBatch(tCourseBaseInfos);
} catch (SQLException e) {
resposeResult.setMsg("保存数据库的时候出错");
logger.error("保存数据库出错");
}
//4.根据返回结果判断重复的数据与条数。
int allTotal = tCourseBaseInfos.size();
// 4.1如果重复的集合为空则证明全部上传成功
if(repeatCourseNums == null || repeatCourseNums.size()==0){
resposeResult.setMsg(allTotal+"条课程信息全部上传成功");
}else {//4.2如果有重复提示哪些重复了
int repeatSize = repeatCourseNums.size();
resposeResult.setMsg("总共"+allTotal+"条数据,成功上传"+(allTotal - repeatSize)+"条,重复了"+repeatSize+"条。"+"重复的课程编号为"+repeatCourseNums.toString());
}
return resposeResult;
} /**
* 读取Excel提取数据(返回提取的数据集合)
* @param fileQualifyName
* @return
*/
private List<TCourseBaseInfo> readExcelData(String fileQualifyName) {
List<TCourseBaseInfo> datas = null;
File file = new File(fileQualifyName);
try {
// 获取一个工作簿
HSSFWorkbook workbook = new HSSFWorkbook(FileUtils.openInputStream(file));
// 获取一个工作表两种方式
// HSSFSheet sheet = workbook.getSheet("sheet0");
// 获取工作表的第二种方式
HSSFSheet sheet = workbook.getSheetAt(0);
int firstRow = 1;
// 获取sheet的最后一行
int lastRow = sheet.getLastRowNum();
if(lastRow <2){//如果只有1行或者0行就直接退出
return null;
}
datas = new ArrayList<TCourseBaseInfo>();//用于返回的数据集合
//循环内不要创建对象引用(集合中存的是对象的引用)
TCourseBaseInfo courseBaseInfo = null;
for(int i=firstRow;i<=lastRow;i++){
courseBaseInfo = new TCourseBaseInfo();
HSSFRow row = sheet.getRow(i);
int lastCol = row.getLastCellNum();
if(lastCol != 14){
//如果不是14列就不读这一行了。
continue;
}
for(int j=0;j<lastCol;j++){
HSSFCell cell= row.getCell(j);//获取一个cell
if (j == 0) {
courseBaseInfo.setCoursenum(cell.getStringCellValue());//课程编号
continue;
}
if (j == 1) {
courseBaseInfo.setCourseplatform(cell.getStringCellValue());//课程平台
continue;
}
if (j == 2) {
courseBaseInfo.setCoursenature(cell.getStringCellValue());//课程性质
continue;
}
if (j == 3) {
courseBaseInfo.setCoursenamecn(cell.getStringCellValue());//中文名称
continue;
}
if (j == 4) {
courseBaseInfo.setCoursenameen(cell.getStringCellValue());//英文名称
continue;
}
if (j == 5) {
courseBaseInfo.setCredit(cell.getStringCellValue());//学分
continue;
}
if (j == 6) {
courseBaseInfo.setCoursehour(cell.getStringCellValue());//学时
continue;
}
if (j == 7) {
courseBaseInfo.setTeachhour(cell.getStringCellValue());//讲课时长
continue;
}
if (j == 8) {
courseBaseInfo.setExperimenthour(cell.getStringCellValue());//实验时长
continue;
}
if (j == 9) {
courseBaseInfo.setComputerhour(cell.getStringCellValue());//上机时长
continue;
}
if (j == 10) {
courseBaseInfo.setPracticehour(cell.getStringCellValue());//实践时长
continue;
}
if (j == 11) {
courseBaseInfo.setWeeklyhour(cell.getStringCellValue());//周学时分配
continue;
}
if (j == 12) {
courseBaseInfo.setScoringway(cell.getStringCellValue());//计分方式
continue;
}
if (j == 13) {
courseBaseInfo.setCoursehourmethod(cell.getStringCellValue());//学时单位
continue;
}
}
//读完一行将数据塞进去
datas.add(courseBaseInfo);
}
} catch (IOException e) {
logger.error("读取上传的Excel出错");
}
return datas;
}
}
Service对提取到的list集合进行批量保存的代码:
主要就是遍历集合,获取课程编号判断数据库中是否已经存在相同编号的数据,如果已经存在则此条数据不保存数据库并将编号加到重复的list集合。
@Override
public int getCountByCourseNum(String courseNum) throws SQLException {
return tCourseBaseInfoCustomMapper.getCountByCourseNum(courseNum);
} @CacheEvict(value = "coursesFy",allEntries =true )//清掉分页的redis缓存
@Override
public boolean addCourseBaseInfo(TCourseBaseInfo courseBaseInfo) throws SQLException {
//如果传下来的课程信息的id为空,就用UUID生成一个ID
if(ValidateCheck.isNull(courseBaseInfo.getCourseid())){
courseBaseInfo.setCourseid(UUIDUtil.getUUID2());
}
// remark1用于标记是否正在使用,1代表正在使用,0代表已经删除。
if(ValidateCheck.isNull(courseBaseInfo.getRemark1())){
courseBaseInfo.setRemark1(DefaultValue.IS_USE);
}
return tCourseBaseInfoMapper.insert(courseBaseInfo)>0?true:false;
} @Override
public List<String> addCourseBaseInfoBatch(List<TCourseBaseInfo> courseBaseInfos) throws SQLException {
//1.遍历集合进行添加。
//1.1如果已经存在相同的课程编号,将该课程的编号加到返回的集合中,用于提示哪些编号重复了
List<String> repeatCourseNums = new ArrayList<String>();
for(TCourseBaseInfo tCourseBaseInfo :courseBaseInfos){
//如果课程编号为空结束本次循环开始下一次
if(ValidateCheck.isNull(tCourseBaseInfo.getCoursenum())){
continue;
}
//根据数据库是否已经存在相同的课程编号决定是否可以保存课程信息
int result = this.getCountByCourseNum(tCourseBaseInfo.getCoursenum());
if(result >= 1){//如果存在就不添加并保存到重复的元素集合
repeatCourseNums.add(tCourseBaseInfo.getCoursenum());
}else {//不存在就可以添加
this.addCourseBaseInfo(tCourseBaseInfo);
}
}
return repeatCourseNums;
}
解释:
1.文件保存的工具方法:
/******* S针对SptingMVC的上传文件的处理 *************/
/**
* 专门针对SpringMVC的文件上传操作
* @param multipartFile 文件参数
* @param propertiesKey 需要读取的path里面的key
* @param fileName 文件名字,比如: ce5bd946fd43410c8a26a6fa1e9bf23c.pdf
* @return 返回值是最后的文件名字,如果是word需要转成pdf,1.doc返回值就是1.pdf
*/
public static String uploadSpringMVCFile(MultipartFile multipartFile,String propertiesKey,String fileName) throws Exception {
String fileDir = FileHandleUtil.getValue("path", propertiesKey);// 获取文件的基本目录
//1.将文件保存到指定路径
multipartFile.transferTo(new File(fileDir+fileName));//保存文件
//2.根据文件后缀判断文件是word还是pdf,如果是word需要转成pdf,其他的话不做处理
String fileNameSuffix = FilenameUtils.getExtension(fileName);//调用io包的工具类获取后缀
if("doc".equals(fileNameSuffix)||"docx".equals(fileNameSuffix)){//如果后缀是doc或者docx的话转为pdf另存一份
String fileNamePrefix = FilenameUtils.getBaseName(fileName);//获取文件前缀名字
Word2PdfUtil.word2pdf(fileDir+fileName,fileDir+fileNamePrefix+".pdf");//进行word转换pdf操作
fileName = fileNamePrefix+".pdf";//并将文件的名字换成新的pdf名字
}
return fileName;
}
/******* E针对SptingMVC的上传文件的处理 *************/
补充:今天在读取数字111的时候遇到这样一个问题,读取111为字符串报错,解决办法:
cell.setCellType(Cell.CELL_TYPE_STRING);
POI读取Excel数据保存到数据库,并反馈给用户处理信息(导入带模板的数据)的更多相关文章
- Java web项目 Jxl 读取excel 并保存到数据库,(从eclipse上移动到tomact服务器上,之路径更改,)
最开始在eclipse中测试的时候,并没有上传到服务器上,后来发现,想要读取数据必须上传服务器然后把文件删除就可以了,服务器不可以直接读取外地的文件.用到jxl 1.上传到服务器 前端 <for ...
- Java 用jxl读取excel并保存到数据库(此方法存在局限,仅限本地电脑操作,放在服务器上的项目,需要把文件上传到服务器,详细信息,见我的别的博客)
项目中涉及到读取excel中的数据,保存到数据库中,用jxl做起来比较简单. 基本的思路: 把excel放到固定盘里,然后前段页面选择文件,把文件的名字传到后台,再利用jxl进行数据读取,把读取到的数 ...
- java用poi读取Excel表格中的数据
Java读写Excel的包是Apache POI(项目地址:http://poi.apache.org/),因此需要先获取POI的jar包,本实验使用的是POI 3.9稳定版.Apache POI 代 ...
- 项目一:第四天 1、快递员的条件分页查询-noSession,条件查询 2、快递员删除(逻辑删除) 3、基于Apache POI实现批量导入区域数据 a)Jquery OCUpload上传文件插件使用 b)Apache POI读取excel文件数据
1. 快递员的条件分页查询-noSession,条件查询 2. 快递员删除(逻辑删除) 3. 基于Apache POI实现批量导入区域数据 a) Jquery OCUpload上传文件插件使用 b) ...
- 使用poi读取excel数据示例
使用poi读取excel数据示例 分两种情况: 一种读取指定单元格的值 另一种是读取整行的值 依赖包: <dependency> <groupId>org.apache.poi ...
- JAVA从文本文件(txt)读取一百万条数据保存到数据库
Java读取大文本文件保存到数据库 1.追求效率 将文件读取到内存,效率比较高,经过测试读取1G左右的文本文件,机器内存消耗达到接近3个G,对内存消耗太大,不建议使用 2.通过调用第三方类库实现 通过 ...
- POI读取Excel数据
POI读取Excel表格数据 * {所需相关jar下载: * commons-collections4-4.4.jar * commons-compress-1.19.jar * poi-4.1.1. ...
- Java开发小技巧(六):使用Apache POI读取Excel
前言 在数据仓库中,ETL最基础的步骤就是从数据源抽取所需的数据,这里所说的数据源并非仅仅是指数据库,还包括excel.csv.xml等各种类型的数据接口文件,而这些文件中的数据不一定是结构化存储的, ...
- POI读取Excel内容格式化
在用POI读取Excel内容时,经常会遇到数据格式化的问题. 比如:数字12365会变为12365.0;字符串数字123也会变为123.0,甚至会被变为科学计数法.另外日期格式化也是一个头疼的问题.其 ...
随机推荐
- 如何规范 CSS 的命名和书写
我开始学前端的时候也是对于规范问题头疼,后来看了网易的NEC规范,惊呼牛逼 NEC : 更好的CSS样式解决方案 只遵循横向顺序即可,先显示定位布局类属性,后盒模型等自身属性,最后是文本类及修饰类属性 ...
- python参数传递方式
原文地址:http://www.cnblogs.com/zhaopengcheng/p/5492183.html python中一切皆对象,函数中参数传递的是对象的引用. 1在函数中改变变量指向的对象 ...
- BZOJ 3210: 花神的浇花集会
3210: 花神的浇花集会 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 577 Solved: 299[Submit][Status][Discus ...
- BZOJ3829 [Poi2014]FarmCraft 【树形dp】
题目链接 BZOJ3829 题解 设\(f[i]\)为从\(i\)父亲进入\(i\)之前开始计时,\(i\)的子树中最晚装好的时间 同时记\(siz[i]\)为节点\(i\)子树大小的两倍,即为从父亲 ...
- idea中Hibernate错误:无法解析表
idea中Hibernate错误:无法解析表 这种情况主要是在idea中使用hibernate自定义注解,idea无法检查数据源 this inspecton controls whether the ...
- 解题:POI 2008 Station
题面 水水的换根裸题,不过以前还真没做过换根的题 换根的思想就是在DFS中利用树的信息更新出当前点为根时的信息,具体来说一般是考虑子树外和子树内两部分 每个点的答案$ans$就是$ans[fa]+n- ...
- 第一天:简单工厂模式与UML类图
何为简单工厂模式: 通过专门定义一个类,来负责创建其他类的实例,这些其它类通常具有共同的父类. 简单工厂模式的UML类图: 简单工厂模式中包含的角色和相应的职责如下: ...
- GO_10:GO语言基础之error
Go错误处理 Go 语言通过内置的错误接口提供了非常简单的错误处理机制. error类型是一个接口类型,这是它的定义: type error interface { Error() string } ...
- 逻辑回归原理_挑战者飞船事故和乳腺癌案例_Python和R_信用评分卡(AAA推荐)
sklearn实战-乳腺癌细胞数据挖掘(博客主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&a ...
- P2158 [SDOI2008]仪仗队 && 欧拉函数
P2158 [SDOI2008]仪仗队 题目描述 作为体育委员,C君负责这次运动会仪仗队的训练.仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线 ...