1.实现思路

           (1)  准备excel模板,减少用户非法输入,减少报错率。

(2)  导入excel,返回错误Map,key是行数,value是对应的报错。

(3)  把错误列表生成excel,并返回url地址

(4) 前端通过返回的url地址,下载报错的excel

难点: 因没有现成的集群文件存储环境,所以,机器返回下,返回url地址会有问题,会存在下载不到错误列表的问题。所以本博客,只是简单的返回成功和失败的条数,还有错误的map列表。

2.代码篇

2.1  后台代码

pom.xml

<!-- poi --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.8</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.8</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-scratchpad</artifactId><version>3.8</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId><version>3.8</version></dependency>
package com.cloudtech.web.excel;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(value = {ElementType.FIELD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelFiled {/*** 列头名称* @return*/String colName() default "";/*** 数据精度,精确到后几位数* 默认0位* @return*/int precision() default 0;/*** 日期格式* 默认 “yyyy-MM-dd HH:mm:ss”* @return*/String dateFormat() default "";/*** 字段对应的列索引* @return*/int colIndex() default 0;/*** 忽略该字段  为true表示为选填字段,为false为必填字段,必须判断是否为非空* @return*/boolean skip() default false;
}
package com.cloudtech.web.excel;import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;import org.apache.log4j.Logger;
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.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;import com.cloudtech.web.util.ReflectUtil;public class ExcelPOIUtils {final static String errormsg = "您好,第 [%s]行,第[%s]列%s,请重新输入!";private static Logger logger = Logger.getLogger(ExcelPOIUtils.class);private final static String xls = "xls";private final static String xlsx = "xlsx";static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");SimpleDateFormat createDateFormat(String pattern) {return new SimpleDateFormat(pattern);}public static Workbook getWorkBook(MultipartFile file) throws Exception {// 获得文件名String fileName = file.getOriginalFilename();// 创建Workbook工作薄对象,表示整个excelWorkbook workbook = null;try {// 获取excel文件的io流InputStream is = file.getInputStream();// 根据文件后缀名不同(xls和xlsx)获得不同的Workbook实现类对象if (fileName.endsWith(xls)) {// 2003workbook = new HSSFWorkbook(is);} else if (fileName.endsWith(xlsx)) {// 2007workbook = new XSSFWorkbook(is);}} catch (IOException e) {throw new Exception("解析报文出错!");}return workbook;}/*** * @param file   文件* @param class1    实体类* @param errorMap  错误map   key 行号   value  具体报错信息* @param errors    错误列表* @param colCount  列数* @return* @throws Exception*/public static <T> List<T> readExc(MultipartFile file, Class<T> class1,Map<Integer, String> errorMap,List<T> errors,int colCount) throws Exception {try {Workbook workbook = getWorkBook(file);return readExcel(class1, errorMap,errors, workbook,colCount);} catch (Exception e) {throw new Exception(e.getMessage());}}public static <T> List<T> readExc(InputStream in, Class<T> class1,Map<Integer, String> errorMap,List<T> errors,int colCount) throws Exception {try {Workbook workbook = WorkbookFactory.create(in);return readExcel(class1, errorMap,errors, workbook,colCount);} catch (Exception e) {e.printStackTrace();throw new Exception(e.getMessage());}}private static <T> List<T> readExcel(Class<T> class1, Map<Integer, String> errorMap,List<T> errors, Workbook workbook,int colCount)throws Exception {Sheet sheet = workbook.getSheetAt(0);int rowCount = sheet.getPhysicalNumberOfRows(); // 获取总行数if (rowCount == 1) { // 表格最小长度应为2return null;}int coloumNum  =sheet.getRow(0).getPhysicalNumberOfCells();if(coloumNum != colCount){throw new Exception("excel格式跟模板格式不一致!");}List<T> list = new ArrayList<T>(rowCount - 1);T obj;// 遍历每一行for (int r = 1; r < rowCount; r++) {Row row = sheet.getRow(r);obj = class1.newInstance();Field[] fields = class1.getDeclaredFields();Field field;boolean flag = true;     //标识,确定该条数据是否通过第一轮判断boolean errorFlag = false;  //标识是否有错误点StringBuffer error = new StringBuffer();for (int j = 0; j < fields.length; j++) {field = fields[j];ExcelFiled excelFiled = field.getAnnotation(ExcelFiled.class);if(excelFiled == null){continue;}Cell cell = row.getCell(excelFiled.colIndex());try {//序号为0,编号为空,则为无效行if(excelFiled.colIndex() == 0 ){if(cell == null || cell.toString().length() == 0){flag  = false;  break;}}if(!excelFiled.skip()){   //必填字段,需要判断是否非空if (cell == null || cell.toString().length() == 0) {//errogMsg(errorMap, r, j, excelFiled,"不能为空");error.append(excelFiled.colName()+"不能为空"+"|");flag = false;errorFlag = true;continue;}}if (field.getType().equals(Date.class)) {if (Cell.CELL_TYPE_STRING == cell.getCellType()) {ReflectUtil.setValue(obj, field.getName(), dateFormat.parse(cell.getStringCellValue()));} else {ReflectUtil.setValue(obj, field.getName(), new Date(cell.getDateCellValue().getTime()));}} else if (field.getType().equals(java.lang.Integer.class)) {if (Cell.CELL_TYPE_NUMERIC == cell.getCellType()) {ReflectUtil.setValue(obj, field.getName(), (int) cell.getNumericCellValue());} else if (Cell.CELL_TYPE_STRING == cell.getCellType()) {ReflectUtil.setValue(obj, field.getName(), Integer.parseInt(cell.getStringCellValue()));}} else if (field.getType().equals(java.math.BigDecimal.class)) {if (Cell.CELL_TYPE_NUMERIC == cell.getCellType()) {ReflectUtil.setValue(obj, field.getName(), new BigDecimal(cell.getNumericCellValue()));} else if (Cell.CELL_TYPE_STRING == cell.getCellType()) {ReflectUtil.setValue(obj, field.getName(), cell.getStringCellValue());}}else if (field.getType().equals(java.lang.Double.class)) {if (Cell.CELL_TYPE_NUMERIC == cell.getCellType()) {if(excelFiled.precision() == 0){   //没有小数点ReflectUtil.setValue(obj, field.getName(),Double.valueOf(new BigDecimal(cell.getNumericCellValue()).intValue()));}else{ReflectUtil.setValue(obj, field.getName(),new BigDecimal(cell.getNumericCellValue()).doubleValue());}} else if (Cell.CELL_TYPE_STRING == cell.getCellType()) {ReflectUtil.setValue(obj, field.getName(), new Double(cell.getStringCellValue()));}} else if (field.getType().equals(java.lang.String.class)) {if (Cell.CELL_TYPE_NUMERIC == cell.getCellType()) {if(excelFiled.precision() == 0){   //没有小数点ReflectUtil.setValue(obj, field.getName(),new BigDecimal(cell.getNumericCellValue()).intValue()+"");}else{ReflectUtil.setValue(obj, field.getName(),new BigDecimal(cell.getNumericCellValue()).doubleValue()+"");}} else if (Cell.CELL_TYPE_STRING == cell.getCellType()) {ReflectUtil.setValue(obj, field.getName(), cell.getStringCellValue());}}  else {if (Cell.CELL_TYPE_NUMERIC == cell.getCellType()) {ReflectUtil.setValue(obj, field.getName(), new BigDecimal(cell.getNumericCellValue()));} else if (Cell.CELL_TYPE_STRING == cell.getCellType()) {ReflectUtil.setValue(obj, field.getName(), cell.getStringCellValue());}}} catch (Exception e) {flag = false;errorFlag = true;error.append(excelFiled.colName()+"类型格式有误"+"|");}}//录入行号ReflectUtil.setValue(obj, "rowNum",(r+1));if(flag){list.add(obj);}if(errorFlag){errorMap.put(r, error.toString());errors.add(obj);}}return list;}}
package com.cloudtech.web.excel;import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;import com.cloudtech.web.vo.ImportStationInfoVo;public class Main {public static void main(String[] args) {try {InputStream in = new FileInputStream(new File("D://stationInfo.xlsx"));//错误列表HashMap<Integer, String> errorMap = new HashMap<>();List<ImportStationInfoVo> errors = new ArrayList<ImportStationInfoVo>();List<ImportStationInfoVo> readExc = ExcelPOIUtils.readExc(in, ImportStationInfoVo.class,errorMap,errors,24);//List<ExcelEntity> readExc = ExcelPOIUtils.readExc(in, ExcelEntity.class,errorMap,3);System.out.println("数据----------------");for (ImportStationInfoVo s : readExc) {System.out.println(s.toString());}System.out.println("错误maps----------------");errorMap.forEach((k,v)-> System.out.println(v));System.out.println("错误列表----------------");errors.forEach(k-> System.out.println(k.toString()));int success = readExc.size();int error = errorMap.size();System.out.println("总数"+(success+error)+",成功数:"+success+",失败数:"+errorMap.size());}  catch (Exception e) {e.printStackTrace();System.out.println(e.getMessage());}}
}
package com.cloudtech.web.vo;import com.cloudtech.web.excel.ExcelFiled;/*** excel导入模板* * @ClassName: ImportStationInfoVo* @Description:* @author wude* @date 2019年9月2日**/
public class ImportStationInfoVo {@ExcelFiled(colIndex=0,colName="有效行")private String id;@ExcelFiled(colIndex=1,colName="站点编号")private String number;@ExcelFiled(colIndex=2,colName="站点代码")private String serialNo;@ExcelFiled(colIndex=3,colName="站点名称")private String name;@ExcelFiled(colIndex=4,colName="维护公司")private String operatorName;@ExcelFiled(colIndex=5,colName="所在区域")private String areaName;@ExcelFiled(colIndex=6,colName="自动站类型")private String sTypeName;@ExcelFiled(colIndex=7,colName="海陆位置")private String isLand;@ExcelFiled(colIndex=8,colName="是否为秒级站")private String isSecond;@ExcelFiled(colIndex=9,colName="品牌类型",skip=true)private String brandTypeName;@ExcelFiled(colIndex=10,colName="联系人",skip=true)private String linkman;@ExcelFiled(colIndex=11,colName="联系座机",skip=true)private String linkPhone;@ExcelFiled(colIndex=12,colName="联系手机号",skip=true)private String linkMobilePhone;@ExcelFiled(colIndex=13,colName="具体地址",skip=true)private String address;@ExcelFiled(colIndex=14,colName="经度")private Double longitde;@ExcelFiled(colIndex=15,colName="纬度")private Double latitude;@ExcelFiled(colIndex=16,colName="海拔高度")private Double altitude;@ExcelFiled(colIndex=17,colName="安装位置",skip=true)private String installSite;@ExcelFiled(colIndex=18,colName="观测要素",skip=true)private String observeElement;@ExcelFiled(colIndex=19,colName="离地高度")private Double terrainClearance;@ExcelFiled(colIndex=20,colName="气压高度",skip=true)private Double pressureHeight;@ExcelFiled(colIndex=21,colName="供电来源",skip=true)private String powerSupplyType;@ExcelFiled(colIndex=22,colName="电池容量",skip=true)private String batteryCapacity;@ExcelFiled(colIndex=23,colName="占地面积",skip=true)private String roomSize;/** 行数 */private Integer rowNum;public String getNumber() {return number;}public void setNumber(String number) {this.number = number;}public String getSerialNo() {return serialNo;}public void setSerialNo(String serialNo) {this.serialNo = serialNo;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getOperatorName() {return operatorName;}public void setOperatorName(String operatorName) {this.operatorName = operatorName;}public String getAreaName() {return areaName;}public void setAreaName(String areaName) {this.areaName = areaName;}public String getsTypeName() {return sTypeName;}public void setsTypeName(String sTypeName) {this.sTypeName = sTypeName;}public String getIsLand() {return isLand;}public void setIsLand(String isLand) {this.isLand = isLand;}public String getIsSecond() {return isSecond;}public void setIsSecond(String isSecond) {this.isSecond = isSecond;}public String getBrandTypeName() {return brandTypeName;}public void setBrandTypeName(String brandTypeName) {this.brandTypeName = brandTypeName;}public String getLinkman() {return linkman;}public void setLinkman(String linkman) {this.linkman = linkman;}public String getLinkPhone() {return linkPhone;}public void setLinkPhone(String linkPhone) {this.linkPhone = linkPhone;}public String getLinkMobilePhone() {return linkMobilePhone;}public void setLinkMobilePhone(String linkMobilePhone) {this.linkMobilePhone = linkMobilePhone;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Double getLongitde() {return longitde;}public void setLongitde(Double longitde) {this.longitde = longitde;}public Double getLatitude() {return latitude;}public void setLatitude(Double latitude) {this.latitude = latitude;}public Double getAltitude() {return altitude;}public void setAltitude(Double altitude) {this.altitude = altitude;}public String getInstallSite() {return installSite;}public void setInstallSite(String installSite) {this.installSite = installSite;}public String getObserveElement() {return observeElement;}public void setObserveElement(String observeElement) {this.observeElement = observeElement;}public Double getTerrainClearance() {return terrainClearance;}public void setTerrainClearance(Double terrainClearance) {this.terrainClearance = terrainClearance;}public Double getPressureHeight() {return pressureHeight;}public void setPressureHeight(Double pressureHeight) {this.pressureHeight = pressureHeight;}public String getPowerSupplyType() {return powerSupplyType;}public void setPowerSupplyType(String powerSupplyType) {this.powerSupplyType = powerSupplyType;}public String getBatteryCapacity() {return batteryCapacity;}public void setBatteryCapacity(String batteryCapacity) {this.batteryCapacity = batteryCapacity;}public String getRoomSize() {return roomSize;}public void setRoomSize(String roomSize) {this.roomSize = roomSize;}public Integer getRowNum() {return rowNum;}public void setRowNum(Integer rowNum) {this.rowNum = rowNum;}@Overridepublic String toString() {return "ImportStationInfoVo [id=" + id + ", number=" + number + ", serialNo=" + serialNo + ", name=" + name+ ", operatorName=" + operatorName + ", areaName=" + areaName + ", sTypeName=" + sTypeName + ", isLand="+ isLand + ", isSecond=" + isSecond + ", brandTypeName=" + brandTypeName + ", linkman=" + linkman+ ", linkPhone=" + linkPhone + ", linkMobilePhone=" + linkMobilePhone + ", address=" + address+ ", longitde=" + longitde + ", latitude=" + latitude + ", altitude=" + altitude + ", installSite="+ installSite + ", observeElement=" + observeElement + ", terrainClearance=" + terrainClearance+ ", pressureHeight=" + pressureHeight + ", powerSupplyType=" + powerSupplyType + ", batteryCapacity="+ batteryCapacity + ", roomSize=" + roomSize + ", rowNum=" + rowNum + "]";}
}

反射类


package com.cloudtech.web.util;import java.lang.reflect.Field;import com.cloudtech.web.entity.RuleCode;public class ReflectUtil {/*** 使用反射设置变量值** @param target 被调用对象* @param fieldName 被调用对象的字段,一般是成员变量或静态变量,不可是常量!* @param value 值* @param <T> value类型,泛型*/public static <T> void setValue(Object target,String fieldName,T value) {try {Class c = target.getClass();Field f = c.getDeclaredField(fieldName);f.setAccessible(true);f.set(target, value);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}/*** 使用反射获取变量值** @param target 被调用对象* @param fieldName 被调用对象的字段,一般是成员变量或静态变量,不可以是常量* @param <T> 返回类型,泛型* @return 值*/public static <T> T getValue(Object target,String fieldName) {T value = null;try {Class c = target.getClass();Field f = c.getDeclaredField(fieldName);f.setAccessible(true);value = (T) f.get(target);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return value;}public static void main(String[] args) {RuleCode code = new RuleCode();code.setId(1234);//Object value = ReflectUtil.getValue(code, "id");System.out.println(code.getId());/*   String s ="avgSpd gt hThreeMaxSpd";String replace = s.replace("gt", "");String[] split = replace.split(" ");System.out.println();*/}
}

通过反射的方式获取值,在poi导出辅助类是调用反射类的方法,这样,导入导出的辅助类的就支持所有的实体类。

controller类

 // 导入@RequestMapping(value = "importData")@ResponseBodypublic BaseDataResult importData(@RequestParam MultipartFile file) {try {//错误mapsMap<Integer, String> errorMap = new HashMap<>();//错误列表List<ImportStationInfoVo> errors = new ArrayList<ImportStationInfoVo>();//站点数据列表List<ImportStationInfoVo> stations = ExcelPOIUtils.readExc(file, ImportStationInfoVo.class,errorMap,errors,24);HashMap<String, Object> maps = new HashMap<>();maps.put("succ", stations);maps.put("fail", errorMap);return new BaseDataResult(Constans.SUCCESS, "导入成功",maps);} catch (Exception e) {return new BaseDataResult(Constans.FAILED, e.getMessage()); }}

2.2前端代码layui

 <button id="importData" class="layui-btn">导入</button>
<button class="layui-btn" onclick="downloadTemplate();">模板下载</button>

导入layui相关依赖css和js

<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/assets/css/layui.css"/>
<script src="${pageContext.request.contextPath}/assets/js/jquery-3.2.0.min.js"></script>
<script src="${pageContext.request.contextPath}/assets/js/layui.js"></script>

在script初始化如下代码,记得#importData是关键,跟导入按钮的id一样

layui.use([ "element", "laypage", "layer", "upload"], function() {var element = layui.element;var laypage = layui.laypage;var layer = layui.layer;var upload = layui.upload;//主要是这个layui.upload.render({elem: "#importData",//导入idurl: "../station/importData",size: '3072',accept: "file",exts: 'xls|xlsx',done: function (result) {if (result.code == 1) {      //成功$("#stationErro").html("");var fail = result.data.fail;var succ = result.data.succ;var failCount=0;var failHtml="";  //失败的列表for(var key in fail){failHtml+="<tr>"+"<td colspan='3'>第"+(parseInt(key)+1)+"行,"+fail[key]+"</td>"+"</tr>";failCount++;}var content="<tr>"+"<td>"+(failCount+succ.length)+"</td>"+"<td>"+succ.length+"</td>"+"<td>"+failCount+"</td>"+" </tr>";if(failCount != 0){content+="<tr>"+"<td colspan='3' style='color: red;'>导入失败原因如下:</td>"+"</tr>";content+=failHtml;}else{content+="<tr>"+"<td colspan='3' style='color: green;'>您好,暂无错误信息!</td>"+"</tr>";}$(content).appendTo("#stationErro");failTemplate();}else{     //失败return layer.msg(result.error);}}});
});

效果图

3注意

下图是excel的模板,因保密问题,所以,只给一个效果图

业务逻辑:

1.判断有效行是否有值,没有值则认为该数据无效

2、通过自定义的注解里面的skip,判断该字段是否不能为空,为false则认为一定要有值,不然会打印错误信息

3.ImportStationInfoVo只是用来测试的一个实体类,行号和有效行这两个字段必须得有。实体类的类型也不是随便写的,根据实际的需求具体定义,假设站点编号在实体类中是int,表格录入的时候,输入字符串,工具会返回错误提示

4.controller讲解   errorMap是错误列表  key是行号,value是具体的报错拼接起来的

errors是错误的list

stations是第一重简单的非空和类型判断

5.  需要对stations列表进行各种判断,并返回成功的list和错误的集合map

如果你热衷技术,喜欢交流,欢迎加入我们!

poi导入excel数据思路相关推荐

  1. Java 使用poi导入excel,结合xml文件进行数据验证的例子(增加了jar包)

    ava 使用poi导入excel,结合xml文件进行数据验证的例子(增加了jar包) 假设现在要做一个通用的导入方法: 要求: 1.xml的只定义数据库表中的column字段,字段类型,是否非空等条件 ...

  2. 如何优雅的用POI导入Excel文件

    在企业级项目开发中,要经常涉及excel文件和程序之间导入导出的业务要求,那么今天来讲一讲excel文件导入的实现.java实现对excel的操作有很多种方式,例如EasyExcel等,今天我们使用的 ...

  3. poi导出excel写入公式_【java poi 写入Excel后读取公式值问题】poi导入excel

    java poi 写入Excel后读取公式值问题 不用改公式,只需要用cell.getNumericCellValue()获取,读出来就是正确的值了,如果你读出来的还有问题,说明你其他的地方写的还有问 ...

  4. poi导入excel日期处理_POI处理Excel中各种日期格式问题

    前不久写过一篇随笔<EXCEL解析之终极方法WorkbookFactory>,提到使用WorkbookFactory来处理Excel文件数据,最近发现一个问题就是这个办法不能很好的处理各种 ...

  5. HSSFWorkbook下载xls表格模板及导入excel数据

    效果图:(有列置灰.隐藏.下拉列表功能) 下载excel模板代码: private AjaxResult myBatchImportTemplateSelect(List<ProjectTask ...

  6. 【Python处理EXCEL】基础操作篇:在Python中导入EXCEL数据

    一.前期准备 此篇使用两种导入excel数据的方式,形式上有差别,但两者的根本方法实际上是一样的. 首先需要安装两个模块,一个是pandas,另一个是xlrd. 在顶部菜单栏中点击文件,再点击设置,然 ...

  7. web端实现表单提交poi导入excel文件

    <!--虎牌导入会员数据--> <a class="btn btn-primary btn-sm search-btn btn-wide btn-scroll btn-sc ...

  8. springboot使用POI读取excel数据

    MAVEN坐标如下: 便于复制: <!-- excel导出工具 --> <dependency><groupId>org.apache.poi</groupI ...

  9. java 利用POI 读取Excel数据的真实有效行数

    前言 最近发现java导入excel数据时,我的excel数据明明只有4条数据,可是java程序却读取到了第6行.检查代码发现5.6行不小心设置了行高,导致poi的getLastRowNum()方法读 ...

最新文章

  1. ModuleNotFoundError: No module named ‘pandas._libs.tslibs.base‘
  2. nfs参数介绍与写法示例及报错( Operation not permitted)
  3. [综述类] 一文道尽深度学习中的数据增强方法(上)
  4. CodeForces 658C Bear and Forgotten Tree 3(构造)
  5. Visual studio 打包
  6. 21个ui设计技巧,让你的设计不落伍
  7. 《实用技巧》——让你的网站变成响应式的3个简单步骤
  8. C#开发笔记之20-如何用C#深克隆一个对象(优雅方案)?
  9. java课程设计学生信息管理_JAVA课程设计---学生基本信息管理系统
  10. 50. 熟悉与STL相关的Web站点
  11. python弹球游戏移动球拍_python pygame实现挡板弹球游戏的代码
  12. 为什么谈设计总爱提老庄之道
  13. 【C++】图像加载(libpng、FreeImage、stb_image)
  14. 老照片免费修复软件有哪些?一键智能修复老照片工具推荐给你
  15. YouTube直播SDK集成(一)
  16. 系统上电后 bootloader的执行流程
  17. LeetCode第714题解析
  18. 如何使用 Selenium 在 HTML 文本输入中模拟按 Enter 键?
  19. 为何敢称万物追焦?小米12 系列CyberFocus技术详解
  20. Static与Const的区别

热门文章

  1. mysql版scott数据库_MySQL中建立Oracle中SCOTT数据示例
  2. Elasticsearch7.5.0安全(xpack)之身份认证
  3. EVC实现WIN CE下截屏
  4. 其他总结(七)--解决谷歌浏览器不显示翻译此页按钮(网页自动翻译)
  5. 2.商场促销 - 策略模式 (大话设计模式Kotlin版)
  6. 优信二手车以创新迎接机遇与挑战
  7. 机遇与挑战并存,优信二手车强势发力
  8. 2020寒假集训排位赛 Cow Gymnastics 题解(思维)
  9. 宜家2.0:家具巨头对智能家居的大赌注
  10. ask fsk psk 数字调制的三种基本形式