自己救赎之路--Java(Execl导入)
来源:互联网 发布:ntfs for mac 知乎 编辑:程序博客网 时间:2024/05/22 13:41
Execl导入和数据读取
说一下,第一次用IDEA开发Springboot网站,做了一个execl的导入和execl的数据读取,来跟大家分享一下遇到坑,又是如何解决的。
项目的创建
- 第一步,首先创建新项目,上图
上图就是用springboot创建好的项目和目录结构,来上手操作吧!不会百度一大堆
- 第二步,添加控制器,添加页面,写代码
贴上home类的代码
package com.example.demo.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;/** * Created by chenwangming on 2017/7/25. */@Controller@RequestMapping("/")public class Home { @RequestMapping("/index") public String Index(){ return "/index"; } @RequestMapping("/import") public void execlImport() { System.out.print("lal"); }}
上图是我在demo包下添加了一个controller包,在控制器包下创建了一个Home控制器类,以及Home类的相关代码
- 第三步,添加页面,这里我们使用的模板页面
页面是创建在templates目录下的,如上图所示
现在,我们就来运行一下,看看效果如何
结果发现了错了,这页面出来,所以我就找问题,在网上搜索,原来问题的所在是这样的,有2中解决方法,作用都是一样的。
第一种:在pom.xml 中引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
模板依赖第二种:是在创建项目的时候勾选上模板,如图所示
问题解决了,来运行看一下效果:
Execl的导入和读取
因为我之前是做.net 的,所以,我想原理可能是一样的,都是通过form表单把file文件上传到服务器,也就是后台,再在后台通过execl组件来读取内容和处理内容。好了开始动手做了。
- 第一步,在页面添加form 表单 和file上传控件,如下代码所示
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"/> <title>Title</title> <script src="../../js/jquery-3.2.1.min.js"></script></head><body><div style="width: 100%;height: 50px;background-color: beige"> <form id="form1" action="/import" method="post" enctype="multipart/form-data"> <input type="file" id="files" name="files" style="display: none"/> </form> <button id="btnExecl" >导入execl</button></div></body></html><script type="text/javascript"> $(function () { $("#btnExecl").click(function () { $("#files").click(); }) $("#files").change(function () { $("#form1").submit(); }) })();</script>
- 第二步,在后台接受表单传过来的文件,如下代码所示
/** * execl文件导入 */ @RequestMapping("/import") public void execlImport (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全 //String savePath = this.getServletContext().getRealPath("/WEB-INF/upload"); //上传时生成的临时文件保存目录 //String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp"); String savePath = "D:\\fileupload\\upload"; File tmpFile = new File(savePath); if (!tmpFile.exists()) { //创建临时目录 tmpFile.mkdir(); } //消息提示 String message = ""; try { //使用Apache文件上传组件处理文件上传步骤: //1、创建一个DiskFileItemFactory工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。 factory.setSizeThreshold(1024 * 100);//设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB //设置上传时生成的临时文件的保存目录 factory.setRepository(tmpFile); //2、创建一个文件上传解析器 ServletFileUpload upload = new ServletFileUpload(factory); //监听文件上传进度 upload.setProgressListener(new ProgressListener() { public void update(long pBytesRead, long pContentLength, int arg2) { System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead); /** * 文件大小为:14608,当前已处理:4096 文件大小为:14608,当前已处理:7367 文件大小为:14608,当前已处理:11419 文件大小为:14608,当前已处理:14608 */ } }); //解决上传文件名的中文乱码 upload.setHeaderEncoding("UTF-8"); //3、判断提交上来的数据是否是上传表单的数据 if (!ServletFileUpload.isMultipartContent(request)) { //按照传统方式获取数据 return; } //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB upload.setFileSizeMax(1024 * 1024); //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB upload.setSizeMax(1024 * 1024 * 10); //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项 List<FileItem> list = upload.parseRequest(request); for (FileItem item : list) { //如果fileitem中封装的是普通输入项的数据 if (item.isFormField()) { String name = item.getFieldName(); //解决普通输入项的数据的中文乱码问题 String value = item.getString("UTF-8"); //value = new String(value.getBytes("iso8859-1"),"UTF-8"); System.out.println(name + "=" + value); } else {//如果fileitem中封装的是上传文件 //得到上传的文件名称, String filename = item.getName(); System.out.println(filename); if (filename == null || filename.trim().equals("")) { continue; } //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt //处理获取到的上传文件的文件名的路径部分,只保留文件名部分 filename = filename.substring(filename.lastIndexOf("\\") + 1); //得到上传文件的扩展名 String fileExtName = filename.substring(filename.lastIndexOf(".") + 1); //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法 System.out.println("上传的文件的扩展名是:" + fileExtName); //获取item中的上传文件的输入流 InputStream in = item.getInputStream(); //得到文件保存的名称 String saveFilename = makeFileName(filename); //得到文件的保存目录 String realSavePath = makePath(saveFilename, savePath); //创建一个文件输出流 FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename); //创建一个缓冲区 byte buffer[] = new byte[1024]; //判断输入流中的数据是否已经读完的标识 int len = 0; //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据 while ((len = in.read(buffer)) > 0) { //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中 out.write(buffer, 0, len); } //关闭输入流 in.close(); //关闭输出流 out.close(); //删除处理文件上传时生成的临时文 //item.delete(); message = "文件上传成功!"; } } }catch (FileUploadBase.FileSizeLimitExceededException e) { e.printStackTrace(); //request.setAttribute("message", "单个文件超出最大值!!!"); //request.getRequestDispatcher("/message.jsp").forward(request, response); return; }catch (FileUploadBase.SizeLimitExceededException e) { e.printStackTrace(); //request.setAttribute("message", "上传文件的总的大小超出限制的最大值!!!"); //request.getRequestDispatcher("/message.jsp").forward(request, response); return; }catch (Exception e) { message = "文件上传失败!"; e.printStackTrace(); } request.setAttribute("message",message); //request.getRequestDispatcher("/message.jsp").forward(request, response); } /** * @Method: makeFileName * @Description: 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称 * @Anthor:孤傲苍狼 * @param filename 文件的原始名称 * @return uuid+"_"+文件的原始名称 */ private String makeFileName(String filename) { //2.jpg //为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名 return UUID.randomUUID().toString() + "_" + filename; } /** * 为防止一个目录下面出现太多文件,要使用hash算法打散存储 * @Method: makePath * @Description: * @Anthor:孤傲苍狼 * * @param filename 文件名,要根据文件名生成存储目录 * @param savePath 文件存储路径 * @return 新的存储目录 */ private String makePath(String filename,String savePath){ //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址 int hashcode = filename.hashCode(); int dir1 = hashcode&0xf; //0--15 int dir2 = (hashcode&0xf0)>>4; //0-15 //构造新的保存目录 String dir = savePath + "\\" + dir1 + "\\" + dir2; //upload\2\3 upload\3\5 //File既可以代表文件也可以代表目录 File file = new File(dir); //如果目录不存在 if(!file.exists()){ //创建目录 file.mkdirs(); } return dir; }
说句实话,虽然我懂.net的代码,但是毕竟Java做的少,我想肯定有写好的完整的代码示例,于是就在网上找了个不错的代码贴过来改改,上面的代码就是贴过的,原文链接:http://www.cnblogs.com/xdp-gacl/p/4200090.html ,不过我发现是有问题的,来给大家剖析一下问题。
经过调试,发现没有获取到文件,如下图
看来有些代码也是不靠谱的,还是要自己解决,就在网上各种搜索问题,总结如下:
我是在SpringBoot下测试时,发现的该问题,即在解析请求时List list = upload.parseRequest(request);得到的list size=0,也就是根本没有得到文件数据。我在网上搜索该问题的解决方法,大致有以下两种:(1)原因在于spring的配置文件中已经配置了MultipartResolver,导致文件上传请求已经被预处理过了,所以此处解析文件列表为空,对应的做法是删除该段配置。
(2)认为是structs的过滤器导致请求已被预处理,所以也要修改对应过滤器的配置。
然而,在SpringBoot下,上述两种解决方法不可能做到,因为SpringBoot的相关配置都是自己完成的,根本没有显示的配置文件。况且以上两种解决方法,修改配置文件可能影响整个工程的其他部分,所以得另寻方案。对了给大家贴上原文地址:http://blog.csdn.net/u013248535/article/details/55823364
- 第三步,只能修改后台代码了,来看修改后的代码
/** * execl文件导入 */ @RequestMapping("/import") public void execlImport (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //保存文件路径 String savePath = "D:\\fileupload\\upload"; String message=""; String realSavePath=""; String saveFilename=""; //强制转换request StandardMultipartHttpServletRequest req = (StandardMultipartHttpServletRequest) request; try { Iterator<String> iterator = req.getFileNames(); while (iterator.hasNext()) { MultipartFile file = req.getFile(iterator.next()); String fileNames = file.getOriginalFilename(); int split = fileNames.lastIndexOf("."); //文件名 String substring = fileNames.substring(0, split); //文件格式 String substring1 = fileNames.substring(split + 1, fileNames.length()); //文件内容 byte[] bytes = file.getBytes(); //存储文件 //文件大小 long size = file.getSize(); //文件扩展名 String extension = fileNames.substring(split + 1, fileNames.length()); //获取item中的上传文件的输入流 InputStream in = file.getInputStream(); //得到文件保存的名称 saveFilename = makeFileName(fileNames); //得到文件的保存目录 realSavePath = makePath(saveFilename, savePath); //创建一个文件输出流 FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename); //创建一个缓冲区 byte buffer[] = new byte[1024]; //判断输入流中的数据是否已经读完的标识 int len = 0; //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据 while ((len = in.read(buffer)) > 0) { //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中 out.write(buffer, 0, len); } //关闭输入流 in.close(); //关闭输出流 out.close(); message="上传成功!"; } } catch (IOException e) { message="上传失败!"; e.printStackTrace(); } request.setAttribute("message",message); //request.getRequestDispatcher("/message.jsp").forward(request, response); } /** * @Method: makeFileName * @Description: 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称 * @Anthor:孤傲苍狼 * @param filename 文件的原始名称 * @return uuid+"_"+文件的原始名称 */ private String makeFileName(String filename) { //2.jpg //为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名 return UUID.randomUUID().toString() + "_" + filename; } /** * 为防止一个目录下面出现太多文件,要使用hash算法打散存储 * @Method: makePath * @Description: * @Anthor:孤傲苍狼 * * @param filename 文件名,要根据文件名生成存储目录 * @param savePath 文件存储路径 * @return 新的存储目录 */ private String makePath(String filename,String savePath){ //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址 int hashcode = filename.hashCode(); int dir1 = hashcode&0xf; //0--15 int dir2 = (hashcode&0xf0)>>4; //0-15 //构造新的保存目录 String dir = savePath + "\\" + dir1 + "\\" + dir2; //upload\2\3 upload\3\5 //File既可以代表文件也可以代表目录 File file = new File(dir); //如果目录不存在 if(!file.exists()){ //创建目录 file.mkdirs(); } return dir; }
我对Java的好多类库不是很熟,不能像.net 一样知道的那么多,所有就一遍查阅资料,一边调试的看效果,不过这可以上传文件了
- 第四步,上传本地文件到服务器,来看效果图
这是上传图片成功后的截图。
- 第五步,读取execl数据,贴代码
/** * 解析execl文件 * @param path */ private void analysisExecl(String path) throws IOException, ParseException { ImportExeclHelper poi =new ImportExeclHelper(); List<List<String>> list=poi.read(path); List<Users> uselist=new ArrayList<Users>(); if (list != null) { for (int i = 0; i < list.size(); i++) { System.out.print("第" + (i) + "行"); if(i>1) { Users u=new Users(); List<String> cellList = list.get(i);// for (int j = 0; j < cellList.size(); j++)// { u.setAddress(cellList.get(4)); u.setAge((int)(Double.parseDouble(cellList.get(2))));// String timedata=cellList.get(5); SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy",Locale.UK); // SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd"); Date date = sdf.parse(cellList.get(5)); //String format1 = format.format(date); u.setCreatetime(date); u.setLight(Double.parseDouble(cellList.get(3))); u.setPostil(cellList.get(0)); u.setUsername(cellList.get(1));// System.out.print(" 第" + (j + 1) + "列值:");// System.out.print(" " + cellList.get(j));// } uselist.add(u); } System.out.println(uselist); } } }
package com.hma.controllers;import org.apache.poi.hssf.usermodel.HSSFCell;import org.apache.poi.hssf.usermodel.HSSFDateUtil;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.apache.poi.ss.usermodel.*;import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.Date;import java.util.List;/** * Created by chenwangming on 2017/7/24. */public class ImportExeclHelper { /** 总行数 */ private int totalRows = 0; /** 总列数 */ private int totalCells = 0; /** 错误信息 */ private String errorInfo; /** 构造方法 */ public ImportExeclHelper() { } /** * * @描述:得到总行数 * @参数:@return * @返回值:int */ public int getTotalRows() { return totalRows; } /** * * @描述:得到总列数 * @参数:@return * @返回值:int */ public int getTotalCells() { return totalCells; } /** * * @描述:得到错误信息 * @参数:@return * @返回值:String */ public String getErrorInfo() { return errorInfo; } /** * * @描述:验证excel文件 * @参数:@param filePath 文件完整路径 * @参数:@return * @返回值:boolean */ public boolean validateExcel(String filePath) { /** 检查文件名是否为空或者是否是Excel格式的文件 */ if (filePath == null || !(WDWUtil.isExcel2003(filePath) || WDWUtil.isExcel2007(filePath))) { errorInfo = "文件名不是excel格式"; return false; } /** 检查文件是否存在 */ File file = new File(filePath); if (file == null || !file.exists()) { errorInfo = "文件不存在"; return false; } return true; } /** * * @描述:根据文件名读取excel文件 * @参数:@param filePath 文件完整路径 * @参数:@return * @返回值:List */ public List<List<String>> read(String filePath) { List<List<String>> dataLst = new ArrayList<List<String>>(); InputStream is = null; try { /** 验证文件是否合法 */ if (!validateExcel(filePath)) { System.out.println(errorInfo); return null; } /** 判断文件的类型,是2003还是2007 */ boolean isExcel2003 = true; if (WDWUtil.isExcel2007(filePath)) { isExcel2003 = false; } /** 调用本类提供的根据流读取的方法 */ File file = new File(filePath); is = new FileInputStream(file); dataLst = read(is, isExcel2003); is.close(); } catch (Exception ex) { ex.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { is = null; e.printStackTrace(); } } } /** 返回最后读取的结果 */ return dataLst; } /** * * @描述:根据流读取Excel文件 * @参数:@param inputStream * @参数:@param isExcel2003 * @参数:@return * @返回值:List */ public List<List<String>> read(InputStream inputStream, boolean isExcel2003) throws IOException { List<List<String>> dataLst = null; try { /** 根据版本选择创建Workbook的方式 */ Workbook wb = null; if (isExcel2003) { wb = new HSSFWorkbook(inputStream); } else { wb = new XSSFWorkbook(inputStream); } dataLst = read(wb); } catch (IOException e) { e.printStackTrace(); } return dataLst; } /** * * @描述:读取数据 * @参数:@param Workbook * @参数:@return * @返回值:List<List<String>> */ private List<List<String>> read(Workbook wb) { List<List<String>> dataLst = new ArrayList<List<String>>(); /** 得到第一个shell */ Sheet sheet = wb.getSheetAt(0); /** 得到Excel的行数 */ this.totalRows = sheet.getPhysicalNumberOfRows(); /** 得到Excel的列数 */ if (this.totalRows >= 1 && sheet.getRow(0) != null) { this.totalCells = sheet.getRow(0).getPhysicalNumberOfCells(); } /** 循环Excel的行 */ for (int r = 0; r < this.totalRows; r++) { Row row = sheet.getRow(r); if (row == null) { continue; } List<String> rowLst = new ArrayList<String>(); /** 循环Excel的列 */ for (int c = 0; c < this.getTotalCells(); c++) { Cell cell = row.getCell(c); if(cell.getCellComment()!=null) { rowLst.add(cell.getCellComment().getString().toString()); } String cellValue = ""; if (null != cell) { // 以下是判断数据的类型 switch (cell.getCellType()) { case HSSFCell.CELL_TYPE_NUMERIC: // 数字 if (HSSFDateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue() ; cellValue=date.toString(); }else{ cellValue = cell.getNumericCellValue() + ""; } //cellValue= cell.getDateCellValue(); break; case HSSFCell.CELL_TYPE_STRING: // 字符串 cellValue = cell.getStringCellValue(); break; case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean cellValue = cell.getBooleanCellValue() + ""; break; case HSSFCell.CELL_TYPE_FORMULA: // 公式 cellValue = cell.getCellFormula() + ""; break; case HSSFCell.CELL_TYPE_BLANK: // 空值 cellValue = ""; break; case HSSFCell.CELL_TYPE_ERROR: // 故障 cellValue = "非法字符"; break; default: cellValue = "未知类型"; break; } } rowLst.add(cellValue); } /** 保存第r行的第c列 */ dataLst.add(rowLst); } return dataLst; }}/** * * @描述:工具类 */class WDWUtil{ /** * * @描述:是否是2003的excel,返回true是2003 * @参数:@param filePath 文件完整路径 * @参数:@return * @返回值:boolean */ public static boolean isExcel2003(String filePath) { return filePath.matches("^.+\\.(?i)(xls)$"); } /** * * @描述:是否是2007的excel,返回true是2007 * @参数:@param filePath 文件完整路径 * @参数:@return * @返回值:boolean */ public static boolean isExcel2007(String filePath) { return filePath.matches("^.+\\.(?i)(xlsx)$"); }}
这个是读取execl方法,然后转化成Users类 ,打印出来。 不过这里面还有个ImportExeclHelper 帮助类,我也给贴出来了,如上代码所示。
说一下,读取execl 遇到的问题吧!
1 . word中的日期读取出来是42900.0格式的,也不是时间戳,所以尝试了很多种方法不没有搞定,后来加了
if (HSSFDateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue() ; cellValue=date.toString(); }else{ cellValue = cell.getNumericCellValue() + ""; }
这判断后才勉强转化成日期格式,这段在代码中有,希望大家有更好建议。
2 . 我对java的日期转换是一头雾水,跟.net的真心不一样,百度了好多次,才转换成功,如下代码
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy",Locale.UK); Date date = sdf.parse(cellList.get(5));
好了,今天的内容就写到这里了,很感谢那些遇到问题分享给大家的人,才让我们提高解决问题的效率,从我做起,一起发现问题,解决问题,感谢大家多多支持,再次感谢两位原文链接的博主,让我一个没有做过Java的人很容易的实现我想要的功能!
技术交流群:210470210
- 自己救赎之路--Java(Execl导入)
- 自我救赎之路--java(jar包导入)
- 自我救赎之路--Java(数据处理)
- Execl导入notes JAVA代理
- Java做execl导入数据库
- 自我救赎之路--Java(图片处理)
- 自我救赎之路--Java(Intellij IDEA)
- 自我救赎之路—Java(HttpClient请求)
- Execl导入问题之文本转换
- java对Execl的导入导出
- 一位大学生的自我救赎之路
- java对execl的导入、导出操作-- POI / JXL
- java对execl的导入、导出操作-- POI / JXL .
- Java实现对execl的导入和导出
- php导入execl
- Execl数据导入数据库
- execl导入mysql
- c# datatable导入execl
- Load Data使用方法
- 接口的方法与变量
- mysql写存储过程的一些注意事项以及mysql的一些函数
- Eclipse安装Sequoyah插件 配置本机开发报错Native Development: Invalid path for NDK(路径无效) 解决方案
- Maven Archetypes Part 3: 怎样构建一个多模块工程?
- 自己救赎之路--Java(Execl导入)
- Integer==陷阱
- AngularJS Select(选择框)
- 用java中DefaultTableModel类实现对表格的增删操作
- 移动端的touch事件
- Mac中如何卸载pkg包
- unique函数的使用方法(STL库函数)
- c库函数
- Java中常见的5种WEB服务器介绍