使用OCUpload和POI一键上传Excel并解析导入数据库
一、OCUpload插件的使用
1.1 OCUpload介绍
OCUpload (One Click Upload)译成中文就是一键上传的意思。它是JQuery的一个插件。
对于传统的文件上传,只能通过form表单,将enctype设置为multipart/form-data,选中文件后还需在页面点击submit提交按钮,提交表单,才能在后台接收上传的文件并进行相关字段解析,上传成功后,页面还要刷新,这样并不符合我们的某些实际需求。如果要用ajax进行文件上传达到不刷新页面的效果,这样也是不对的,因为ajax不支持文件上传,这是因为response原因,一般请求浏览器是会处理服务器输出的response,例如生成png、文件下载等,然而ajax请求只是个“字符型”的请求,即请求的内容是以文本类型存放的。文件的下载是以二进制形式进行的,虽然可以读取到返回的response,但只是读取而已,是无法执行的,说白点就是js无法调用到浏览器的下载处理机制和程序。那这时想要达到上传页面并不刷新的效果怎么把呢???我们可以这么做。
<iframe name="text" style="display:none"></iframe> <form target="text" action="xxx" method="post" enctype="multipart/form-data"> <input type="file" name="myFile"/> <input type="submit" value="upload"/> </form>
通过这种方式上传文件,刷新的页面就变成了这个iframe,而且设置的隐藏我们看不到,而我们自己所用的页面就不会刷新,通过这种方式达到了一个不刷新页面上传文件的效果。
而OCUpload就是采用了这种方式,只是进行了封装我们看不到。接下来就讲一讲怎么使用UCOpload。
1.2 OCUpload的使用步骤
第一步:将js文件引入页面
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.8.3.js"></script> <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery.ocupload-1.1.2.js"></script>
第二步:在页面中提供任意一个元素
<input id="myButton" type="button" value="上传"/>
第三步:调用插件提供的upload方法,动态修改HTML页面元素
<script type="text/javascript"> $(function () { $("#myButton").upload({ action: 'regionAction_importXls.action', //你所要向服务器请求的的路径,必填 name: 'regionFile', //上传组件的name的值,不写默认是file enctype: 'multipart/form-data', //mime类型,使用默认就好 params: {}, //请求时额外传递的参数,默认是为空的 onSelect: function (self, element) { //当用户选择了一个文件后触发事件 this.autoSubmit = false; //当选择了文件后,关闭自动提交 }, onSubmit: function (self, element) { }, //提交表单之前触发事件 autoSubmit: true, //是否自动提交,即当选择了文件,自动关闭了选择窗口后,是否自动提交请求。 onComplete: function (data, self, element) { } //提交表单完成后触发的事件 }); }); </script>
我们打开页面并上传文件后,发现html页面变成了这样:
二、Apache POI技术
2.1 POI简介
Apache POI是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”。
要使用POI,我们需要下载它的开发包,解压如下:
或者在项目中引入POI的依赖:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.11</version> </dependency>
2.2 接收上传的文件,并用POI解析
在客户端上传测试文件:
在Action中提供一个File类型的属性,名称和上传的文件输入框名称一致regionFile
@Controller @Scope("prototype") public class RegionAction extends ActionSupport implements ModelDriven<Region> { private Region region; @Autowired private IRegionService regionService; // 属性驱动,接收上传的文件 private File regionFile; public void setRegionFile(File regionFile) { this.regionFile = regionFile; } /** * 区域导入 * * @return */ public String importXls() throws IOException { List<Region> regionList = new ArrayList<>(); //使用POI解析Excel文件 HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(regionFile)); //根据名称获得指定Sheet对象 HSSFSheet hssfSheet = workbook.getSheet("Sheet1"); //遍历标签页中所有的行 for (Row row : hssfSheet) { int rowNum = row.getRowNum(); // 行号 // 如果是标题行,结束本次循环,直接进入下一次循环 if (rowNum == 0) { continue; } String id = row.getCell(0).getStringCellValue(); String province = row.getCell(1).getStringCellValue(); String city = row.getCell(2).getStringCellValue(); String district = row.getCell(3).getStringCellValue(); String postcode = row.getCell(4).getStringCellValue(); // 包装一个区域对象 Region region = new Region(id, province, city, district, postcode, null, null); regionList.add(region); } // 批量保存 regionService.saveBatch(regionList); return NONE; } @Override public Region getModel() { return region; } }
至此,Excel文件的数据就能成功传入到数据库中了
三、pinyin4J
3.1 简单介绍
上面导入的数据中,我们发现shortcode和citycode字段都为null,而原excel文件中并没有这两个字段,说明这两个字段需要我们手动生成。shortcode是省市区首字母的简写,比如河北省石家庄市桥西区的shortcode就是HBSJZQX;citycode是城市拼音的简写,比如石家庄市的citycode为shijiazhuang。这时候我们就需要使用pinyin4J来帮我们完成这个工作。
pinyin4J是一个支持将中文转换到拼音的Java开源类库,它能够根据中文字符获取其对应的拼音,并且拼音的格式可以控制。pinyin4J的基本功能有:
- 支持同一汉字有多个发音
- 支持拼音的格式化输出,比如第几声之类的
- 支持简体中文、繁体中文转换为拼音
这里是它的官方下载地址:http://pinyin4j.sourceforge.net/
3.2 入门案例
在使用pinyin4J之前,需要导入相关的jar包,或者引入pinyin4J的依赖
<!-- 引入pinyin4J的依赖 --> <dependency> <groupId>com.belerweb</groupId> <artifactId>pinyin4j</artifactId> <version>2.5.0</version> </dependency>
编写测试代码:
public class PinYin4jUtilsTest { @Test public void test1() { //河北省 石家庄市 桥西区 String province = "河北省"; String city = "石家庄市"; String district = "桥西区"; //简码---->>HBSJZQX province = province.substring(0, province.length() - 1); //河北 city = city.substring(0, city.length() - 1); //石家庄 district = district.substring(0, district.length() - 1); //桥西 String info = province + city + district; String[] headByString = PinYin4jUtils.getHeadByString(info); String shorcode = StringUtils.join(headByString); System.out.println(shorcode); //城市编码---->>shijiazhuang String citycode = PinYin4jUtils.hanziToPinyin(city, ""); System.out.println(citycode); } }
3.3 修改RegionAction
@Controller @Scope("prototype") public class RegionAction extends ActionSupport implements ModelDriven<Region> { private Region region; @Autowired private IRegionService regionService; // 属性驱动,接收上传的文件 private File regionFile; public void setRegionFile(File regionFile) { this.regionFile = regionFile; } /** * 区域导入 * * @return */ public String importXls() throws IOException { List<Region> regionList = new ArrayList<>(); //使用POI解析Excel文件 HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(regionFile)); //根据名称获得指定Sheet对象 HSSFSheet hssfSheet = workbook.getSheet("Sheet1"); //遍历标签页中所有的行 for (Row row : hssfSheet) { int rowNum = row.getRowNum(); // 行号 // 如果是标题行,结束本次循环,直接进入下一次循环 if (rowNum == 0) { continue; } String id = row.getCell(0).getStringCellValue(); String province = row.getCell(1).getStringCellValue(); String city = row.getCell(2).getStringCellValue(); String district = row.getCell(3).getStringCellValue(); String postcode = row.getCell(4).getStringCellValue(); // 包装一个区域对象 Region region = new Region(id, province, city, district, postcode, null, null); province = province.substring(0, province.length() - 1); city = city.substring(0, city.length() - 1); district = district.substring(0, district.length() - 1); String info = province + city + district; String[] headByString = PinYin4jUtils.getHeadByString(info); String shortcode = StringUtils.join(headByString); //城市编码---->>shijiazhuang String citycode = PinYin4jUtils.hanziToPinyin(city, ""); region.setShortcode(shortcode); region.setCitycode(citycode); regionList.add(region); } // 批量保存 regionService.saveBatch(regionList); return NONE; } @Override public Region getModel() { return region; } }
查看数据库,这时候shortcode和citycode的数据也生成了
四、使用POI导出页面数据
4.1 页面调整
为页面中导出按钮绑定事件
// 导出按钮对应的处理函数 function doExport(){ // 发送请求,请求action,进行文件下载 window.location.href = "subareaAction_exportXls.action" }
4.2 服务端实现
第一步:查询所有的分区数据
第二步:使用POI将数据写到Excel文件中
第三步:使用输出流进行文件下载
/** * 分区数据导出功能 * @throws IOException */ public String exportXls() throws IOException{ //第一步:查询所有的分区数据 List<Subarea> list = subareaService.findAll(); //第二步:使用POI将数据写到Excel文件中 //在内存中创建一个Excel文件 HSSFWorkbook workbook = new HSSFWorkbook(); //创建一个标签页 HSSFSheet sheet = workbook.createSheet("分区数据"); //创建标题行 HSSFRow headRow = sheet.createRow(0); headRow.createCell(0).setCellValue("分区编号"); headRow.createCell(1).setCellValue("开始编号"); headRow.createCell(2).setCellValue("结束编号"); headRow.createCell(3).setCellValue("位置信息"); headRow.createCell(4).setCellValue("省市区"); for (Subarea subarea : list) { HSSFRow dataRow = sheet.createRow(sheet.getLastRowNum() + 1); dataRow.createCell(0).setCellValue(subarea.getId()); dataRow.createCell(1).setCellValue(subarea.getStartnum()); dataRow.createCell(2).setCellValue(subarea.getEndnum()); dataRow.createCell(3).setCellValue(subarea.getPosition()); dataRow.createCell(4).setCellValue(subarea.getRegion().getName()); } //第三步:使用输出流进行文件下载(一个流、两个头) String filename = "分区数据.xls"; String contentType = ServletActionContext.getServletContext().getMimeType(filename); ServletOutputStream out = ServletActionContext.getResponse().getOutputStream(); ServletActionContext.getResponse().setContentType(contentType); //获取客户端浏览器类型 String agent = ServletActionContext.getRequest().getHeader("User-Agent"); filename = FileUtils.encodeDownloadFilename(filename, agent); ServletActionContext.getResponse().setHeader("content-disposition", "attachment;filename="+filename); workbook.write(out); return NONE; }
参考:https://www.cnblogs.com/xiaobai1226/p/7507953.html