Excel文件上传
1,导入市场活动:
1)把用户计算机上的excel文件上传到服务器(文件上传)
2)使用java解析excel文件,获取excel文件中的数据
3)把解析出来的数据添加数据库中
4)返回响应信息
技术准备:
1)文件上传:
fileuploadtest.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
%>
<html>
<head>
<base href="<%=basePath%>">
<title>演示文件上传</title>
</head>
<body>
<!--
文件上传的表单三个条件:
1.表单组件标签必须用:<input type="file">
<input type="text|password|radio|checkbox|hidden|button|submit|reset|file">
<select>,<textarea>等
2.请求方式只能用:post
get:参数通过请求头提交到后台,参数放在URL后边;只能向后台提交文本数据;对参数长度有限制;数据不安全;效率高,有缓存
post:参数通过请求体提交到后台;既能能提交文件数据,又能够提交二进制数据;理论上对参数长度没有限制;相对安全;效率相对较低
3.表单的编码格式只能用:multipart/form-data
根据HTTP协议的规定,浏览器每次向后台提交参数,都会对参数进行统一编码;默认采用的编码格式是urlencoded,这种编码格式只能对文本数据进行编码;
浏览器每次向后台提交参数,都会首先把所有的参数转换成字符串,然后对这些数据统一进行urlencoded编码;
文件上传的表单编码格式只能用multipart/form-data:
格式是:enctype="multipart/form-data"
-->
<form action="workbench/activity/fileUpload.do" method="post" enctype="multipart/form-data">
<input type="file" name="myFile"><br>
<input type="text" name="userName"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
ActivityController
|->fileUpload()
配置springmvc的文件上传解析器
<!-- 配置文件上传解析器 id:必须是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="#{1024*1024*80}"/>
<property name="defaultEncoding" value="utf-8"/>
</bean>
配置所必须的文件上传解析器之后才能够继续写代码.
/**MultipartFile 这个是springmvc 专门用来封装文件的类.
* 配置springmvc的文件上传解析器
*
*/
@RequestMapping("/workbench/activity/fileUpload.do")
public @ResponseBody Object fileUpload(String userName, MultipartFile myFile) throws Exception{
//把文本数据打印到控制台
System.out.println("userName="+userName);
//把文件在服务指定的目录中生成一个同样的文件
String originalFilename=myFile.getOriginalFilename();
//Original 中文翻译为原始的,起初的,原先的.
//File file=new File("D:\\course\\18-CRM\\阶段资料\\serverDir\\"+originalFilename); 这个File有两个构造方法可以用
File file=new File("D:\\course\\18-CRM\\阶段资料\\serverDir\\",originalFilename);//路径必须手动创建好,文件如果不存在,会自动创建
myFile.transferTo(file);
//返回响应信息
ReturnObject returnObject=new ReturnObject();
returnObject.setCode(Contants.RETURN_OBJECT_CODE_SUCCESS);
returnObject.setMessage("上传成功");
return returnObject;
}
2)使用java解析excel文件:iText,apache-poi
关于办公文档插件使用的基本思想:把办公文档的所有元素封装成普通的Java类,程序员通过操作这些类达到操作办公文档目的。
文件---------HSSFWorkbook
页-----------HSSFSheet
行-----------HSSFRow
列-----------HSSFCell
/**
* 使用apache-poi解析excel文件
*/
public class ParseExcelTest {
public static void main(String[] args) throws Exception{
//根据excel文件生成HSSFWorkbook对象,封装了excel文件的所有信息
InputStream is=new FileInputStream("D:\\course\\18-CRM\\阶段资料\\serverDir\\aaa.xls");
HSSFWorkbook wb=new HSSFWorkbook(is);
//根据wb获取HSSFSheet对象,封装了一页的所有信息
HSSFSheet sheet=wb.getSheetAt(0);//页的下标,下标从0开始,依次增加
//根据sheet获取HSSFRow对象,封装了一行的所有信息
HSSFRow row=null;
HSSFCell cell=null;
for(int i=0;i<=sheet.getLastRowNum();i++) {//sheet.getLastRowNum():最后一行的下标
row=sheet.getRow(i);//行的下标,下标从0开始,依次增加
for(int j=0;j<row.getLastCellNum();j++) {//row.getLastCellNum():最后一列的下标+1
//根据row获取HSSFCell对象,封装了一列的所有信息
cell=row.getCell(j);//列的下标,下标从0开始,依次增加
//获取列中的数据
System.out.print(HSSFUtils.getCellValueForStr(cell)+" ");
}
//每一行中所有列都打完,打印一个换行
System.out.println();
}
}
}
把上面图片中的代码封装成工具类中的方法,因为是重复的代码
/**
* 关于excel文件操作的工具类
*/
public class HSSFUtils {
/**
* 从指定的HSSFCell对象中获取列的值
* @return
*/
public static String getCellValueForStr(HSSFCell cell){
String ret="";
if(cell.getCellType()==HSSFCell.CELL_TYPE_STRING){
ret=cell.getStringCellValue();
}else if(cell.getCellType()==HSSFCell.CELL_TYPE_NUMERIC){
ret=cell.getNumericCellValue()+"";
}else if(cell.getCellType()==HSSFCell.CELL_TYPE_BOOLEAN){
ret=cell.getBooleanCellValue()+"";
}else if(cell.getCellType()==HSSFCell.CELL_TYPE_FORMULA){
ret=cell.getCellFormula();
}else{
ret="";
}
return ret;
}
}
上面写的是不插入到数据库的,下面的代码是仿照实际工作中导入文件肯定是要插入到数据库的.
我只把部分重点的代码写一下
Controller层
@RequestMapping("/workbench/activity/importActivity.do")
public @ResponseBody Object importActivity(MultipartFile activityFile,String userName,HttpSession session){
System.out.println("userName="+userName);
User user=(User) session.getAttribute(Contants.SESSION_USER);
ReturnObject returnObject=new ReturnObject();
try {
//把excel文件写到磁盘目录中
/*String originalFilename = activityFile.getOriginalFilename();
File file = new File("D:\\course\\18-CRM\\阶段资料\\serverDir\\", originalFilename);//路径必须手动创建好,文件如果不存在,会自动创建
activityFile.transferTo(file);*/
//解析excel文件,获取文件中的数据,并且封装成activityList
//根据excel文件生成HSSFWorkbook对象,封装了excel文件的所有信息
//InputStream is=new FileInputStream("D:\\course\\18-CRM\\阶段资料\\serverDir\\"+originalFilename);
InputStream is=activityFile.getInputStream();
HSSFWorkbook wb=new HSSFWorkbook(is);
//根据wb获取HSSFSheet对象,封装了一页的所有信息
HSSFSheet sheet=wb.getSheetAt(0);//页的下标,下标从0开始,依次增加
//根据sheet获取HSSFRow对象,封装了一行的所有信息
HSSFRow row=null;
HSSFCell cell=null;
Activity activity=null;
List<Activity> activityList=new ArrayList<>();
for(int i=1;i<=sheet.getLastRowNum();i++) {//sheet.getLastRowNum():最后一行的下标
row=sheet.getRow(i);//行的下标,下标从0开始,依次增加
activity=new Activity();
activity.setId(UUIDUtils.getUUID());
activity.setOwner(user.getId());
activity.setCreateTime(DateUtils.formateDateTime(new Date()));
activity.setCreateBy(user.getId());
for(int j=0;j<row.getLastCellNum();j++) {//row.getLastCellNum():最后一列的下标+1
//根据row获取HSSFCell对象,封装了一列的所有信息
cell=row.getCell(j);//列的下标,下标从0开始,依次增加
//获取列中的数据
String cellValue=HSSFUtils.getCellValueForStr(cell);
if(j==0){
activity.setName(cellValue);
}else if(j==1){
activity.setStartDate(cellValue);
}else if(j==2){
activity.setEndDate(cellValue);
}else if(j==3){
activity.setCost(cellValue);
}else if(j==4){
activity.setDescription(cellValue);
}
}
//每一行中所有列都封装完成之后,把activity保存到list中
activityList.add(activity);
}
//调用service层方法,保存市场活动
int ret=activityService.saveCreateActivityByList(activityList);
returnObject.setCode(Contants.RETURN_OBJECT_CODE_SUCCESS);
returnObject.setRetData(ret);
}catch (Exception e){
e.printStackTrace();
returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
returnObject.setMessage("系统忙,请稍后重试....");
}
return returnObject;
}
还有前端页面,因为上传文件,所以跟普通参数不一样
//导入按钮点击后页面会弹出一个窗口
<!-- 导入市场活动的模态窗口 -->
<div class="modal fade" id="importActivityModal" role="dialog">
<div class="modal-dialog" role="document" style="width: 85%;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">导入市场活动</h4>
</div>
<div class="modal-body" style="height: 350px;">
<div style="position: relative;top: 20px; left: 50px;">
请选择要上传的文件:<small style="color: gray;">[仅支持.xls]</small>
</div>
<div style="position: relative;top: 40px; left: 50px;">
<input type="file" id="activityFile">
</div>
<div style="position: relative; width: 400px; height: 320px; left: 45% ; top: -40px;" >
<h3>重要提示</h3>
<ul>
<li>操作仅针对Excel,仅支持后缀名为XLS的文件。</li>
<li>给定文件的第一行将视为字段名。</li>
<li>请确认您的文件大小不超过5MB。</li>
<li>日期值以文本形式保存,必须符合yyyy-MM-dd格式。</li>
<li>日期时间以文本形式保存,必须符合yyyy-MM-dd HH:mm:ss的格式。</li>
<li>默认情况下,字符编码是UTF-8 (统一码),请确保您导入的文件使用的是正确的字符编码方式。</li>
<li>建议您在导入真实数据之前用测试文件测试文件导入功能。</li>
</ul>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button id="importActivityBtn" type="button" class="btn btn-primary">导入</button>
</div>
</div>
</div>
</div>
//给"导入"按钮添加单击事件
$("#importActivityBtn").click(function () {
//收集参数
var activityFileName=$("#activityFile").val();
//截取后缀文件类型是不是xls,需要进行校验
var suffix=activityFileName.substr(activityFileName.lastIndexOf(".")+1).toLocaleLowerCase();//xls,XLS,Xls,xLs,....
if(suffix!="xls"){
alert("只支持xls文件");
return;
}
//获取文件,这个方法获取的就是整个文件,
var activityFile=$("#activityFile")[0].files[0];
//判断一下文件的大小是不是符合需求标准5M
if(activityFile.size>5*1024*1024){
alert("文件大小不超过5MB");
return;
}
//FormData是ajax提供的接口,可以模拟键值对向后台提交参数;
//FormData最大的优势是不但能提交文本数据,还能提交二进制数据
var formData=new FormData();
formData.append("activityFile",activityFile);
formData.append("userName","张三");
//发送请求
$.ajax({
url:'workbench/activity/importActivity.do',
data:formData,
processData:false,//设置ajax向后台提交参数之前,是否把参数统一转换成字符串:true--是,false--不是,默认是true
contentType:false,//设置ajax向后台提交参数之前,是否把所有的参数统一按urlencoded编码:true--是,false--不是,默认是true
type:'post',
dataType:'json',
success:function (data) {
if(data.code=="1"){
//提示成功导入记录条数
alert("成功导入"+data.retData+"条记录");
//关闭模态窗口
$("#importActivityModal").modal("hide");
//刷新市场活动列表,显示第一页数据,保持每页显示条数不变
queryActivityByConditionForPage(1,$("#demo_pag1").bs_pagination('getOption', 'rowsPerPage'));
}else{
//提示信息
alert(data.message);
//模态窗口不关闭
$("#importActivityModal").modal("show");
}
}
});
});