功能需求
①用户在市场活动主页面,点击"导入"按钮,弹出导入市场活动的模态窗口;
②用户在导入市场活动的模态窗口选择要上传的文件,点击"导入"按钮,完成导入市场活动的功能.
*只支持.xls
*文件大小不超过5MB
③导入成功之后,提示成功导入记录条数,关闭模态窗口,刷新市场活动列表,显示第一页数据,保持每页显示条数不变
④*导入失败,提示信息,模态窗口不关闭,列表也不刷新
功能分析
①把计算机的excel文件上传到服务器
②使用java解析excel文件,获取excel文件的数据
③解析出来的数据添加到数据库中
④返回响应信息
技术准备
①文件上传表单的三个条件
- 表单组件标签使用<input type="file">
- 请求方式是post:参数通过请求体提交后台,能提交文本数据和二进制数据,长度没限制。安全,效率低。
- HTTP协议规定,浏览器向后台提交参数的时候,都会对参数进行统一编码。默认采用urlencoded,对文本数据进行编码成字符串。表单编码只能是multipart/form-data
<form action="url" method="post" enctype="multipart/form-data">
<input type="file" name="myFile"><br>
<input type="text" name="username"><br>
<input type="submit" name="提交"><br>
</form>
②使用java解析excel文件
在mvc配置文件,MultipartFile activityFile。配置文件上传解析器 id:必须是multipartResolver
<!-- 配置文件上传解析器 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>
poi插件
流程图
代码实现
一、ActivityMapper
1.在ActivityMapper的接口中,添加批量插入的按钮
/**
*批量插入
*/
int insertActivityByList(List<Activity> activityList);
2.配置映射文件的sql语句
- 插入的字段是id, owner, name, start_date, end_date, cost, description, create_time, create_by
- 通过<foreach>标签进行遍历
- 返回值是添加的条数
<insert id="insertActivityByList">
insert into tbl_activity (id, owner, name, start_date,
end_date, cost, description,
create_time, create_by)
values
<foreach collection="list" item="obj" separator=",">
(#{obj.id},#{obj.owner},#{obj.name},#{obj.startDate},#{obj.endDate},#{obj.cost},#{obj.description},#{obj.createTime},#{obj.createBy})
</foreach>
</insert>
二、ActivityService
@Override
public int saveCreateActivityByList(List<Activity> activityList) {
return activityMapper.insertActivityByList(activityList);
}
三、ActivityController
1.通过session获取user,并且创建返回的Object
// 1 通过session获取user
User user = (User) session.getAttribute(Contants.SESSION_USER);
// 2 创建返回的Object
ReturnObject returnObject = new ReturnObject();
2.读取文件准备工作
// 3.1 获取文件输入流
InputStream is = activityFile.getInputStream();
// 3.1 创建文件
HSSFWorkbook wb = new HSSFWorkbook(is);
// 3.2 获取excel表第一页的信息
HSSFSheet sheet = wb.getSheetAt(0);
// 3.3 创建行、列、接收的对象、接收的集合
HSSFRow row = null;
HSSFCell cell = null;
Activity activity = null;
List<Activity> activityList = new ArrayList<>();
3.通过循环读取文件内容--先获取行数--然后根据这个行,读取列
- 获取行数是sheet.getLastRowNum(),获取这个行的内容sheet.getRow(i)
- 通过Session的user,给发起者,创建者赋值user.id
- 通过UUISUtils.getUUID()给活动的id赋值
- 通过DateUtils.formateDateTime(new Date())创建时间
- 通过表格设置的列,给activity实体类赋值。
- 循环完一行后,activityList.add(activity)
/**
* 批量导入
*/
@RequestMapping("/workbench/activity/importActivities.do")
public @ResponseBody
Object importActivities(MultipartFile activityFile, HttpSession session) {
// 1 通过session获取user
User user = (User) session.getAttribute(Contants.SESSION_USER);
// 2 创建返回的Object
ReturnObject returnObject = new ReturnObject();
// 3 读取文件
try {
// 3.1 获取文件输入流
InputStream is = activityFile.getInputStream();
// 3.1 创建文件
HSSFWorkbook wb = new HSSFWorkbook(is);
// 3.2 获取excel表第一页的信息
HSSFSheet sheet = wb.getSheetAt(0);
// 3.3 创建行、列、接收的对象、接收的集合
HSSFRow row = null;
HSSFCell cell = null;
Activity activity = null;
List<Activity> activityList = new ArrayList<>();
// 3.4 通过循环读取文件内容
// 3.4.1 行数
for (int i = 1; i < sheet.getLastRowNum(); i++) {
// 3.4.2 读取此行
row = sheet.getRow(i);
// 3.4.3 创建activity对象
activity = new Activity();
activity.setId(UUIDUtils.getUUID());
activity.setOwner(user.getId());
activity.setCreateTime(DateUtils.formateDateTime(new Date()));
activity.setCreateBy(user.getId());
// 3.4.3 读取此行的所有列
for (int j = 0; j < row.getLastCellNum(); j++) {
// 3.4.4 读取此行的列的值
cell = row.getCell(j);
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 {
activity.setDescription(cellValue);
}
}
activityList.add(activity);
}
// 4 调用service
int ret = activityService.saveCreateActivityByList(activityList);
if (ret > 0) {
// 插入成功
returnObject.setCode(Contants.RETURN_OBJECT_CODE_SUCCESS);
returnObject.setRetDate(ret);
} else {
// 插入失败
returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
returnObject.setMessage("系统繁忙,稍后再试");
}
} catch (IOException e) {
e.printStackTrace();
// 插入失败
returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
returnObject.setMessage("系统繁忙,稍后再试");
}
return returnObject;
}
四、index.jsp
<input type="file" id="activityFile">
①、在js中,获取上传的文件名 var activityFileName = $("#activityFile").val();
②、获取上传的文件--$("#activityFile").get(0)获取DOM对象,然后可以上传多个文件,选取第一个文件files[0]---- var activityFile = $("#activityFile").get(0).files[0];
③、FormData上传文件,通过模拟K-V对向后台提交参数。FormData最大的优势是不但能提交文本数据,还能提交二进制数据
var formData = new FormData();
formData.append("activityFile", activityFile);
完整的js代码
$("#importOpenActivityBtn").click(function () {
// 6.1 点击导入弹出导入框
$("#importActivityModal").modal("show");
// 6.2 点击导入按钮
$("#importActivityBtn").click(function () {
// 收集参数
var activityFileName = $("#activityFile").val();
// 截取文件类型
var suffix = activityFileName.substr(activityFileName.lastIndexOf(".") + 1).toLocaleLowerCase();
if (suffix != "xls") {
alert("只支持xls文件");
return;
}
// 获取文件--$("#activityFile").get(0)获取DOM对象,然后可以上传多个文件,选取第一个文件files[0]
var activityFile = $("#activityFile").get(0).files[0];
if (activityFile.size > 5 * 1024 * 1024) {
alert("文件不能大于5MB");
return;
}
// FormData是ajax提供的接口,可以模拟K-V对向后台提交参数;
// FormData最大的优势是不但能提交文本数据,还能提交二进制数据
var formData = new FormData();
formData.append("activityFile", activityFile);
// 发送请求
$.ajax({
url: 'workbench/activity/importActivities.do',
data:formData,
processData:false,// 不转换为字符串
contentType:false,// 不编码
type: 'post',
dataType: 'json',
success: function (data) {
if (data.code == "1") {
// 成功导入
$("#importActivityModal").modal("hide");
queryActivityByConditionForPage(1, $("#pagDiv").bs_pagination('getOption', 'rowsPerPage'));
alert("成功导入" + data.retDate + "条数据");
} else {
alert(data.message);
$("#importActivityModal").modal("show");
}
}
});
});
});