辛苦写的,转载请注明来源^_^

一、为什么要写这个Excel工具类

上个项目有个功能点需要导出信息到Excel文件,于是到网上找了工具类xdemo,首先感谢原作者的奉献,使用很简单。但在使用的过程中也发现了几个问题(可能是我用的版本太老导致的):

1.类的属性为空时,没有相应处理,Excel中的单元格会前移一个单元格。
2.不支持Java8的LocalDateTime的日期转换。
3.Excel反序列化List时,不支持自定义日期格式。
4.由于写的时间较早,其中很多POI的API都是标记过时的。
5.代码中大量使用for循环,if判断,对于代码洁癖的我,有点不习惯(对原作者没有任何恶意^_^,不要误解)

二、和老版的Excel工具类对比

功能点 新版ExcelUtils 旧版ExcelUtils
自定义表头样式 支持 不支持
自定义内容样式 支持 不支持
自定义序列化属性转换 支持 支持
自定义反序列属性转换 支持 支持
支持LocalDateTime 支持 不支持
自定义表格合并 不支持(写出来太费劲^_^) 支持

三、使用的依赖

Gradle

//FastJson
compile ("com.alibaba:fastjson:1.2.35")
//POI
compile ("org.apache.poi:poi:3.16")
compile ("org.apache.poi:poi-ooxml:3.16")

Maven

//FastJson
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.35</version>
</dependency>
//POI
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.16</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.16</version>
</dependency>

四、使用的技术

1.使用FastJson作为Json转换工具(号称最快的Json解析工具)
2.大量使用Java8的Stream进行链式操作(好像也写了一些for循环……)
3.利用Java8的lambda表达式简化语法
4.利用Java8的Optional排除空指针异常

工具中采用的思想是约定大于配置。必需按照约定好的步骤进行调用。

五、List转Excel的实现思想

1.顺序获取类中所有属性的Excel注解,拿到Excel注解的name属性,设置为表头。
2.逐个顺序获取对象中带有Excel注解的属性值,然后做对应的转换(false->假,true->真等),之后写入到cell中,cell的类型均为String类型。
3.写出文件,搞定了

六、Excel转List的实现思想

可不可以把每行转换成一个对象的Json格式,再用Json工具转换成对象呢?这样效率可能会慢一点,但事实证明并没有慢多少,而且很方便》》》》

1.读取类中的所有带有Excel注解的属性的属性名(个数应和Exel的列的个数对应)。
2.将每一行组成Map<String,String>的数据,代表一个对象。那么多选就是List<Map<String,String>>,然后将其序列化,就类似于这样的Json:

[
{"name":"king1","age":"18"
},
{"name":"king2","age":"19"
},
......
]

组合成了对象数组的Json格式了,这时候只要调用Json工具的List list = JSON.parseArray(json, Class clazz)方法就可以拿到反序列的对象了,这个做法是不是有点骚气==》==》》》》》》

约定:

List中的类中带有Excel注解的属性必需与Excel文件中的数据完全对应,才能反序列成功。说的简单点,就是反序列时类属性上的@Excel注解要和导出为Excel时加的@Excel注解一样。

七、Excel工具类代码

7.1 Excel.java

package com.kingboy.common.utils.excel;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author kingboy--KingBoyWorld@163.com* @date 2017/7/26 下午1:23* @desc Excel注解,用以生成Excel表格文件.*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Excel {//列名String name() default "";//宽度int width() default 25;//忽略该字段boolean skip() default false;//日期格式String dateFormat() default "yyyy年MM月dd日 HH:mm";}

7.2 ExcelStyle.java

package com.kingboy.common.utils.excel;import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;/*** @author kingboy--KingBoyWorld@163.com* @date 2017/7/26 下午4:58* @desc 设置Excel的样式.使用了build模式,链式赋值*/
public class ExcelStyle {public ExcelStyle() { }//对齐方式private HorizontalAlignment align;//字体  "黑体"等private String fontName;//是否加粗,对表头不生效private boolean isBold;//字体大小private short size;//字体颜色private short fontColor;//边框粗细private BorderStyle borderStyle;//背景颜色private short backColor;public ExcelStyle setAlign(HorizontalAlignment align) {this.align = align;return this;}public ExcelStyle setFontName(String fontName) {this.fontName = fontName;return this;}public ExcelStyle setBold(boolean bold) {isBold = bold;return this;}public ExcelStyle setSize(short size) {this.size = size;return this;}public ExcelStyle setFontColor(short fontColor) {this.fontColor = fontColor;return this;}public ExcelStyle setBorderStyle(BorderStyle borderStyle) {this.borderStyle = borderStyle;return this;}public ExcelStyle setBackColor(short backColor) {this.backColor = backColor;return this;}public HorizontalAlignment getAlign() {return align;}public String getFontName() {return fontName;}public boolean isBold() {return isBold;}public short getSize() {return size;}public short getFontColor() {return fontColor;}public BorderStyle getBorderStyle() {return borderStyle;}public short getBackColor() {return backColor;}
}

7.3 ExcelUtils.java

package com.kingboy.common.utils.excel;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** @author kingboy--KingBoyWorld@163.com* @date 2017/7/26 下午1:25* @desc Excel工具类. 只针对单个类内的属性进行转换。* 额外说明:本工具类支持设置数据行的格式,但由于这个功能占用执行时间过多(大约十倍),所以在205行注释掉了,有需要可以打开* 使用说明-博客:http://blog.csdn.net/kingboyworld/article/details/76253785*/
public final class ExcelUtils {private ExcelUtils() { }/*** 将List转换成Excel* @param list 数据集合* @param filePath java7中的文件操作  创建方式:Paths.get("文件地址");* @param <T> bean类型* @return* @throws Exception*/public static <T> void listToExcel(List<T> list, Path filePath, Map<String, Map<String, String>> fieldMapper,ExcelStyle headStyle, ExcelStyle contentStyle) throws Exception {//List为null或者empty抛出异常Optional.ofNullable(list).filter(l -> !l.isEmpty()).orElseThrow(NullPointerException::new);//1. 获取类的字符串属性List<Excel> excelList = getExcelAnnoList(list.get(0).getClass());//2. 创建工件薄,工件表Workbook workbook = new SXSSFWorkbook();Sheet sheet = workbook.createSheet();//3. 设置表头setHead(excelList, sheet, headStyle);//4. 设置内容setContent(list, sheet, fieldMapper, contentStyle);//5. 写文件workbook.write(Files.newOutputStream(filePath));}//每次转换多少行private static Integer size = 1_000;/*** excel转换为List,基本思路是拼接成Json,然后用Json工具转换为List* 必需保证类里面的带有Excel注解属性的顺序和Excel文件中标题的顺序相对应* @param filePath 文件路径    创建方式:Paths.get("文件地址");* @param clazz 类* @param <T>* @return*/public static<T> List<T> excelToList(Path filePath, Class<T> clazz, Map<String, Map<String, String>> fieldMapper)throws Exception {Workbook workbook = new XSSFWorkbook(Files.newInputStream(filePath));Sheet sheet = workbook.getSheetAt(0);//1. 获取类和Excel表格对应的属性,有序放入ArrayList中ArrayList<String> fieldList = getFieldNameByExcelAnno(clazz);//2. 获取结果ArrayList<T> resultList = getClazzArrayList(sheet, clazz, fieldList, fieldMapper);return resultList;}/*------------------------------ExcelToList的调用方法------------------------------------*//**** @param sheet 工作表* @param fieldList 获取类中有映射关系的属性名* @param <T>* @return*/private static <T> ArrayList<T> getClazzArrayList(Sheet sheet, Class<T> clazz, ArrayList<String> fieldList,Map<String, Map<String, String>> fieldMapper) {//数据行数int rowNumber = sheet.getPhysicalNumberOfRows() - 1;//读取次数int times = rowNumber / size + 1;//结果集ArrayList<T> result = new ArrayList<T>(rowNumber);Stream.iterate(1, i -> i + 1).limit(times - 1).forEach(i -> {result.addAll(getArrayListFromMap(readExcel((i - 1) * size + 1, i == times ? rowNumber : size, sheet, fieldList),clazz,fieldMapper));});return result;}/*** 解析Json字符串* @param mapList Excel表中的数据* @param clazz* @param fieldMapper 属性转换容器* @param <T>* @return*/private static <T> List<T> getArrayListFromMap(List<Map<String, String>> mapList, Class<T> clazz,Map<String, Map<String, String>> fieldMapper) {//记录默认的日期格式String tempDateFormat = JSONObject.DEFFAULT_DATE_FORMAT;//设置日期编码getFieldWithExcel(clazz).filter(field -> field.getType() == Date.class || field.getType() == LocalDateTime.class).findFirst().ifPresent(field ->JSONObject.DEFFAULT_DATE_FORMAT = field.getAnnotation(Excel.class).dateFormat());//转换属性if (fieldMapper != null) {mapList.stream().forEach(map -> {map.forEach((key, value) -> {if (fieldMapper.get(key) != null) {//真实的属性值String realValue = fieldMapper.get(key).get(value);//如果有对应的值,就设置对应的值map.put(key, realValue == null ? value : realValue);}});});}List<T> list = JSON.parseArray(JSON.toJSONString(mapList), clazz);//还原默认的日期格式JSONObject.DEFFAULT_DATE_FORMAT = tempDateFormat;return list;}/*** 读取指定数量的数据,每行都拼接成一个Map<String, String>的集合* @param start 开始行* @param size 长度* @param sheet* @param fieldList 获取类中有映射关系的属性名* @return*/private static <T> ArrayList<Map<String, String>> readExcel(int start, int size, Sheet sheet, ArrayList<String> fieldList) {ArrayList<Map<String, String>> listMap = new ArrayList<>();for (int i = start; i < start + size; i++) {Map<String, String> map = new TreeMap<>();for (int j = 0; j < fieldList.size(); j++) {map.put(fieldList.get(j), sheet.getRow(i).getCell(j).getStringCellValue());}listMap.add(map);}return listMap;}/*** 获取属性名* @param clazz* @param <T>* @return* @throws Exception*/private static <T> ArrayList<String> getFieldNameByExcelAnno(Class<T> clazz) throws Exception {return getFieldWithExcel(clazz).map(field -> field.getName()).collect(Collectors.toCollection(ArrayList::new));}/*------------------------------ListToExcel的调用方法------------------------------------*//*** 写入内容* @param list 数据内容* @param sheet* @param fieldMapper 属性转换* @param <T>*/private static <T> void setContent(List<T> list, Sheet sheet, Map<String, Map<String, String>> fieldMapper, ExcelStyle contentStyle) {Stream.iterate(0, item -> item + 1).limit(list.size()).forEach(item -> {//当前行Row row = sheet.createRow(item + 1);//每个对象的属性值List<String> fieldValue = getFiledValueIfIsExcel(list.get(item), fieldMapper);Stream.iterate(0, i -> i + 1).limit(fieldValue.size()).forEach(i -> {Cell cell = row.createCell(i);cell.setCellType(CellType.STRING);//cell.setCellStyle(getContentStyle(sheet.getWorkbook(), contentStyle));cell.setCellValue(fieldValue.get(i));});});}/*** 写入标题* @param excelList 标题* @param sheet*/private static void setHead(List<Excel> excelList, Sheet sheet, ExcelStyle headStyle) {Row row = sheet.createRow(0);Stream.iterate(0, item -> item + 1).limit(excelList.size()).forEach(item -> {Cell cell = row.createCell(item);cell.setCellType(CellType.STRING);cell.setCellValue(excelList.get(item).name());cell.setCellStyle(getTitleStyle(sheet.getWorkbook(), headStyle));sheet.setColumnWidth(item, excelList.get(item).width() * 2 << 6);});}/*** 设置头样式* @param workbook* @return*/private static CellStyle getTitleStyle(Workbook workbook, ExcelStyle headStyle) {CellStyle cellStyle = workbook.createCellStyle();headStyle = headStyle == null ? new ExcelStyle() : headStyle;//对齐方式cellStyle.setAlignment(headStyle.getAlign() == null ? HorizontalAlignment.CENTER : headStyle.getAlign());//设置字体Font font = workbook.createFont();String fontName = headStyle.getFontName();font.setFontName(null == fontName ? "黑体" : fontName);//字体大小font.setFontHeightInPoints(headStyle.getSize() <= 0 ? 14 : headStyle.getSize());font.setBold(true);font.setColor(headStyle.getFontColor() <= 0 ? HSSFColor.BLACK.index : headStyle.getFontColor());cellStyle.setFont(font);//背景cellStyle.setFillForegroundColor(headStyle.getBackColor() <= 0? HSSFColor.SEA_GREEN.index: headStyle.getBackColor());cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);BorderStyle border = headStyle.getBorderStyle() == null ? BorderStyle.MEDIUM : headStyle.getBorderStyle();//边框cellStyle.setBorderLeft(border);cellStyle.setBorderTop(border);cellStyle.setBorderRight(border);cellStyle.setBorderBottom(border);//自动换行//cellStyle.setWrapText(true);return cellStyle;}/*** 设置内容样式,占用过大,并没有开启这个功能* @param workbook* @return*/private static CellStyle getContentStyle(Workbook workbook, ExcelStyle contentStyle) {contentStyle = contentStyle == null ? new ExcelStyle() : contentStyle;CellStyle cellStyle = workbook.createCellStyle();//对齐方式cellStyle.setAlignment(contentStyle.getAlign() == null ? HorizontalAlignment.LEFT : contentStyle.getAlign());//设置字体Font font = workbook.createFont();String fontName = contentStyle.getFontName();font.setFontName(null == fontName ? "黑体" : fontName);//字体大小font.setFontHeightInPoints(contentStyle.getSize() <= 0 ? 12 : contentStyle.getSize());font.setBold(contentStyle.isBold());font.setColor(contentStyle.getFontColor() <= 0 ? HSSFColor.BLACK.index : contentStyle.getFontColor());cellStyle.setFont(font);//背景cellStyle.setFillForegroundColor(contentStyle.getBackColor() <= 0? HSSFColor.WHITE.index: contentStyle.getBackColor());cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);BorderStyle border = contentStyle.getBorderStyle() == null ? BorderStyle.THIN : contentStyle.getBorderStyle();//边框cellStyle.setBorderLeft(border);cellStyle.setBorderTop(border);cellStyle.setBorderRight(border);cellStyle.setBorderBottom(border);//自动换行//cellStyle.setWrapText(true);return cellStyle;}/*** 拿到一个类中属性上的Excel注解* @param clazz* @param <T>* @return* @throws Exception*/private static <T> List<Excel> getExcelAnnoList(Class<T> clazz) throws Exception {return  getFieldWithExcel(clazz).map(field -> field.getAnnotation(Excel.class)).collect(Collectors.toCollection(ArrayList::new));}/*** 获取带有Excel注解的属性* @param clazz* @param <T>* @return*/private static <T> Stream<Field> getFieldWithExcel(Class<T> clazz) {Field[] fields = clazz.getDeclaredFields();return Arrays.stream(fields).filter(field -> {Excel excel = field.getAnnotation(Excel.class);return excel != null && !excel.skip();});}/*** 获取一个类包含Excel注解的属性的值* @param t* @param <T>* @return*/private static  <T> List<String> getFiledValueIfIsExcel(T t, Map<String, Map<String, String>> fieldMapper) {return getFieldWithExcel(t.getClass()).map(field -> {field.setAccessible(true);Object o = null;try {o = field.get(t);} catch (IllegalAccessException e) {e.printStackTrace();}//如果属性值为空,返回空字符串if (Objects.isNull(o)) {o =  "";}//如果是Date类型if (o instanceof Date) {o =  new SimpleDateFormat(field.getAnnotation(Excel.class).dateFormat()).format((Date) o);}//如果是LocalDateTime类型,支持Java8LocalDateTimeif (o instanceof LocalDateTime) {o =  ((LocalDateTime) o).format(DateTimeFormatter.ofPattern(field.getAnnotation(Excel.class).dateFormat()));}//bool和int属性转换,感觉最常用这两个,其它的需要再扩充if (fieldMapper != null && (o instanceof Boolean || o instanceof Integer)) {Map<String, String> map = fieldMapper.get(field.getName());o =  map == null ? o : map.get(o.toString()) == null ? o : map.get(o.toString());}//其它的返回toStringreturn o.toString();}).collect(Collectors.toCollection(ArrayList::new));}}

八、使用方法

//把List转换为Excel
public static <T> void listToExcel(List<T> list, Path filePath, Map<String, Map<String, String>> fieldMapper, ExcelStyle headStyle, ExcelStyle contentStyle) {}

参数说明:
1. list: 要转换的类(类中需要转换的属性需要加上Excel注解)
2. filePath: Java7中的文件操作类。Excel导出的地址
3. fieldMapper: 属性转换(可以为null)
4. headStyle: 头部样式(可以为null),为空时使用默认样式。
5. contentStyle:内容体的样式(可以为null),这个默认不生效(由于这个功能占用执行时间过多(大约十倍),所以在205行注释掉了,有需要可以打开)

//把Excel转换为List

excelToList(Path filePath, Class<T> clazz, Map<String, Map<String, String>> fieldMapper){}

参数说明:
1. filePath: Java7中的文件操作类。Excel导出的地址
2. clazz: 要转换的类
3. fieldMapper: 属性转换(可以为null)
4. 如果有日期等,需要在类属性的Excel注解上给dateFormat属性赋值。

九、测试用例

//基础类
public class ExcelDTO {@Excel(name = "姓名", width = 30)private String name;@Excel(name = "年龄", width = 30)private Integer age;@Excel(skip = true)private String password;@Excel(name = "生日", dateFormat = "yyyy年MM/dd HH:mm", width = 50)private Date birth;@Excel(name = "帐户")private Double money;@Excel(name = "冻结")private Boolean lock;//getter,setter}

测试


/*** @author kingboy--KingBoyWorld@163.com* @date 2017/7/26 下午2:04* @desc 测试我写的Excel工具类.*/
public class MyExcelTest {/*** 导出为Excel,将属性进行转换。* @throws Exception*/@Testpublic void ListToExcel_test() throws Exception {long start = System.nanoTime();//属性转换Map<String, Map<String, String>> map = new HashMap<>();//age的转换Map<String, String> value = new HashMap<>();value.put("12", "12岁");value.put("15", "15岁");value.put("18", "18岁");map.put("age", value);//lock的转换Map<String, String> lock = new HashMap<>();lock.put("true", "锁");lock.put("false", "正常");map.put("lock", lock);ExcelUtils.listToExcel(getExcelDTOList(), Paths.get("/Users/kingboy/Desktop/My.xlsx"), map, null, null);System.out.println("-----my-------" + (System.nanoTime() - start) / 1000_000 + "毫秒");}/*** 导出为Excel,没有将属性进行转换。* @throws Exception*/@Testpublic void ListToExcelNoMapper_test() throws Exception {//没有转换属性测试ExcelUtils.listToExcel(getExcelDTOList(), Paths.get("/Users/kingboy/Desktop/My1.xlsx"), null, new ExcelStyle().setBackColor(HSSFColor.WHITE.index),new ExcelStyle().setAlign(HorizontalAlignment.CENTER));}/*** 导入为List,将属性进行转换。* 注意属性转换是反过来的。* @throws Exception*/@Testpublic void ExcelToList_test() throws Exception {long start = System.nanoTime();Map<String, Map<String, String>> map = new HashMap<>();Map<String, String> value = new HashMap<>();value.put("小", "12");value.put("中", "15");value.put("大", "18");Map<String, String> lock = new HashMap<>();lock.put("锁", "true");lock.put("正常", "false");map.put("age", value);map.put("lock", lock);List<ExcelDTO> excelDTOS = ExcelUtils.excelToList(Paths.get("/Users/kingboy/Desktop/My.xlsx"), ExcelDTO.class, map);System.out.println("----my--------" + (System.nanoTime() - start) / 1000_000 + "毫秒");}public List<ExcelDTO> getExcelDTOList() {List<ExcelDTO> list = new ArrayList<>();Stream.iterate(1, item -> item + 1).limit(10000).forEach(item -> list.add(new ExcelDTO("king1", 15, "1123", new Date(), 111d, true)));return list;}}

导出的效果图:

有属性转换的效果:

无属性转换的效果:

炎炎夏日最新版Excel导入导出工具类火热出炉相关推荐

  1. 一个基于POI的通用excel导入导出工具类的简单实现及使用方法

    前言: 最近PM来了一个需求,简单来说就是在录入数据时一条一条插入到系统显得非常麻烦,让我实现一个直接通过excel导入的方法一次性录入所有数据.网上关于excel导入导出的例子很多,但大多相互借鉴. ...

  2. java Excel导入导出工具类 及使用demo

    java Excel导入导出工具类 及使用demo 前言:相信进来的都是想尽快解决问题的,话不多说,按照以下步骤来,可以操作导出excel到本地,导入同理,自行学习.步骤一:直接复制以下excel工具 ...

  3. Java操作百万数据量Excel导入导出工具类(程序代码教程)

    Java操作百万数据量Excel导入导出工具类(程序代码教程): # 功能实现1.自定义导入数据格式,支持配置时间.小数点类型(支持单/多sheet)(2种方式:本地文件路径导入(只支持xls.xls ...

  4. Excel导入导出工具类

    目录 1.mavn jar 2 工具类代码 2.1 ExcelUtil 2.2 引用自写类 2.2.1 ExcelMsg 2.2.2 CellDataType 2.2.3 SaxReadExcelUt ...

  5. Java poi 实现excel导入导出工具类

    最近项目上又要大量的涉及excel导入导出,网上各种导入导出的方式层出不穷,我是比较青睐官方的poi,但是要自己去操作工作簿对象自己一行一行的读取,会有很多的重复代码,重复劳动,也极为不美观,基于合成 ...

  6. Excel导入导出工具类(多sheet、多表头、单元格下拉选择、根据列名匹配转为List)

    一.多sheet 通过配置动态生成多个工作表(sheet),自定义sheet的名称,如下效果图: 二.多表头 通过配置生成多表头,效果图如下: 主要核心代码: // 赋值后,执行合并单元格 log.t ...

  7. java开发excel导入导出工具类基于EasyExcel

    一.工具类 import com.alibaba.excel.EasyExcel; import com.alibaba.excel.write.style.column.LongestMatchCo ...

  8. excel导入导出工具类_Hutool Java工具类库导出Excel,超级简单

    前言 在开发应用系统的时候,导出文件是必不可少的功能. 以前用过POI.easyexcel等工具的导入导出功能,但总感觉太麻烦了,代码特别多,感觉并不是很好用. 今天给大家介绍一款新工具,java工具 ...

  9. Java基础学习总结(49)——Excel导入导出工具类

    在项目的pom文件中引入 <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifac ...

最新文章

  1. Timer和TimerTask
  2. POJ 1106 Transmitters(计算几何)
  3. python程序设计基础电子版_Python 程序设计基础(董付国 著)完整版PDF[6MB]
  4. phpstudy安装ssl证书_新版Siteground一键安装免费SSL证书 网站https安全访问
  5. minigui linux 安装与运行
  6. 服务器可以装两个系统吗,云服务器可以装多个系统吗
  7. Java中String、StringBuffer、StringBuilder三者的区别
  8. Softmax回归模型的构建和实现(Fashion-MNIST图像分类)
  9. Head First SQL Your Brain on SQL读书笔记
  10. 酷q机器人php源码,酷Q机器人完整的一套源代码,智能化管理群组
  11. 广告中cpm,ecpm,rpm指标含义
  12. 网易新版BLOG邀请,有需要的朋友进。
  13. 视觉SLAM十四讲笔记-第四讲 李群与李代数
  14. PTrade和QMT对比那个更好用?
  15. CSDN博客论坛——读好书,畅想“我的IT成长路”活动【已完成】
  16. python2.7开发photoshop一些经验
  17. oracle打开错误日志文件,Oracle联机日志出现错误ORA-16038 ORA-19809 ORA-00312 解决
  18. ModuleNotFoundError: No module named ‘_bz2‘问题解决
  19. 微博 - 如何修改微博昵称?
  20. “菩提子”是菩提树的种子吗?

热门文章

  1. Win10系统中看不到局域网电脑且服务里没有Computer Browser如何解决
  2. linux 下阻塞睡眠等待selec函数简单实现
  3. y.sing_【Y.SING衣香丽影(国商店)】Y.SING衣香丽影(国商店)电话,Y.SING衣香丽影(国商店)地址_图吧地图...
  4. 【人工智能的数学基础】利普希茨连续条件(Lipschitz Continuity Condition)
  5. [杂谈] 记 程序员 对抗失眠烦恼的 大法
  6. 阅读:网络安全工程师和信息安全工程师有什么区别?
  7. Java:时间戳转换成时间
  8. 老鱼Python数据分析——篇十八:消息推送(二)
  9. 我的第一个博客(开始自学PHP之路)
  10. 行业变天,汽车经销商如何转型破局?