一、 项目中存在这样一个需求:
1)获取当前请求页面URL中的一个参数值taskId
2)将Excel中数据读取和taskId一起存放到数据库(taskId和Excel中数据存在关联关系,但是taskId不在Excel中)
二、应用技术:
后台框架:Springmvc
持久层框架:mybatis
数据库:mysql
前端:jsp、Ajax
项目管理工具:maven,特别需要的pom配置用于操作Excel:
<!-- apache poi start --> <!-- POI --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.8</version> <exclusions> <exclusion> <artifactId>commons-codec</artifactId> <groupId>commons-codec</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.8</version> </dependency> <!-- apache poi end -->
工程目录结构:
三、实现过程:
1、前端:
1)文件上传页面
<form enctype="multipart/form-data" style="display:inline;white-space: nowrap;" id="batchUpload" action="case/upload" method="post" class="form-horizontal"> <button class="btn btn-success btn-xs" id="uploadEventBtn" style="height:26px;" type="button" >选择文件</button> <input type="file" name="file" style="width:0px;height:0px;" id="uploadEventFile"> <input id="uploadEventPath" disabled="disabled" type="text" > </form>
2)上传js
<script type="text/javascript"> var Point = function(){ this.init = function(){ //模拟上传excel $("#uploadEventBtn").unbind("click").bind("click",function(){ $("#uploadEventFile").click(); }); $("#uploadEventFile").bind("change",function(){ $("#uploadEventPath").attr("value",$("#uploadEventFile").val()); }); }; //点击上传按钮 this.uploadBtn = function(){ var uploadEventFile = $("#uploadEventFile").val(); if(uploadEventFile == ''){ alert("请选择excel,再上传"); }else if(uploadEventFile.lastIndexOf(".xls")<0){//可判断以.xls和.xlsx结尾的excel alert("只能上传Excel文件"); }else{ var url = '/case/upload/'; var id = getUrlParam('taskId');//获取URL中taskId var formData = new FormData($('form')[0]);//获取form表单请求文件 formData.append("id",id);//添加请求参数,用户传给后台 console.log("id------------------------"+id); point.sendAjaxRequest(url,'POST',formData); } }; this.sendAjaxRequest = function(url,type,data){ $.ajax({ url : url, type : type, data : data, success : function(result) { alert( result); }, error : function() { alert( "excel上传失败"); }, cache : false, contentType : false, processData : false }); }; } var point; $(function(){ point = new Point(); point.init(); }); /*获取URL参数*/ function getUrlParam(name){ //构造一个含有目标参数的正则表达式对象 var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)"); //匹配目标参数 var r = window.location.search.substr(1).match(reg); //返回参数值 if (r!=null) return unescape(r[2]); return null; }
</script>
2、Excel工具类
1)数据库连接:
package ***;
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException;
/** * @author zhaowei * @date 2019年5月21日 下午3:37:08 * */ public class DBconnection { private static Connection con = null; private static String driverName = "com.mysql.jdbc.Driver"; private static String Name="automation_wr"; private static String Passwd="3faf8db433cc0235"; private static String url = "jdbc:mysql://test1254.db.58dns.org:4420/db58_automation"; public static Connection getConnection() { try { /*注册jdbc驱动*/ Class.forName(driverName); /*获取数据库连接*/ con=DriverManager.getConnection(url,Name,Passwd); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return con; } public static void closeConnection() { if (con!=null) { try { con.close(); } catch (Exception e) { e.printStackTrace(); } } }
} 2)读取Excel数据:
package ***;
import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.web.multipart.MultipartFile;
import com.bj58.automation.entity.CaseEntity;
/** * @author zhaowei * @date 2019年5月22日 下午1:09:33 * */ public class ReadExcel { // 总行数 private int totalRows = 0; // 总条数 private int totalCells = 0; // 错误信息接收器 private String errorMsg; //private List<PointEntity> pointEntities; // 构造方法 public ReadExcel() { } // 获取总行数 public int getTotalRows() { return totalRows; } // 获取总列数 public int getTotalCells() { return totalCells; } // 获取错误信息 public String getErrorInfo() { return errorMsg; } /** * 读EXCEL文件,获取信息集合 * * @param fielName * @return */ public List<CaseEntity> getExcelInfo(MultipartFile mFile) { String fileName = mFile.getOriginalFilename();// 获取文件名 List<CaseEntity> caseEntities = null; try { if (!validateExcel(fileName)) {// 验证文件名是否合格 return null; } boolean isExcel2003 = true;// 根据文件名判断文件是2003版本还是2007版本 if (isExcel2007(fileName)) { isExcel2003 = false; } caseEntities = createExcel(mFile.getInputStream(), isExcel2003); } catch (Exception e) { e.printStackTrace(); } return caseEntities; } /** * 根据excel里面的内容读取用例信息 * * @param is输入流 * @param isExcel2003 excel是2003还是2007版本 * @return * @throws IOException */ public List<CaseEntity> createExcel(InputStream is, boolean isExcel2003) { List<CaseEntity> caseEntities=null; try { Workbook wb = null; if (isExcel2003) {// 当excel是2003时,创建excel2003 wb = new HSSFWorkbook(is); } else {// 当excel是2007时,创建excel2007 wb = new XSSFWorkbook(is); } caseEntities = readExcelValue(wb);// 读取Excel里面客户的信息 } catch (IOException e) { e.printStackTrace(); } return caseEntities; } /** * 读取Excel里面用例的信息 * * @param wb * @return */ private List<CaseEntity> readExcelValue(Workbook wb) { // 得到第一个shell Sheet sheet = wb.getSheetAt(0); // 得到Excel的行数 this.totalRows = sheet.getPhysicalNumberOfRows(); // 得到Excel的列数(前提是有行数) if (totalRows > 1 && sheet.getRow(0) != null) { this.totalCells = sheet.getRow(0).getPhysicalNumberOfCells(); } List<CaseEntity> caseEntities = new ArrayList<CaseEntity>(); // 循环Excel行数 for (int r = 1; r < totalRows; r++) { Row row = sheet.getRow(r); if (row == null) { continue; } CaseEntity caseEntity = new CaseEntity(); // 循环Excel的列 for (int c = 0; c < this.totalCells; c++) { Cell cell = row.getCell(c); if (null != cell) { if (c == 0) { // 如果是纯数字,比如你写的是25,cell.getNumericCellValue()获得是25.0,通过截取字符串去掉.0获得25 if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String pointName = String.valueOf(cell.getNumericCellValue()); caseEntity.setPointName(pointName.substring(0, pointName.length() - 2 > 0 ? pointName.length() - 2 : 1));//埋点名称 } else { caseEntity.setPointName(cell.getStringCellValue());// 埋点名称 } } else if (c == 1) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String platform = String.valueOf(cell.getNumericCellValue()); caseEntity.setPlatform(platform.substring(0, platform.length() - 2 > 0 ? platform.length() - 2 : 1));// 所属平台 } else { caseEntity.setPlatform(cell.getStringCellValue());// 所属平台 } } else if (c == 2) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String platformVersion = String.valueOf(cell.getNumericCellValue()); caseEntity.setPlatformVersion(platformVersion.substring(0, platformVersion.length() - 2 > 0 ? platformVersion.length() - 2 : 1));// 支持的平台版本 } else { caseEntity.setPlatformVersion(cell.getStringCellValue());// 支持的平台版本 } } else if (c == 3) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String pointType = String.valueOf(cell.getNumericCellValue()); caseEntity.setPointType(pointType.substring(0, pointType.length() - 2 > 0 ? pointType.length() - 2 : 1));// 埋点类型 0:默认, 1:展现 2:点击 } else { caseEntity.setPointType(cell.getStringCellValue());// 埋点类型 0:默认, 1:展现 2:点击 } } else if (c == 4) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String pageType = String.valueOf(cell.getNumericCellValue()); caseEntity.setPageType(pageType.substring(0, pageType.length() - 2 > 0 ? pageType.length() - 2 : 1));// 支持的平台版本 } else { caseEntity.setPageType(cell.getStringCellValue());// 支持的平台版本 } } else if (c == 5) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String actionType = String.valueOf(cell.getNumericCellValue()); caseEntity.setActionType(actionType.substring(0, actionType.length() - 2 > 0 ? actionType.length() - 2 : 1));// 事件标识 } else { caseEntity.setActionType(cell.getStringCellValue());// 事件标识 } } else if (c == 6) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String cate = String.valueOf(cell.getNumericCellValue()); caseEntity.setCate(cate.substring(0, cate.length() - 2 > 0 ? cate.length() - 2 : 1));// 所属业务 } else { caseEntity.setCate(cell.getStringCellValue());// 所属业务 } } else if (c == 7) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String params = String.valueOf(cell.getNumericCellValue()); caseEntity.setParams(params.substring(0, params.length() - 2 > 0 ? params.length() - 2 : 1));// 参数 } else { caseEntity.setParams(cell.getStringCellValue());// 参数 } } else if (c == 8) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String sidDict = String.valueOf(cell.getNumericCellValue()); caseEntity.setSidDict(sidDict.substring(0, sidDict.length() - 2 > 0 ? sidDict.length() - 2 : 1));// 补充参数 } else { caseEntity.setSidDict(cell.getStringCellValue());// 补充参数 } } else if (c == 9) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String owner = String.valueOf(cell.getNumericCellValue()); caseEntity.setOwner(owner.substring(0, owner.length() - 2 > 0 ? owner.length() - 2 : 1));// 埋点所属人 } else { caseEntity.setOwner(cell.getStringCellValue());// 埋点所属人 } } else if (c == 10) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String iworkUrl = String.valueOf(cell.getNumericCellValue()); caseEntity.setIworkUrl(iworkUrl.substring(0, iworkUrl.length() - 2 > 0 ? iworkUrl.length() - 2 : 1));// iwork地址 } else { caseEntity.setIworkUrl(cell.getStringCellValue());// iwork地址 } } else if (c == 11) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String iOSPath = String.valueOf(cell.getNumericCellValue()); caseEntity.setiOSPath(iOSPath.substring(0, iOSPath.length() - 2 > 0 ? iOSPath.length() - 2 : 1));// iOS UI路径 } else { caseEntity.setiOSPath(cell.getStringCellValue());// iOS UI路径 } } else if (c == 12) { if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { String AndPath = String.valueOf(cell.getNumericCellValue()); caseEntity.setAndPath(AndPath.substring(0, AndPath.length() - 2 > 0 ? AndPath.length() - 2 : 1));// 安卓 UI路径 } else { caseEntity.setAndPath(cell.getStringCellValue());// 安卓 UI路径 } } } } // 添加到list caseEntities.add(caseEntity); } return caseEntities; } /** * 验证EXCEL文件 * @param filePath * @return */ public boolean validateExcel(String filePath) { if (filePath == null || !(isExcel2003(filePath) || isExcel2007(filePath))) { errorMsg = "文件名不是excel格式"; return false; } return true; } // @描述:是否是2003的excel,返回true是2003 public static boolean isExcel2003(String filePath) { return filePath.matches("^.+\\.(?i)(xls)$"); } // @描述:是否是2007的excel,返回true是2007 public static boolean isExcel2007(String filePath) { return filePath.matches("^.+\\.(?i)(xlsx)$"); } }
3、后台实现:
1)定义实体(和数据库表字段对应,也是Excel中导入数据的来源依据)
package ***;
import java.util.Date;
/** * @author zhaowei * @date 2019年5月22日 下午5:50:43 * */ public class CaseEntity { public String id;//主键 public int parentId;//父级Id public String pointName;//埋点名称 public String platform;//所属平台 0:APP, 1:M 2:PC public String platformVersion;//支持的平台版本 public String pointType;//埋点类型 0:默认, 1:展现 2:点击 public String pageType;//页面标识 public String actionType;//事件标识 public String cate;//所属业务 public String params;//参数 public String sidDict;//补充参数 public String owner;//埋点所属人 public String iworkUrl;//iwork地址 public String iOSPath;//iOS UI路径 public String AndPath;//安卓 UI路径 public String state;//埋点状态 0:正常 1:停用 public Date createTime;//创建时间 public String updateTime;//更新时间 public String getId() { return id; } public void setId(String id) { this.id = id; } public int getParentId() { return parentId; } public void setParentId(int parentId) { this.parentId = parentId; } public String getPointName() { return pointName; } public void setPointName(String pointName) { this.pointName = pointName; } public String getPlatform() { return platform; } public void setPlatform(String platform) { this.platform = platform; } public String getPlatformVersion() { return platformVersion; } public void setPlatformVersion(String platformVersion) { this.platformVersion = platformVersion; } public String getPointType() { return pointType; } public void setPointType(String pointType) { this.pointType = pointType; } public String getPageType() { return pageType; } public void setPageType(String pageType) { this.pageType = pageType; } public String getActionType() { return actionType; } public void setActionType(String actionType) { this.actionType = actionType; } public String getCate() { return cate; } public void setCate(String cate) { this.cate = cate; } public String getParams() { return params; } public void setParams(String params) { this.params = params; } public String getSidDict() { return sidDict; } public void setSidDict(String sidDict) { this.sidDict = sidDict; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public String getIworkUrl() { return iworkUrl; } public void setIworkUrl(String iworkUrl) { this.iworkUrl = iworkUrl; } public String getiOSPath() { return iOSPath; } public void setiOSPath(String iOSPath) { this.iOSPath = iOSPath; } public String getAndPath() { return AndPath; } public void setAndPath(String andPath) { AndPath = andPath; } public String getState() { return state; } public void setState(String state) { this.state = state; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date date) { this.createTime = date; } public String getUpdateTime() { return updateTime; } public void setUpdateTime(String updateTime) { this.updateTime = updateTime; }
} 2)定义两个接口,一个是读取excel中的数据,生成list,另外一个是Excel导入埋点用例,分别如下:
读取Excel:
package ***;
import org.springframework.web.multipart.MultipartFile;
/** * @author zhaowei * @date 2019年5月22日 下午8:31:11 * */ public interface ExcelService { /** * 读取excel中的数据,生成list */ String readExcelFile( MultipartFile file,int parentId);
}导入埋点用例:
package ***;
import com.bj58.automation.entity.CaseEntity;
/** * @author zhaowei * @date 2019年5月22日 下午1:06:07 * */ public interface PointService { public void excelCase(CaseEntity caseEntity);//Excel导入埋点用例
} 3)实现以上两个接口,分别为:
读取Excel:
package ***;
import java.util.Date; import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile;
import com.bj58.automation.entity.CaseEntity; import com.bj58.automation.service.ExcelService; import com.bj58.automation.service.PointService; import com.bj58.automation.util.ReadExcel;
/** * @author zhaowei * @date 2019年5月22日 下午8:35:15 * */ @Service("excelServices") public class ExcelImp implements ExcelService{ @Autowired PointService pointService;//业务接口 @Override public String readExcelFile(MultipartFile file,int parentId) { String result =""; //创建处理EXCEL的类 ReadExcel readExcel=new ReadExcel(); //解析excel,获取上传的事件单 List<CaseEntity> caseEntities = readExcel.getExcelInfo(file); //System.out.println(JSON.toJSON(caseEntities)); //至此已经将excel中的数据转换到list里面了,接下来就可以操作list,可以进行保存到数据库,或者其他操作, //和你具体业务有关,这里不做具体的示范 for (CaseEntity caseEntity : caseEntities) { caseEntity.setCreateTime(new Date()); caseEntity.setParentId(parentId); pointService.excelCase(caseEntity); } if(caseEntities != null && !caseEntities.isEmpty()){ result = "上传成功"; }else{ result = "上传失败"; } return result; }
}
导入埋点用例:
package ***;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
import com.bj58.automation.dao.CaseDao; import com.bj58.automation.entity.CaseEntity; import com.bj58.automation.service.PointService;
/** * @author zhaowei * @date 2019年5月22日 下午1:08:01 * */ @Service("pointServices") public class PointImp implements PointService{ @Autowired CaseDao caseDao;//数据访问接口 //Excel导入埋点用例 @Override public void excelCase(CaseEntity caseEntity) { caseDao.excelCase(caseEntity); } }
4)定义DAO:
package ***;
import com.bj58.automation.entity.CaseEntity;
/** * @author zhaowei * @date 2019年5月14日 上午9:53:43 * */ public interface CaseDao { public void excelCase(CaseEntity caseEntity);//Excel导入埋点用例
}
5)定义持久层mapper
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.bj58.automation.dao.CaseDao"> <!-- WARNING - @mbggenerated This element is automatically generated by MyBatis Generator, do not modify. --> insert into t_point(parentId,pointName,platform,platformVersion,pointType,pageType,actionType,cate,params,sidDict, owner,iworkUrl,iOSPath,AndPath,state,createTime,updateTime) values(#{parentId,jdbcType=INTEGER},#{pointName,jdbcType=VARCHAR},#{platform,jdbcType=VARCHAR}, #{platformVersion,jdbcType=VARCHAR},#{pointType,jdbcType=VARCHAR},#{pageType,jdbcType=VARCHAR}, #{actionType,jdbcType=VARCHAR},#{cate,jdbcType=VARCHAR},#{params,jdbcType=VARCHAR}, #{sidDict,jdbcType=VARCHAR},#{owner,jdbcType=VARCHAR},#{iworkUrl,jdbcType=VARCHAR}, #{iOSPath,jdbcType=VARCHAR},#{AndPath,jdbcType=VARCHAR},0,#{createTime,jdbcType=VARCHAR}, #{updateTime,jdbcType=VARCHAR}) </insert> </mapper>
6)控制层实现:
//上传Excel @ResponseBody @RequestMapping(value="/upload",method = RequestMethod.POST,produces="text/html;charset=UTF-8") public String upload(@RequestParam(value = "file", required = false) MultipartFile file,@RequestParam(value="id",required = false)Integer id, HttpServletRequest request, HttpServletResponse response){ String result=null; result = excelService.readExcelFile(file,id); return result; } 基于不同的业务需求,具体要求也不一致。如果不携带额外参数只是Excel上传过程会比较简单,在以上前端和后台接口及实现去掉id即可,效果图如下:
