ssm框架中导入excel文件

一、先在pom.xml中引入commons-fileupload依赖

    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>

二、JSP页面

给导出按钮设置id=”importActivityBtn”,添加单击事件,发送异步请求

        //文件上传三个条件:<input type="file"> 。要post请求,因为post能提交文件,而get不行。表单编码格式multipart/form-data
		$("#importActivityBtn").click(function () {
		    // $("#activityFile").val();只能获取文件名
            var activityFileName = $("#activityFile").val();
            //截取activityFileName中最后一个.索引再加一 后面的字符串
            var suffix=activityFileName.substr(activityFileName.lastIndexOf(".")+1).toLocaleLowerCase();//转为小写 xls,Xls,XLS,xLs...都是excel文件
            if(suffix!="xls"){
                alert("导入活动仅支持xls文件");
                return;
			}
			//获取文件 .get(0)获得dom对象,dom对象里才有files
			var activityFile = $("#activityFile").get(0).files[0];//可以得到文件数组,但是浏览器只能选择一个,files[0]拿数组的第一个
			//判断文件大小
			if(activityFile.size>5*1024*1024){//activityFile.size()单位是字节
				alert("文件大小不能超过5MB");
				return;
			}
			//FormData是ajax提供的接口,可以模拟键值对(: =)向后台提供参数,不仅能提交文本数据,还能提交二进制数据(文件);
			var formData = new FormData();
            formData.append("activityFile",activityFile);//前面名字要和Controller中参数名字一致
            //上传文件需要加这两个属性processData:false;contentType:false;
            $.ajax({
				url:'importActivity.do',
				data:formData,
				type:"post",
				processData:false,//设置ajax向后台提交参数之前,是否把参数转换为字符串:true---是,false--不是,默认是true
				contentType:false,//设置ajax向后台提交参数之前,是否把所有的参数统一按urlencoded编码(只能对字符串进行编码) true---是,false---不是
				dataType:"json",
				success:function (data) {
				    if(data.code=="1"){
				        alert("成功导入"+data.retData+"条活动");
				        $("#importActivityModal").modal("hide");//关闭文件上传的窗口
                        queryActivityByConditionForPage(1,$("#demo_page1").bs_pagination('getOption','rowsPerPage'));
                    }else {
				        alert(data.message);
				        $("#importActivityModal").modal("show");//本来就是开着的,不关闭文件上传的窗口
					}

                }

			});

        });

三、在springmvc配置文件中配置文件上传解析器

<!-- 配置文件上传解析器 id:必须是multipartResolver&ndash-->
    <!--CommonsMultipartResolver的对象从post请求体中拿数据,文件  id名不能改-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="#{1024*1024*5}"/><!--文件大小,其实在前台就验证大小了,不用这个-->
        <property name="defaultEncoding" value="utf-8"/>
    </bean>

 四、Controller层,读取文件每一行每一列的值,封装成实体类对象,插入数据库

// 配置springmvc的文件上传解析器,CommonsMultipartResolver的对象从post请求体中拿数据,文件。把文件给 MultiparFile activityFile
    @ResponseBody
    @RequestMapping("/importActivity.do")
    public Object importActivity(MultipartFile activityFile,HttpSession session){
        User user = (User) session.getAttribute(Contants.SESSION_USER);//用户登录时就用户信息放到session中,现在拿出来
        ReturnObject returnObject = new ReturnObject();//返回的对象
        try {
            String originalFilename = activityFile.getOriginalFilename();//获取原来的名字,也就是用户上传时文件的名字
            InputStream inputStream = activityFile.getInputStream();
            //根据excel文件生成HSSFWorkbook对象,封装了excel文件的所有信息
            HSSFWorkbook wb = new HSSFWorkbook(inputStream);
            //根据wb获取HSSFSheet对象,封装了一页的所有信息
            HSSFSheet sheet = wb.getSheetAt(0);//只有一页
            //根据sheet获取HSSFRow对象,封装了一行的所有信息
            HSSFRow row = null;
            HSSFCell cell = null;
            Activity activity=null;
            List<Activity> activityList = new ArrayList<>();

            //从excel文件中遍历每一行
            for(int i=1;i<=sheet.getLastRowNum();i++){//getLastRowNum()最后一行的下标,所以<=
                row=sheet.getRow(i);
                activity=new Activity();
                activity.setId(UUIDUtils.getUUID());//自定义的工具方法,生成32位随机id
                activity.setOwner(user.getId());
                activity.setCreateTime(DateUtils.formateDateTime(new Date()));//自定义工具方法,把当前事件转为yyyy-MM-dd
                activity.setCreateBy(user.getId());
                //在一行中遍历每一列
                for(int j=0;j<row.getLastCellNum();j++){//getLastCellNum()最后一列的下标+1,所以<
                    //根据row获取HSSFCell对象,封装了一列的所有信息
                    cell=row.getCell(j);
                    String cellValue=HSSFUtils.getCellValueForStr(cell);//自定义工具类,判断获取的列的值是什么类型,再赋值给cellValue
                    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放到activityList中
                activityList.add(activity);
            }
            //把activityList插入数据库
            int ret = activityService.saveCreateActivityByList(activityList);
            returnObject.setCode(Contants.RETURN_OBJECT_CODE_SUCCESS);
            returnObject.setRetData(ret);
        } catch (IOException e) {
            e.printStackTrace();
            returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
            returnObject.setMessage("系统繁忙,请稍后重试...");
        }
        return returnObject;
    }

记得配置扫描Contrller

五、获取Cell值的工具类

因为获取每一列的值需要先判断值是什么类型才能获取,所以生成工具类方便调用

import org.apache.poi.hssf.usermodel.HSSFCell;

public class HSSFUtils {
    /**
     * 从指定的HSSFCell对象获取列的值
     * @return
     */
    public static String getCellValueForStr(HSSFCell cell){
//        因为cell.get__CellValue获取列的值方法必须指定数据类型,所以要判断一下列的数据类型是什么再获取
//        用cell.getCellType()可以得到列的数据类型,是什么数据类型就用什么cell.get__CellValue获取

        String ret="";
        if(cell.getCellType()==HSSFCell.CELL_TYPE_STRING){//字符串类型
            ret=cell.getStringCellValue();
        }else if(cell.getCellType()==HSSFCell.CELL_TYPE_NUMERIC){//数值类型 默认Double
            ret=Double.toString(cell.getNumericCellValue());
            //ret是字符型的,不是继承关系不能强转。它不是一个封装类,不是一个对象,所以不能用toString().。。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 if(cell.getCellType()==HSSFCell.CELL_TYPE_BLANK){//空类型
            ret="null";
        }else if(cell.getCellType()==HSSFCell.CELL_TYPE_ERROR){//错误类型
            ret="error";
        }
        return ret;
    }
}

六、Service和实现类

public interface ActivityService {

    //批量插入市场活动
    int saveCreateActivityByList(List<Activity> activityList);

}
@Service("activityService")
public class ActivityServiceImpl implements ActivityService{
    @Autowired
    ActivityMapper activityMapper;

    @Override
    public int saveCreateActivityByList(List<Activity> activityList) {
        return activityMapper.insertActivityByList(activityList);
    }

}

记得配置扫描Service

七、Dao和mapper

public interface ActivityMapper {
   
    //批量插入市场活动
    int insertActivityByList(List<Activity> activityList);

}
<insert id="insertActivityByList" parameterType="com.ycj.domain.Activity">
        insert into tbl_activity(id, owner, name, start_date, end_date, cost, description, create_time, create_by)
        value 
        <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>

记得配置mapper注解扫描器

八、总结

难点一在于Controller层中两个for循环读取每一行每一列的值,而读Cell,也就是列的值需要先判断是什么类型的值,cell.get__CellValue()有6种类型;二是发送异步请求使用FormData接口把文件放请求体中上传。

    原文作者:给你一朵小红花H
    原文地址: https://blog.csdn.net/m0_59359926/article/details/123492612
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞