今天遇到这么一个需求,将课程信息以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数据保存到数据库,并反馈给用户处理信息(导入带模板的数据)的更多相关文章

  1. Java web项目 Jxl 读取excel 并保存到数据库,(从eclipse上移动到tomact服务器上,之路径更改,)

    最开始在eclipse中测试的时候,并没有上传到服务器上,后来发现,想要读取数据必须上传服务器然后把文件删除就可以了,服务器不可以直接读取外地的文件.用到jxl 1.上传到服务器 前端 <for ...

  2. Java 用jxl读取excel并保存到数据库(此方法存在局限,仅限本地电脑操作,放在服务器上的项目,需要把文件上传到服务器,详细信息,见我的别的博客)

    项目中涉及到读取excel中的数据,保存到数据库中,用jxl做起来比较简单. 基本的思路: 把excel放到固定盘里,然后前段页面选择文件,把文件的名字传到后台,再利用jxl进行数据读取,把读取到的数 ...

  3. java用poi读取Excel表格中的数据

    Java读写Excel的包是Apache POI(项目地址:http://poi.apache.org/),因此需要先获取POI的jar包,本实验使用的是POI 3.9稳定版.Apache POI 代 ...

  4. 项目一:第四天 1、快递员的条件分页查询-noSession,条件查询 2、快递员删除(逻辑删除) 3、基于Apache POI实现批量导入区域数据 a)Jquery OCUpload上传文件插件使用 b)Apache POI读取excel文件数据

    1. 快递员的条件分页查询-noSession,条件查询 2. 快递员删除(逻辑删除) 3. 基于Apache POI实现批量导入区域数据 a) Jquery OCUpload上传文件插件使用 b) ...

  5. 使用poi读取excel数据示例

    使用poi读取excel数据示例 分两种情况: 一种读取指定单元格的值 另一种是读取整行的值 依赖包: <dependency> <groupId>org.apache.poi ...

  6. JAVA从文本文件(txt)读取一百万条数据保存到数据库

    Java读取大文本文件保存到数据库 1.追求效率 将文件读取到内存,效率比较高,经过测试读取1G左右的文本文件,机器内存消耗达到接近3个G,对内存消耗太大,不建议使用 2.通过调用第三方类库实现 通过 ...

  7. POI读取Excel数据

    POI读取Excel表格数据 * {所需相关jar下载: * commons-collections4-4.4.jar * commons-compress-1.19.jar * poi-4.1.1. ...

  8. Java开发小技巧(六):使用Apache POI读取Excel

    前言 在数据仓库中,ETL最基础的步骤就是从数据源抽取所需的数据,这里所说的数据源并非仅仅是指数据库,还包括excel.csv.xml等各种类型的数据接口文件,而这些文件中的数据不一定是结构化存储的, ...

  9. POI读取Excel内容格式化

    在用POI读取Excel内容时,经常会遇到数据格式化的问题. 比如:数字12365会变为12365.0;字符串数字123也会变为123.0,甚至会被变为科学计数法.另外日期格式化也是一个头疼的问题.其 ...

随机推荐

  1. [OS] Linux进程、线程通信方式总结

    转自:http://blog.sina.com.cn/s/blog_64b9c6850100ub80.html Linux系统中的进程通信方式主要以下几种: 同一主机上的进程通信方式 * UNIX进程 ...

  2. 【CSS】规范大纲

    文件规范: 文件分类 : 通用类 :业务类. 文件引入:行内样式(不推荐):外联引入:内联引入.(避免使用Import引入) 文件本身:文件名. 编码:UTF-8. 注释规范: 块状注释:统一缩进,在 ...

  3. java 静态类与静态方法应用场景

    静态类:工具类 例如 Array.sort(arry) 静态方法:设置文件名

  4. Qt——线程与定时器

    一.定时器QTimer类 The QTimer class provides repetitive and single-shot timers. The QTimer class provides ...

  5. Qt——基本工具的使用

    本文主要介绍在windows系统中使用C++编写Qt程序所需要的一些工具,不会具体地讲工具怎么使用. 其它系统的安装本文不会涉及,在http://wiki.qt.io/Main中,有关于各种系统qt安 ...

  6. nginx配置虚拟路径下载文件(.apk)

    公司将安卓apk文件放到服务器上,实现用户点击链接并下载 nginx version 1.14.1 nginx配置修改 server { listen 80; server_name localhos ...

  7. BZOJ5324 JXOI2018守卫(区间dp)

    对于每个区间[l,r],显然右端点r是必须放置守卫的.考虑其不能监视到的点,构成一段段区间.一个非常显然但我就是想不到的性质是,对于这样的某个区间[x,y],在(y+1,r)内的点都是不能监视到这个区 ...

  8. elasticsearch使用More like this实现基于内容的推荐

    基于内容的推荐通常是给定一篇文档信息,然后给用户推荐与该文档相识的文档.Lucene的api中有实现查询文章相似度的接口,叫MoreLikeThis.Elasticsearch封装了该接口,通过Ela ...

  9. Pku1149 PIGS 卖猪

    题目链接:ヾ(≧∇≦*)ゝ Description Emmy在一个养猪场工作.这个养猪场有M个锁着的猪圈,但Emmy并没有钥匙. 顾客会到养猪场来买猪,一个接着一个.每一位顾客都会有一些猪圈的钥匙,他 ...

  10. MQTT - Connect报文解析

    #include <bits/stdc++.h> using namespace std; int main() { ] = { /* * 固定报头: MQTT报文类型(1), 保留位 * ...