从前台导入/导出数据库数据实现(HSSF)
一、导出
用户在浏览器主页面,通过选中从数据库中取出的记录,点击"导出",把所有符合条件的数据生成一个excel文件,输出到浏览器;激活文件下载的对话框,用户选择要保存目录,完成导出数据的功能。
- 使用java生成excel文件:这里处理办公文档的插件使用的是
apache-poi
1. 依赖
<!--poi-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
2. 关键点
- 把
excel
文件中所有的元素都封装成java
类,程序员通过java
类以及类的对象,达到操作excel
文件的目的.
关键类:HSSFWorkbook
:excel文件HSSFSheet
:表HSSFRow
:行HSSFCell
:单元格
- 所有文件下载的请求只能发同步请求
3. POI的使用
- 创建一个excel文件
HSSFWorkbook workbook = new HSSFWorkbook();
- 通过文件,创建一页,可以在创建时给页起名字
HSSFSheet sheet = workbook.createSheet(); HSSFSheet sheet = workbook.createSheet("页的名字");
- 通过页,创建一行
- 行的创建要通过下标来指定是哪一行
- 下标是通过从0开始的计数
- 如下案例所示
createRow(0)
,表示创建的是第一行
HSSFRow row = sheet.createRow(0);
- 通过行,来创建行中的单元格
- 单元格也是要通过下标来指定是哪一格
- 下标是通过从0开始的计数
- 如下案例所示
createCell(0)
,表示是在当前行中创建的第一个单元格
HSSFCell cell = row.createCell(0);
- 设置单元格的值
cell.setCellValue("id");
- 将文件保存在本地
OutputStream out = new FileOutputStream(new File("D:\\study\\student.xls")); workbook.write(out);
4. 导出功能的实现
(1) 前端导出按钮绑定点击事件
$("#exportActivityAllBtn").click(function () {
if(confirm("确定要导出所有数据吗?")){
//必须是传统请求
window.location.href = "workbench/activity/exportActivityAll.do";
}
})
(2) 后台生成excel文件并传到前台
要点:
- 生成excel文件,并填充数据
- 为客户浏览器提供下载框,并设置默认的文件名(可以有空格,冒号自动转为下划线)
response.setContentType("octets/stream"); response.setHeader("Content-Disposition","attachment;filename=Activity-"+dateStr+".xls");
- 获取响应流,将数据发送到前台
out = response.getOutputStream(); workbook.write(out);
- Tomcat会自动关闭响应流
@RequestMapping("/exportActivityAll.do")
public void exportActivityAll(HttpServletResponse response){
//通过业务层查询所有的记录,Activity是个实体类
List<Activity> aList = activityService.getActivityList();
//创建一个excel文件
HSSFWorkbook workbook = new HSSFWorkbook();
//通过文件,创建一页
HSSFSheet sheet = workbook.createSheet();
//通过页,创建一行
HSSFRow row = sheet.createRow(0);
//创建第一行下的第1个单元格,第一行为表头
HSSFCell cell = row.createCell(0);
cell.setCellValue("id");
//创建第一行下的第2个单元格
cell = row.createCell(1);
cell.setCellValue("owner");
//遍历sList取值填充excel
for(int i=0;i<aList.size();i++){
//取出每一个市场活动,将数据填充到每一个单元格
Activity a = aList.get(i);
row = sheet.createRow(i+1);
//创建第一行下的第1个单元格
cell = row.createCell(0);
cell.setCellValue(a.getId());
//创建第一行下的第2个单元格
cell = row.createCell(1);
cell.setCellValue(a.getOwner());
}
//获取当前时间的字符串,格式如下,可以有空格
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
String dateStr = sdf.format(date);
//为客户浏览器提供下载框,并设置默认的文件名,冒号自动转为下划线,
response.setContentType("octets/stream");
response.setHeader("Content-Disposition","attachment;filename=Activity-"+dateStr+".xls");
/*
通过response得到的响应流,如果我们自己没有关闭掉
tomcat服务器会自动帮我们关闭掉
*/
OutputStream out = null;
try {
//获取响应流
out = response.getOutputStream();
workbook.write(out);
workbook.close();
} catch (Exception e) {
e.printStackTrace();
}
}
二、导入
用户在主页面,点击"导入"按钮,弹出导入数据的模态窗口(BootStrap实现);用户在导入数据的模态窗口,选择要导入的文件,点击"导入"按钮,完成导入市场活动的功能.
- 处理文件上传的插件:这里使用的是
springMVC
:file.transferTo(new File(fileName)));
- 处理办公文档的插件:同样是
apache-poi
,将excel解析成为java对象
1. 依赖
<!--poi-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
2. 操作要求
(1)仅支持.xls
或.xlsx
格式的文件
(2)文件大小不超过5MB
3. 配置SpringMVC
因为使用的是SpringMVC
框架,所以要在SpringMVC
的配置文件中加入以下配置:(注意id
必须是multipartResolver
)
<!-- 配置文件上传解析器 id:必须是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置上传文件的大小-->
<property name="maxUploadSize" value="#{1024*1024*5}"/>
<!--设置上传文件的编码-->
<property name="defaultEncoding" value="utf-8"/>
</bean>
4. 实际目录和虚拟目录
- 实际目录:以盘符开始(相当于操作系统的绝对路径)
- 虚拟目录:以
/
开始,/
代表应用部署后的根目录(相当于java项目的绝对路径)
5. 导入功能实现
(1) 前端实现
要点:
- 获取用户上传的文件的绝对地址(
value
),从绝对地址中截取出后缀名(.
后的字符串)(substr
),从而判断是否为excel文件 - 通过
files
属性取得文件,判断文件大小(与在配置中判断文件大小选一个即可) FormData
类型的作用是可以提交文本数据,还可以提交二进制数据,通过FormData
模拟键值对向服务器提交数据- 文件上传必须用
post
请求 - 发送ajax请求,
processData
和contentType
参数均为false
//为导入按钮绑定事件,执行导入操作(通过excel文件生成表中的记录)
$("#importActivityBtn").click(function () {
//获取用户上传的文件的绝对地址
var activityFileName = $("#activityFile").val();
//从绝对地址中截取出后缀名(.后的字符串)
var suffix = activityFileName.substr(activityFileName.lastIndexOf(".")+1);
//判断是否为excel文件
if(suffix!="xls" && suffix!="xlsx"){
alert("不是有效的excel文件");
return false;
}
//取得文件
/*
jquery没有为我们提供取得文件的方法,所以我们还是必须要使用到原生js的dom来取
使用files属性
*/
var activityFile = $("#activityFile")[0].files[0];
//判断文件大小(这种方法和在SpringMVC配置中设置的方法选其一即可)
if(activityFile.size>1024*1024*5){
alert("文件大小不超过5MB!");
return false;
}
//FormData是ajax定义的接口,可以模拟键值对向服务器提交数据
//FormData类型的作用是可以提交文本数据,还可以提交二进制数据.
var formData=new FormData();
formData.append("myFile",$("#activityFile")[0].files[0]);
/*
contentType:false
默认情况下,ajax向服务器发送数据之前,
把所有数据统一按照applciation/x-www-form-urlencoded编码格式进行编码;
把contentType设置为false,能够阻止这种行为.
processData:false
主要是配合contentType使用的,
默认情况下,ajax把所有数据进行applciation/x-www-form-urlencoded编码之前,
会把所有数据统一转化为字符串;把proccessData设置为false,可以阻止这种行为.
*/
//做文件上传,请求方式必须是post请求
$.ajax({
url : "workbench/activity/importActivity.do",
data : formData,
type : "post",
dataType : "json",
processData : false,
contentType : false,
success : function (data) {
if(data.success){
//上传成功
alert("文件上传成功");
}else{
alert("文件上传失败");
}
}
})
})
(2) 后台实现
要点:
- 通过
MultipartFile
类,来接收前台传过来的数据 - 给文件生成一个名字,不能有特殊字符,这里使用了时间(与导出中的时间不同)
- 在做文件上传相关操作的时候,一定要使用的是虚拟路径
- 创建一个存放临时文件的文件夹
tmpDic
,将上传的文件先放到这儿。为了防止idea不随着项目发布该文件夹,要在文件夹中建一个jsp
文件(任意一个需要编译的文件) - 通过全局域对象的
realPath
方法来取得虚拟路径下的真实路径request.getServletContext().getRealPath("/tmpDic");
- 将上传回来的二进制解析成excel文件,并将excel保存在临时文件夹中
file.transferTo(new File(path+"/"+fileName));
- 获取文件的输入流,通过输入流,获取
execl
文件InputStream input = new FileInputStream(path+"/"+fileName); //通过输入流,获取execl文件 HSSFWorkbook workbook = new HSSFWorkbook(input);
- 将excel文件中的数据循环遍历,提取出来保存到实体类的集合中,再传入
dao
层保存到数据库中 - *注意:
sheet.getLastRowNum()
返回的最后一行的行数是从0
开始算的,即只有一列的话返回0;row.getLastCellNum()
返回的最后一个单元格列数是从1
开始算的,即只有一个单元格的话返回1 - 关闭文件
具体代码:
@RequestMapping("/importActivity.do")
@ResponseBody
public Map<String,Object> importActivity(@RequestParam("myFile")MultipartFile file, HttpServletRequest request) throws AjaxRequestException {
//取得文件的名称(与导出不同,文件中不能有空格和冒号等)
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = new Date();
String fileName = sdf.format(date);
//取得文件上传的路径
/*
真实路径:盘符下的路径 例如 C: D:
虚拟路径:找的是当前项目下的路径
由于文件上传的位置,通过盘符写死的形式,有可能出错(盘符有可能是不存在的)
所以我们在做文件上传相关操作的时候,一定要使用的是虚拟路径
我们在webapp的路径下,新建了一个tmpDic的文件夹
但是如果这个文件夹里面所保存的都是不需要进行编译的文件,
那么这个文件夹在idea默认的处理下,是不会跟着项目一起发布到服务器中的
所以我们现在需要想办法,将tmpDic文件夹变成能够进行发布的文件夹
我们可以在tmpDic下创建一个jsp文件,从此这个文件夹就成为了必须要编译jsp的文件夹
*/
//我们通过全局域对象realPath方法来取得虚拟路径下的真实路径
String path = request.getServletContext().getRealPath("/tmpDic");
try {
//将上传回来的二进制解析成excel文件,并将excel保存在临时文件夹中
file.transferTo(new File(path+"/"+fileName));
//获取文件的输入流
InputStream input = new FileInputStream(path+"/"+fileName);
//通过输入流,获取execl文件
HSSFWorkbook workbook = new HSSFWorkbook(input);
//取得下标为0(第一页)中的信息
HSSFSheet sheet = workbook.getSheetAt(0);
List<Activity> aList = new ArrayList<>();
HSSFRow row = null;
//遍历行,这里getLastRowNum()方法需要加1
for(int i=1;i<sheet.getLastRowNum()+1;i++){
//获取行
row = sheet.getRow(i);
HSSFCell cell = null;
//遍历单元格,这里getLastCellNum()方法不需要加1
for(int j=0;j<row.getLastCellNum();j++){
//获取单元格
cell = row.getCell(j);
if(j==0){
a.setOwner(cell.getStringCellValue());
}else if(j==1){
a.setName(cell.getStringCellValue());
}
}
aList.add(a);
}
//调用业务层,业务层调用dao层,保存数据
activityService.saveActivityList(aList);
//关闭文件
workbook.close();
} catch (Exception e) {
e.printStackTrace();
throw new AjaxRequestException();
}
Map<String , Object> map = new HashMap<>();
map.put("success", true);
return map
}