前言

由于工作原因,有这种需求,就是把数据库中的数据导出成 Excel 表格,同时,也得支持人家用 Excel 表格导入数据到数据库。当前项目也是在用 EasyExcel,所以我不得不学啦!

以前学习的过程中,有听过 EasyExcel 这么一个东西,不过从来没用过,所以,正好借此机会学习,看看如何使用它来实现需求。

在学习 EasyExcel 的这段时间里,也了解到工作中这种导入导出的需求还是挺常见的,所以决定记录下来。

官方文档:https://easyexcel.opensource.alibaba.com/docs/current/

需求

用户点击导入按钮,就能够上传 Excel 文件,将 Excel 文件的数据导入到系统中。

用户勾选目标数据 id,点击导出按钮,就能将系统中的数据以 Excel 文件的格式下载到本地。

分析

导入,从用户的视角来看,就是导入 Excel 文件;从开发者的视角,或者说系统的视角来看,就是读取用户的 Excel 文件的数据到系统中(实际上是读取到计算机的内存中),最后将读取到的数据存储到数据库,EasyExcel 在导入的过程中进行了读操作

导出,同理,用户的视角就是导出,开发者的视角就是把系统的数据写入到用户的计算机上,即写操作

简而言之,涉及 IO 操作的,视角不同,说法不同(初学IO时就没搞清楚,为我后续的学习留下了大坑T_T!)。

当然我们也可以把导入说成写操作,毕竟数据是最终是存储在系统的数据库中的,即写到了系统的数据库里了。自己别搞混了就行。

准备

本 Demo 使用 Spring Boot 构建,配合 MyBaits Plus,以游戏数据导入和导出作为需求;一些工具依赖如下:

<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.10</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

依赖

今天 EasyExcel 主菜,需要加其依赖才能食用~

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.7</version>
</dependency>

配置

server:
port: 4790 spring:
application:
name: easyexcel-demo
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/easy_excel_demo?useUnicode=true&autoReconnect=true&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&characterEncoding=utf8
username: root
password: 123456

游戏实体类

咱们的游戏类就这些属性:id、游戏名称、价格、uuid,发售日期、创建时间、修改时间

/**
* @author god23bin
* @version 1.0
* @description 游戏
* @date 2022/10/21 16:51:02
*/
@Data
@TableName("t_game")
public class Game { @TableId(type = IdType.AUTO)
private Long id; private String name; private Double price; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" ,timezone = "GMT+8")
private Date releaseDate; @TableField(fill = FieldFill.INSERT)
private String uuid; @TableField(fill = FieldFill.INSERT)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" ,timezone = "GMT+8")
private Date gmtCreate; @TableField(fill = FieldFill.INSERT_UPDATE)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" ,timezone = "GMT+8")
private Date gmtModified;
}

模型

啥是模型?别慌,先假设需要导入的 Excel 表格长这样:

那么这个就是所谓的模型啦,不管是还是,都需要相对应的对象,所以一般会编写一个读对象的类和写对象的类,当然,如果读写的表头字段都是一模一样,直接一个类就可以了,导入导出都用这个类。

读对象

读对象-GameImportExcelModel

/**
* @author god23bin
* @version 1.0
* @description Game 导入的 Excel 数据模型(读对象)
* @date 2022/10/21 17:18:50
*/
@Data
public class GameImportExcelModel { private String name; private Double price; private Date releaseDate;
}

写对象

写对象-GameExportExcelModel

/**
* @author god23bin
* @version 1.0
* @description Game 导出的 Excel 数据模型(写对象)
* @date 2022/10/21 17:18:50
*/
@Data
public class GameExportExcelModel { @ExcelProperty("游戏ID")
private Long id; @ExcelProperty("游戏名")
private String name; @ExcelProperty("价格")
private Double price; @ExcelProperty("发售日期")
private Date releaseDate;
}

实现

导入功能

用户点击导入按钮,就能够上传 Excel 文件,将 Excel 文件的数据导入到系统中。

前端实现一个上传文件的按钮,后端就接收这个文件,读取这个文件的数据,存储到数据库中。

开胃菜-后端

搭个整体的代码框架先!

持久层

GameMapper

@Mapper
public interface GameMapper extends BaseMapper<Game> {
}
业务层

GameService

/**
* @author god23bin
* @version 1.0
* @description
* @date 2022/11/8 14:36:43
*/
public interface GameService { /**
* 导入Excel数据到数据库
* @date 2022/11/8 14:38
* @param file Excel文件
* @return boolean
**/
boolean importExcel(MultipartFile file); }

GameServiceImpl

/**
* @author god23bin
* @version 1.0
* @description
* @date 2022/11/8 14:40:08
*/
@Slf4j
@Service
public class GameServiceImpl extends ServiceImpl<GameMapper, Game> implements GameService { @Resource
private GameMapper gameMapper; /**
* 导入Excel数据到数据库
*
* @param file Excel文件
* @return boolean
* @date 2022/11/8 14:38
**/
@Override
public boolean importExcel(MultipartFile file) {
// 这里就需要用到「读监听器」了,需要我们自己实现
return null;
} }
控制层

GameController

/**
* @author god23bin
* @version 1.0
* @description
* @date 2022/11/8 14:31:50
*/
@RestController
public class GameController { @Resource
private GameService gameService; @PostMapping("/excel/import/game")
public ResponseEntity<String> importExcel(@RequestPart("file") MultipartFile file) {
gameService.importExcel(file);
return new ResponseEntity<>("OK", HttpStatus.OK);
}
}

正餐-读数据需要用到的监听器

对于读取,有一个监听器需要我们实现,根据文档的说明,这个监听器是不可以让 Spring 来管理的。

有个很重要的点 DemoDataListener 不能被 spring管理,要每次读取 excel都要 new,然后里面用到 spring 可以构造方法传进去

所以我们也不需要加上 @Component 注解把这个类作为组件让 Spring 扫描。直接一个普通的类就行

具体代码如下,需要知道的是:

  • 需要继承 AnalysisEventListener 类,参数化的类型(泛型)为 GameImportExcelModel(读对象)

GameImportExcelListener

/**
* @author god23bin
* @version 1.0
* @description
* @date 2022/10/24 08:45:15
*/
@Slf4j
public class GameImportExcelListener extends AnalysisEventListener<GameImportExcelModel> { /**
* 每隔100条存储到数据库,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 100; /**
* 缓存的数据
*/
private List<Game> cachedDataList = new ArrayList<>(BATCH_COUNT); /**
* 每解析一行数据就会执行这个方法
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(GameImportExcelModel data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSON.toJSONString(data));
Game game = new Game();
BeanUtil.copyProperties(data, game);
cachedDataList.add(game);
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
cachedDataList.clear();
}
} private void saveData() {
// 这里写存储到数据库的逻辑代码
} /**
* 解析完之后会执行这个方法,如果有其他事情需要做,可以在这里加上代码来完成
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}
}

但是!如果我们想要使用 Spring IOC 管理对象,比如 Dao、Mapper 这些对象,现在当前类是用不了 @Autowired 注解将这些对象注入的,那我们怎么获取它们?

方法就是:在该类中写一个构造方法,将这些被 Spring 管理的对象作为参数传入进来!

比如我这里需要用到 GameMapper 对象,那么就将它作构造方法的参数传进来。

@Slf4j
public class GameImportExcelListener extends AnalysisEventListener<GameImportExcelModel> { // 省略其他代码 private GameMapper gameMapper; public GameImportExcelListener(GameMapper gameMapper) {
this.gameMapper = gameMapper;
} @Override
public void invoke(GameImportExcelModel data, AnalysisContext context) {
// ...
} private void saveData() {
// ...
} @Override
public void doAfterAllAnalysed(AnalysisContext context) {
// ...
}
}
完整的监听器代码

GameImportExcelListener

package cn.god23bin.demo.excel.listener;

import cn.god23bin.demo.entity.Game;
import cn.god23bin.demo.excel.bean.GameImportExcelModel;
import cn.god23bin.demo.mapper.GameMapper;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j; import java.util.ArrayList;
import java.util.List; /**
* @author zwb
* @version 1.0
* @description
* @date 2022/10/24 08:45:15
*/
@Slf4j
public class GameImportExcelListener extends AnalysisEventListener<GameImportExcelModel> { /**
* 每隔100条存储到数据库,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 100; /**
* 缓存的数据
*/
private List<Game> cachedDataList = new ArrayList<>(BATCH_COUNT); private GameMapper gameMapper; public GameImportExcelListener(GameMapper gameMapper) {
this.gameMapper = gameMapper;
} /**
* 每解析一行数据就会执行这个方法
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(GameImportExcelModel data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSON.toJSONString(data));
Game game = new Game();
BeanUtil.copyProperties(data, game);
cachedDataList.add(game);
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
cachedDataList.clear();
}
} private void saveData() {
// 这里写存储到数据库的逻辑代码
for (Game game : cachedDataList) {
gameMapper.insert(game);
}
} /**
* 解析完之后会执行这个方法,如果有其他事情需要做,可以在这里加上代码来完成
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}
}

完善业务层

  1. 使用 EasyExcel.read() 方法构建一个 Excel reader builder,第一个参数是文件输入流,第二个参数是读对象,指定它这个class去读,第三个参数就是读监听器
  2. 接着链式调用 sheet() 方法和 doRead() 方法,完成整个 Excel 的读取操作。
@Slf4j
@Service
public class GameServiceImpl extends ServiceImpl<GameMapper, Game> implements GameService { @Resource
private GameMapper gameMapper; /**
* 导入Excel数据到数据库
*
* @param file Excel文件
* @return boolean
* @date 2022/11/8 14:38
**/
@Override
public boolean importExcel(MultipartFile file) {
try {
// 使用 EasyExcel.read() 方法构建一个 Excel reader builder,第一个参数是文件输入流,第二个参数是读对象,指定它这个class去读,第三个参数就是读监听器
EasyExcel.read(file.getInputStream(), GameImportExcelModel.class, new GameImportExcelListener(gameMapper))
.sheet()
.doRead();
} catch (IOException e) {
log.error("Error importing: {}", e.getMessage());
return false;
}
return true;
} }

测试

使用 Postman 测试,请求后端的导入 Excel 的接口,在 Postman 中选好 Post 请求并且输入请求路径。

点击 Headers 设置请求头:

  • Key 中输入 Content-Type,属性的值输入 multipart/form-data

点击 Body 设置请求体:

  • 选择 form-data 格式,Key 中输入 file,便可以选择文件进行上传了

测试结果:

可以看到Excel中的数据成功存储到数据库中了,这就完成了导入的功能!

导出功能

用户勾选目标数据 id,点击导出按钮,就能将系统中的数据以 Excel 文件的格式下载到本地。

细节:需要导出的文件名称为这种格式:游戏列表-2022-11-11-12-30-00.xlsx

在这个导出文件的场景下,就需要后端返回前端文件数据,后端有两种方式可以返回,让前端进行下载。

  1. 后端返回文件所在的 URL,前端直接根据 URL 进行下载。
  2. 后端以二进制流的形式返回文件流,前端再接受这个流下载到本地。

由于我们的数据是在数据库中的,并不是直接存储 Excel 文件的,所以我们以二进制流的形式返回文件流给前端,让前端下载。

看看 EasyExcel 的 write 方法签名,里面有好多个重载的 write 方法,我们看看这个就行:

public static ExcelWriterBuilder write(OutputStream outputStream, Class head)

参数说明:

  • 第一个参数是文件输出流
  • 第二个参数是指定我们要参照哪个模型类去写这个 Excel,head 意思就是该类的属性将作为 Excel 的表头。

代码

主要逻辑
// 假设这里是从数据库获取的集合
List<Game> data = ...;
// 文件格式
String fileName = new String("");
String format = "yyyy-MM-dd-HH-mm-ss";
fileName = fileName + DateUtil.format(new Date(), format);
// 将数据写到输出流返回给前端
EasyExcel.write(ExcelUtil.getResponseOutputStream(fileName, response), GameExportExcelModel.class)
.sheet("工作簿")
.doWrite(dataList);
Excel 工具类
/**
* @author god23bin
* @version 1.0
* @description Excel 工具类
* @date 2022/11/18 17:55:48
*/
public class ExcelUtil { /**
* 获取响应输出流
* @date 2022/11/18 18:10
* @param fileName 文件名
* @param response 响应
* @return java.io.OutputStream
**/
public static OutputStream getResponseOutputStream(String fileName, HttpServletResponse response) {
try {
// 给文件名编码,则前端接收后进行解码
fileName = URLEncoder.encode(fileName, "UTF-8");
// 指定客户端接收的响应内容类型为Excel以及字符编码为UTF-8
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf8");
// 让浏览器提供打开、保存的对话框,以附件的形式下载,同时设置文件名格式
response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx");
// 禁止缓存
response.setHeader("Cache-Control", "no-store");
response.addHeader("Cache-Control", "max-age=0");
return response.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

控制层

用 Set 集合去重,防止多次查询同一数据。

    @PostMapping("/excel/export/game")
public ResponseEntity<String> exportExcel(@RequestBody Set<String> uuidList, HttpServletResponse response) {
gameService.exportExcel(new ArrayList<>(uuidList), response);
return new ResponseEntity<>("OK", HttpStatus.OK);
}

业务层

主要逻辑是去数据库查询出需要导出的数据,然后转成对应的导出模型对象,最后使用 EasyExcel 的 write() 方法将数据写到输出流。

    /**
* 导出数据库记录到Excel
*
* @param uuidList uuid集合
* @param response 响应
* @return boolean
* @date 2022/11/11 14:23
**/
@Override
public boolean exportExcel(List<String> uuidList, HttpServletResponse response) {
// 根据uuid找到需要导出的记录集合
LambdaQueryWrapper<Game> achievementWrapper = new LambdaQueryWrapper<>();
achievementWrapper.in(Game::getUuid, uuidList);
achievementWrapper.orderByDesc(Game::getGmtCreate);
List<Game> games = this.baseMapper.selectList(achievementWrapper);
// 将查询到的数据转换成对应Excel的导出模型对象
List<GameExportExcelModel> dataList = games.stream().map(game -> {
GameExportExcelModel gameExportExcelModel = new GameExportExcelModel();
BeanUtil.copyProperties(game, gameExportExcelModel);
return gameExportExcelModel;
}).collect(Collectors.toList());
// 文件格式
String fileName = new String("");
String format = "yyyy-MM-dd-HH-mm-ss";
fileName = fileName + DateUtil.format(new Date(), format);
// 将数据写到输出流返回给前端
EasyExcel.write(ExcelUtil.getResponseOutputStream(fileName, response), GameExportExcelModel.class)
.sheet("工作簿")
.doWrite(dataList);
return true;
}

测试

以请求体的方式传递一个需要导出的游戏的 uuid 数组

点击 Send 按钮旁边的三角符号,点击 Send and Download,这样就可以下载了,最后下载的 Excel 打开后如下:

额,翻车,格式有点点问题,问题不大,这时候就需要一个自定义的拦截器帮我们处理单元格。

自定义拦截器

拿来主义,写法基本是这样:

EasyExcel导出自动适应列宽 Excel样式

public class CustomCellWriteHandler extends AbstractColumnWidthStyleStrategy {

    private static final int MAX_COLUMN_WIDTH = 255;

    private Map<Integer, Map<Integer, Integer>> cache = new HashMap<>(16);

    public CustomCellWriteHandler() {
}
/**
* Sets the column width when head create
*
* @param writeSheetHolder
* @param cellDataList
* @param cell
* @param head
* @param relativeRowIndex
* @param isHead
*/
@Override
protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
if (needSetWidth) {
Map<Integer, Integer> maxColumnWidthMap = cache.get(writeSheetHolder.getSheetNo());
if (maxColumnWidthMap == null) {
maxColumnWidthMap = new HashMap<>(16);
cache.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
} Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
if (columnWidth >= 0) {
if (columnWidth > 255) {
columnWidth = 255;
}
Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 7250);
}
}
}
} private Integer dataLength(List<CellData> cellDataList, Cell cell, Boolean isHead) {
if (isHead) {
return cell.getStringCellValue().getBytes().length;
} else {
CellData cellData = (CellData) cellDataList.get(0);
CellDataTypeEnum type = cellData.getType();
if (type == null) {
return -1;
} else {
switch (type) {
case STRING:
return cellData.getStringValue().getBytes().length;
case BOOLEAN:
return cellData.getBooleanValue().toString().getBytes().length;
case NUMBER:
return cellData.getNumberValue().toString().getBytes().length;
default:
return -1;
}
}
}
}
}

但是为什么这样写,好吧,目前不了解T_T,有待研究。

接着注册这个拦截器,让它知道该如何处理,修改业务层的代码:

EasyExcel.write(ExcelUtil.getResponseOutputStream(fileName, response), GameExportExcelModel.class)
.sheet("工作簿")
.registerWriteHandler(new CustomCellWriteHandler())
.doWrite(dataList);

最后导出效果:

总结

某张 Excel 表需要你导入到系统中,这里系统指的就是你所做的项目,更准确来说将 Excel 的数据插入到你系统中的数据库里。那么就可以使用 EasyExcel。

常见的需求就是对 Excel 数据的导入导出,我们需要做的就是根据 Excel 表进行建模,创建对应的读对象和写对象。

对于导入,就需要读对象配合读监听器来实现。

对于导出,就直接通过 write 方法,以二进制流的方式将数据写到响应体中。

最后的最后

由本人水平所限,难免有错误以及不足之处, 屏幕前的靓仔靓女们 如有发现,恳请指出!

最后,谢谢你看到这里,谢谢你认真对待我的努力,希望这篇博客对你有所帮助!

你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!

初次邂逅 EasyExcel的更多相关文章

  1. 与JSP的初次邂逅……

    JSP是可以内嵌在网页中,由服务器端来执行与解释的程序,是一种动态网页技术标准. 在传统的HTML文件(*.htm或*.html)中加入Java程序片段和JSP标记,就构成了JSP网页(*.jsp). ...

  2. CMS3.0——初次邂逅express

    前言: 刚接手cms3.0的工作,似乎对一切都那么的不熟悉,于是在开始新需求之前,先做一个简单的登录系统. 项目目录: 1.使用webstroms建expreess项目,非常方便简单,建好的项目目录就 ...

  3. Java眼中的XML--文件读取--1 应用DOM方式解析XML

    初次邂逅XML: 需要解析的XML文件: 这里有两个book子节点. 1.如何进行XML文件解析前的准备工作,另外解析先获取book节点. 这个我后来看懂了: 这个Node的ELEMENT_NODE= ...

  4. Java眼中的XML--------文件读取

     XML 的初次邂逅 初次邂逅XML 如何进行XML文件解析前的准备工作 在Java程序中如何获取xml文件的内容 在Java程序中读取xml文件的过程也成为----解析xml文件 解析的目的:获取节 ...

  5. Java——关于static关键字的那些事总结

    前言: 先说说今天为啥要谈这个东西,虽然学Java已经有两年了,但是今天,本着温故而知新的态度,仔细的第三次翻看了<Head Firt Java>这本书,虽然这本书介绍的很多东西都特别基础 ...

  6. [转] C++ try catch() throw 异常处理

    原文地址 其它很多程序员一样,本书的主人公阿愚也是在初学C++时,在C++的sample代码中与异常处理的编程方法初次邂逅的,如下:   // Normal program statements  . ...

  7. 《Machine Learning in Action》—— 剖析支持向量机,单手狂撕线性SVM

    <Machine Learning in Action>-- 剖析支持向量机,单手狂撕线性SVM 前面在写NumPy文章的结尾处也有提到,本来是打算按照<机器学习实战 / Machi ...

  8. “知疫”疫情防控可视化平台——NABCD分析

    "知疫"疫情防控可视化平台 项目 内容 这个作业属于那个课程 2021春季学期软件工程(罗杰.任健) 这个作业的要求在哪里 初次邂逅,需求分析 1 NABCD分析 NEED 目前多 ...

  9. 「Unity卡牌自走棋」项目NABCD分析

    项目 内容 这个作业属于哪个课程 2021学年春季软件工程(罗杰 任健) 这个作业的要求在哪里 团队项目-初次邂逅,需求分析 在这个课程的目标是 锻炼在大规模开发中的团队协作能力 这个作业在哪个具体方 ...

  10. 【观隅】数据集管理与可视化平台-NABCD分析

    项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任健) 这个作业的要求在哪里 团队项目-初次邂逅,需求分析 项目介绍 观隅 数据集管理与可视化平台(取"观一隅而知全局" ...

随机推荐

  1. 为什么数字化转型离不开 MES 系统?

    确切的说应该是制造业企业的数字化转型离不开MES系统,原因很简单,制造业企业的核心工作是生产制造,做数字化转型就是对生产制造各个环节进行数字化改造,提质增效降成本,而MES系统是制造执行系统,是生产制 ...

  2. 用golang开发系统软件的一些细节

    用golang开发系统软件的一些细节 作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 (本文的pdf版本) ...

  3. CentOS 7.9 安装 rocketmq-4.9.2

    一.CentOS 7.9 安装 rocketmq-4.9.2 地址: https://rocketmq.apache.org https://github.com/apache/rocketmq ht ...

  4. Springboot集成阿里云短信

    目录 1 前言 2 准备工作 2.1 了解流程 2.2 配置信息 2.3 短信签名和模板 2.3.1 签名 2.3.2 模板 2.3.3 存入数据库 3 SDK 4 集成Springboot 4.1 ...

  5. Azure DevOps Pipelines部署.Net Core 应用到Kubernetes

    一.    先决条件 1.Azure Repos Git/Git和项目上传 把本地的Net Core项目上传至Azure Repos Git/Git 2.Docker Registry Service ...

  6. 14.MongoDB系列之配置分片

    1. 启动服务器 1.1 启动配置服务器 配置服务器是集群的大脑,保存着关于每个服务器包含哪些数据的所有元数据,因此,必须首先创建配置服务器. 由于资源限制,在同一机器上启动三个进程 # mkdir ...

  7. 银行ATM存取款系统(C语言实现)

    这里使用的运行工具是DEV C++.老铁们一定要看仔细了.是DEV C++ 仅供借鉴:这个是大一时期写的.大四的时候整理了一下(本人C语言学的也不太好).肯定很多不足和存在漏洞的地方.仅供借鉴.仅供借 ...

  8. 洛P8109题解

    摘自本人洛谷博客,原文章地址:https://www.luogu.com.cn/blog/cjtb666anran/solution-p8109 本题原题目摘录: 本场比赛共有 \(n\) 道题,Ci ...

  9. 四、Django中使用celery

    项目跟目录创建celery包,目录结构如下: mycelery/ ├── config.py ├── __init__.py ├── main.py └── sms/ ├── __init__.py ...

  10. Sublime Text - Linux Package Manager Repositories

    Linux Package Manager Repositories http://www.sublimetext.com/docs/linux_repositories.html Sublime T ...