简介

  • 在现代办公环境中,Word文档和HTML页面都是常见的信息表达方式。有时,我们需要将Word文档转换为HTML格式,以便在网页上展示或进行进一步的处理。本文将介绍如何使用Apache POI库和Jsoup库来实现Word文档到HTML的转换,并处理文档中的图片资源。

  • 环境准备

  • Java开发环境

  • Apache POI库

  • Jsoup库

  • Hutool工具库(用于简化文件和字符串操作)

1. 步骤1:创建项目和依赖

  • 首先,我们需要创建一个Java项目,并添加Apache POI和Jsoup库的依赖。可以通过Maven或Gradle来管理这些依赖。
  <poi.version>4.1.2</poi.version>
<!--注意版本保持一致 poi poi-ooxml poi-scratchpad-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<!-- 操作doc ppt xls -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>${poi.version}</version>
</dependency>
<!-- 操作docx pptx xlsx --> <!--word S-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version>
</dependency> <dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.poi.xwpf.converter.xhtml</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.converter.docx.xwpf</artifactId>
<version>2.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>

步骤2:读取Word文档

使用Apache POI库读取Word文档。对于.docx文件,使用XWPFDocument类;对于.doc文件,使用HWPFDocument类。

docx:

   /**
* 解析docx成html
*
* @param file
* @return
* @throws IOException
*/
public static String Word2007ToHtml(MultipartFile file) throws IOException {
if (file.isEmpty() || file.getSize() <= 0) {
log.error("Sorry File does not Exists!");
return null;
} else {
if (file.getOriginalFilename().endsWith(".docx") || file.getOriginalFilename().endsWith(".DOCX")) {
// 1) 加载word文档生成 XWPFDocument对象
InputStream in = file.getInputStream();
XWPFDocument document = new XWPFDocument(in);
setParagraphs(document);
//解析XHTML配置
XHTMLOptions xhtmlOptions = XHTMLOptions.create();
// 将样式都写为内联样式,而不是写到style标签中 默认false
xhtmlOptions.setFragment(true);
xhtmlOptions.setIgnoreStylesIfUnused(false);
// 也可以使用字符数组流获取解析的内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XHTMLConverter.getInstance().convert(document, baos, xhtmlOptions);
String content = baos.toString();
org.jsoup.nodes.Document doc = setDocXStyle(content); baos.close();
return doc.html();
} else {
log.error("Enter only MS Office 2007+ files");
return null;
}
}
}
doc读取代码
  /**
* 解析doc成html 并保存图片文件到本地
*
* @param file
* @return
* @throws IOException
* @throws ParserConfigurationException
* @throws TransformerException
*/
public static String Word2003ToHtmlAndSaveImage(MultipartFile file) throws IOException { //使用字符数组流获取解析的内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream outStream = new BufferedOutputStream(baos);
try {
//将上传的文件传入Document转换
HWPFDocument wordDocument = new HWPFDocument(file.getInputStream());
//处理标题
Range range = wordDocument.getRange();
HashSet<String> hashSet = new HashSet<>();
for (int i = 0; i < range.numParagraphs(); i++) {
Paragraph paragraph = range.getParagraph(i);
int lvl = paragraph.getLvl();
if (StrUtil.isNotEmpty(paragraph.text().trim())) {
//标题
if (lvl == 1 || lvl == 0 || lvl == 2 || lvl == 4) {
String newContent = HEADLINE_DJ_ + RandomUtil.randomNumbers(8) + "_";
paragraph.insertBefore(newContent);
// paragraph.replaceText(paragraph.text(), newContent+paragraph.text() );
hashSet.add(newContent);
}
}
} Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(document);
//将读取到的图片上传并添加链接地址
wordToHtmlConverter.setPicturesManager(new PicturesManager() {
@Override
public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) {
return getImgUrl(suggestedName, content);
}
}); // word文档转Html文档
wordToHtmlConverter.processDocument(wordDocument);
Document htmlDocument = wordToHtmlConverter.getDocument();
DOMSource domSource = new DOMSource(htmlDocument);
StreamResult streamResult = new StreamResult(outStream);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer serializer = factory.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty(OutputKeys.METHOD, "html");
serializer.transform(domSource, streamResult);
String content = baos.toString();
// 使用Jsoup解析HTML内容
org.jsoup.nodes.Document doc = Jsoup.parse(content);
// 查找并修改目标段落
hashSet.forEach(text -> {
text = getReplaceAllNR(text); Elements elements = doc.select("p");
String finalText = text;
elements.forEach(el -> {
if (el.text().contains(finalText)) {
Element h2Element = new Element("h2");
h2Element.text(el.text().replaceAll(finalText, ""));
h2Element.attr("style", "font-weight: bold;font-size: 22px;");
el.replaceWith(h2Element);
}
});
// 添加CSS样式
org.jsoup.select.Elements elementsfontSize = doc.select("span");
elementsfontSize.forEach(fs -> fs.attr("style", "font-size: 19px; ")); }); // log.info("docToHtmlText--->{}", content);
return doc.html();
} catch (Exception e) {
log.error("docToHtmlText 异常", e);
throw new MyException("docToHtmlText 异常!", e.getMessage());
} finally {
baos.close();
outStream.close();
} }

步骤3:转换文档内容为HTML

对于.docx文件,使用XWPF库提供的XHTMLConverter类将文档内容转换为HTML。对于.doc文件,使用WordToHtmlConverter类进行转换。

步骤4:处理文档中的图片

在转换过程中,需要特别处理文档中的图片。对于.docx文件,可以通过遍历段落和运行(XWPFRun)来获取图片数据,并使用MinioUtil(或其他存储服务)保存图片并获取图片的URL。对于.doc文件,可以通过PicturesManager接口来处理图片的保存和链接更新。

步骤5:样式调整和优化

使用Jsoup库对生成的HTML内容进行样式调整和优化。例如,可以通过CSS选择器来定位并修改特定的元素样式。

处理html,添加h2标签到富文本,显示目录用。

 // 遍历文档中的段落,标记标题
private static void setParagraphs(XWPFDocument document) {
// 遍历文档中的段落,标记标题
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
boolean isTitle = false;
String style = paragraph.getStyle();
if (StrUtil.isEmpty(style)) {
continue;
}
//paragraph.getStyle() 是获取段落标题等级
if (style.equals("1") || style.equals("2") || style.equals("3") || style.equals("4")) {
Long res = new Date().getTime();
String headline = HEADLINE_DJ_ + RandomUtil.randomNumbers(5) + "_" + res;
paragraph.setStyle(headline);
isTitle = true;
}
for (XWPFRun run : paragraph.getRuns()) {
run.setFontSize(40);
if (isTitle) {
run.setFontSize(60);
run.setBold(true);
}
}
} }

步骤6:完整代码示例

点击查看代码
package com.csot.kms.common.poi;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.csot.kms.common.utill.MinioUtil;
import com.csot.kms.common.valid.MyException;
import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLConverter;
import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLOptions;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.PicturesManager;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.PictureType;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.xwpf.usermodel.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.*; @Slf4j
public class WordToHtmlPoiUtil { public static final String HEADLINE_DJ_ = "HEADLINE_DJ_"; public static String docImport(MultipartFile file) throws Exception {
//返回的html字符串
String html = "";
//word类型是否doc
boolean wordType = false;
//临时图片存放文件夹 图片会保存在此路径(临时保存)(doc类型使用)
String docsTempImages = System.getProperty("java.io.tmpdir") + IdUtil.simpleUUID() + "/";
//判断类型
String suffixName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
if (file.getOriginalFilename().endsWith(".docx") || file.getOriginalFilename().endsWith(".DOCX")) {
html = WordToHtmlPoiUtil.Word2007ToHtml(file);
} else if (file.getOriginalFilename().endsWith(".doc") || file.getOriginalFilename().endsWith(".DOC")) {
wordType = true;
html = WordToHtmlPoiUtil.Word2003ToHtmlAndSaveImage(file);
}
//获取图片名称和本地url,这一步上传图片到本地,并把名字和url处理成map
// String uploadPath = "";//word中的图片上传到哪
Map<String, String> imageMaps = WordToHtmlPoiUtil.getImageMaps(docsTempImages, file);
//如果有图片替换成本地地址
if (!imageMaps.isEmpty()) {
html = replaceImgToLocal(html, imageMaps, wordType);
}
html = getReplaceAllNR(html);
return html;
} /**
* 解析docx成html
*
* @param file
* @return
* @throws IOException
*/
public static String Word2007ToHtml(MultipartFile file) throws IOException {
if (file.isEmpty() || file.getSize() <= 0) {
log.error("Sorry File does not Exists!");
return null;
} else {
if (file.getOriginalFilename().endsWith(".docx") || file.getOriginalFilename().endsWith(".DOCX")) {
// 1) 加载word文档生成 XWPFDocument对象
InputStream in = file.getInputStream();
XWPFDocument document = new XWPFDocument(in);
setParagraphs(document);
//解析XHTML配置
XHTMLOptions xhtmlOptions = XHTMLOptions.create();
// 将样式都写为内联样式,而不是写到style标签中 默认false
xhtmlOptions.setFragment(true);
xhtmlOptions.setIgnoreStylesIfUnused(false);
// 也可以使用字符数组流获取解析的内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XHTMLConverter.getInstance().convert(document, baos, xhtmlOptions);
String content = baos.toString();
org.jsoup.nodes.Document doc = setDocXStyle(content); baos.close();
return doc.html();
} else {
log.error("Enter only MS Office 2007+ files");
return null;
}
}
} private static org.jsoup.nodes.Document setDocXStyle(String content) {
//根据标记替换标题内容
org.jsoup.nodes.Document doc = Jsoup.parse(content);
Elements elements = doc.select("p[class^=HEADLINE_DJ_]");
for (Element element : elements) {
Element h2Element = new Element("h2");
h2Element.attr("style", "font-weight: bold;font-size: 22px;");
h2Element.text(element.text());
element.replaceWith(h2Element);
}
// 添加CSS样式
Elements elementsfontSize = doc.select("span");
elementsfontSize.forEach(fs -> fs.attr("style", "font-size: 19px; "));
return doc;
} // 遍历文档中的段落,标记标题
private static void setParagraphs(XWPFDocument document) {
// 遍历文档中的段落,标记标题
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
boolean isTitle = false;
String style = paragraph.getStyle();
if (StrUtil.isEmpty(style)) {
continue;
}
if (style.equals("1") || style.equals("2") || style.equals("3") || style.equals("4")) {
Long res = new Date().getTime();
String headline = HEADLINE_DJ_ + RandomUtil.randomNumbers(5) + "_" + res;
paragraph.setStyle(headline);
isTitle = true;
}
for (XWPFRun run : paragraph.getRuns()) {
run.setFontSize(40);
if (isTitle) {
run.setFontSize(60);
run.setBold(true);
}
}
} } /**
* 解析doc成html 并保存图片文件到本地
*
* @param file
* @return
* @throws IOException
* @throws ParserConfigurationException
* @throws TransformerException
*/
public static String Word2003ToHtmlAndSaveImage(MultipartFile file) throws IOException { //使用字符数组流获取解析的内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream outStream = new BufferedOutputStream(baos);
try {
//将上传的文件传入Document转换
HWPFDocument wordDocument = new HWPFDocument(file.getInputStream());
//处理标题
Range range = wordDocument.getRange();
HashSet<String> hashSet = new HashSet<>();
for (int i = 0; i < range.numParagraphs(); i++) {
Paragraph paragraph = range.getParagraph(i);
int lvl = paragraph.getLvl();
if (StrUtil.isNotEmpty(paragraph.text().trim())) {
//标题
if (lvl == 1 || lvl == 0 || lvl == 2 || lvl == 4) {
String newContent = HEADLINE_DJ_ + RandomUtil.randomNumbers(8) + "_";
paragraph.insertBefore(newContent);
// paragraph.replaceText(paragraph.text(), newContent+paragraph.text() );
hashSet.add(newContent);
}
}
} Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(document);
//将读取到的图片上传并添加链接地址
wordToHtmlConverter.setPicturesManager(new PicturesManager() {
@Override
public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) {
return getImgUrl(suggestedName, content);
}
}); // word文档转Html文档
wordToHtmlConverter.processDocument(wordDocument);
Document htmlDocument = wordToHtmlConverter.getDocument();
DOMSource domSource = new DOMSource(htmlDocument);
StreamResult streamResult = new StreamResult(outStream);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer serializer = factory.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty(OutputKeys.METHOD, "html");
serializer.transform(domSource, streamResult);
String content = baos.toString();
// 使用Jsoup解析HTML内容
org.jsoup.nodes.Document doc = Jsoup.parse(content);
// 查找并修改目标段落
hashSet.forEach(text -> {
text = getReplaceAllNR(text); Elements elements = doc.select("p");
String finalText = text;
elements.forEach(el -> {
if (el.text().contains(finalText)) {
Element h2Element = new Element("h2");
h2Element.text(el.text().replaceAll(finalText, ""));
h2Element.attr("style", "font-weight: bold;font-size: 22px;");
el.replaceWith(h2Element);
}
});
// 添加CSS样式
org.jsoup.select.Elements elementsfontSize = doc.select("span");
elementsfontSize.forEach(fs -> fs.attr("style", "font-size: 19px; ")); }); // log.info("docToHtmlText--->{}", content);
return doc.html();
} catch (Exception e) {
log.error("docToHtmlText 异常", e);
throw new MyException("docToHtmlText 异常!", e.getMessage());
} finally {
baos.close();
outStream.close();
} } private static String getReplaceAllNR(String text) {
text = text.replaceAll("\r\n", "")
.replaceAll("\r", "")
.replaceAll("\n", "");
return text;
} /**
* 获取word中的图片名称和本地url(doc或docx)
* 返回map<图片名称, 存储的图片url地址>
*
* @param
* @param docsTempImages 本地临时图片存放地址(这个工具类Word2003ToHtmlAndSaveImage的方法存到了系统临时文件夹里)
* @param file
* @return
* @throws IOException
*/
public static Map<String, String> getImageMaps(String docsTempImages, MultipartFile file) throws Exception {
//返回map
HashMap<String, String> map = new HashMap<>();
if (file.getOriginalFilename().endsWith(".docx") || file.getOriginalFilename().endsWith(".DOCX")) {
//获取存在word里的图片文件
InputStream in = file.getInputStream();
XWPFDocument document = new XWPFDocument(in);
List<XWPFParagraph> paragraphs = document.getParagraphs();
if (CollUtil.isNotEmpty(paragraphs)) {
paragraphs.forEach(p -> {
List<XWPFRun> runs = p.getRuns();
if (CollUtil.isNotEmpty(runs)) {
runs.forEach(r -> {
List<XWPFPicture> pictures = r.getEmbeddedPictures();
if (CollUtil.isNotEmpty(pictures)) {
pictures.forEach(c -> {
//这里找到word中的图片的名字和数据
XWPFPictureData pictureData = c.getPictureData();
String fileName = pictureData.getFileName();
byte[] data = pictureData.getData();
String localUrl = getImgUrl(fileName, data);
map.put(pictureData.getFileName(), localUrl);
});
}
});
}
});
}
} else if (file.getOriginalFilename().endsWith(".doc") || file.getOriginalFilename().endsWith(".DOC")) {
try {
File dir = new File(docsTempImages);
//如果目录不为空遍历存储到项目中
if (!FileUtil.isEmpty(dir)) {
Arrays.asList(FileUtil.ls(docsTempImages)).forEach(f -> {
String name = f.getName();
BufferedInputStream inputStream = FileUtil.getInputStream(f);
String localUrl = getOssImgUrl(name, inputStream);
map.put(name, localUrl);
});
} } finally {
//删除临时文件夹
FileUtil.del(docsTempImages);
}
}
return map;
} private static String getOssImgUrl(String name, BufferedInputStream inputStream) {
Long res = new Date().getTime();
//设置文件存储路径,可以存放在你想要指定的路径里面
// 新文件名
String newFileName = res + name.substring(name.lastIndexOf(".")); String localUrl = null;
try {
localUrl = MinioUtil.upload(inputStream, newFileName);
} catch (Exception e) {
e.printStackTrace();
}
return localUrl;
} private static String getImgUrl(String fileName, byte[] data) {
if (data.length == 0) {
return "";
}
//保存到本地获取url
Long res = new Date().getTime();
//设置文件存储路径,可以存放在你想要指定的路径里面
// 新文件名
String newFileName = res + fileName.substring(fileName.lastIndexOf("."));
InputStream inputStream = new ByteArrayInputStream(data);
String localUrl = null;
try {
localUrl = MinioUtil.upload(inputStream, newFileName);
} catch (Exception e) {
e.printStackTrace();
}
return localUrl;
} /**
* 替换html图片的路径
*
* @param html
* @param imageMaps
* @throws
*/
public static String replaceImgToLocal(String html, Map<String, String> imageMaps, boolean wordType) {
String returnHtml = "";
//获取当前服务器ip和端口用于图片路径
org.jsoup.nodes.Document doc = Jsoup.parse(html);
// 获取 带有src属性的img元素
Elements imgTags = doc.select("img[src]");
//替换图片
for (org.jsoup.nodes.Element element : imgTags) {
String imageName = StrUtil.subAfter(element.attr("src"), "/", true);
//根据名字获取map中的url,并覆盖之前存的word中的路径
element.attr("src", imageMaps.get(imageName));
}
returnHtml = doc.toString();
//doc格式样式在外部,所以要把style从外部移到内部
if (wordType) {
returnHtml = JsoupUtils.changeHtmlCssLineStyle(doc.toString());
}
return returnHtml;
} }

使用Apache POI和Jsoup将Word文档转换为HTML的更多相关文章

  1. Java中用Apache POI生成excel和word文档

    概述: 近期在做项目的过程中遇到了excel的数据导出和word的图文表报告的导出功能.最后决定用Apache POI来完毕该项功能.本文就项目实现过程中的一些思路与代码与大家共享.同一时候.也作为自 ...

  2. 使用poi根据模版生成word文档,支持插入数据和图片

    一.制作word模版,${xxxx}是一会要替换的内容,最下面的表格是要插入数据,根据是否以$开头来判断是需要替换还是插入数据, 注意如果是需要插入数据,制作的表格模版需要一行空行,也只能有一行空行, ...

  3. poi根据模板导出word文档

    POI结构与常用类 Apache POI是Apache软件基金会的开源项目,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. .NET的开发人员则可以利用NPOI ...

  4. 利用POI操作不同版本号word文档中的图片以及创建word文档

    我们都知道要想利用java对office操作最经常使用的技术就应该是POI了,在这里本人就不多说到底POI是什么和怎么用了. 先说本人遇到的问题,不同于利用POI去向word文档以及excel文档去写 ...

  5. 使用Java POI来选择提取Word文档中的表格信息

    通过使用Java POI来提取Word(1992)文档中的表格信息,其中POI支持不同的ms文档类型,在具体操作中需要注意.本文主要是通过POI来提取微软2003文档中的表格信息,具体code如下(事 ...

  6. 使用Aspose.Words将Word文档转换为Tiff格式图片文件

    用Aspose组件的优点是操作Word文档不需要安装Office就可以实现. 首先需要引用Aspose.Words.dll,链接地址:链接:https://pan.baidu.com/s/1rJvjp ...

  7. Java 使用 jacob 将 word 文档转换为 pdf 文件

    网上查询了许许多多的博客,说利用 poi.iText.Jsoup.jdoctopdf.使用 jodconverter 来调用 openOffice 的服务来转换等等,我尝试了很多种,但要么显示不完全, ...

  8. 使用VBA将批量的WORD文档转换为PDF

    Sub BatchConvertToPDF() Dim destFolderPath As String destFolderPath = GetFolderPath If destFolderPat ...

  9. DEV word文档转换为pdf文件

    引用aspose.net控件2.0. docement doc=new document(文件路径和名称); doc.save(输出路径\file.pdf);

  10. Java将数据写入word文档(.doc)

    Java可用org.apache.poi包来操作word文档.org.apache.poi包可于官网上下载,解压后各jar作用如下图所示: 可根据需求导入对应的jar. 一.HWPFDocument类 ...

随机推荐

  1. macOS搭建SonarQube

    目录 前言 准备环境 下载安装包 解压路径:/usr/local 创建数据库 修改配置文件 配置环境变量 启动SonarQube 扫描项目 项目报告介绍 总结 前言 初到新公司,接手8-10个java ...

  2. 【Azure Developer】使用 Microsoft Graph API查看用户状态和登录记录

    问题描述 通过Microsoft Graph的API如何来查看用户信息和登录记录呢? 问题解答 第一步:需要一个授权Token 比如一个拥有查看用户权限的Azure账号,通过Azure CLI 命令获 ...

  3. 探究C# dynamic动态类型本质

    本周在做接口动态传参的时候思考了个问题:如何把一个json字符串,转成C#动态类? 比如由 { 'userId': 100, 'id': 1, 'title': 'hello world', 'com ...

  4. 序列图 时序图 PlantUML vscode drawio 制作

    序列图 时序图 PlantUML vscode drawio 制作 需求 最近发现 序列图 很多文档都用到,而且很好用.经过研究用vscode,idea都可以编写.这里用vscode编写比较简单. d ...

  5. vuecli-vite-vue3-init 项目架子 快速开发 webpack打包

    要vite的开发的快速 和 webpack打包 开发的时候 用vite,可以打包一个本地可以直接双击,不用起服务的代码 这个架子的缺点就是 vite和vuecli 两套双配置 正式公司项目 还是vue ...

  6. 让 js 失效 Chrome F12 右上角 settings - Preferences - Debugger - Disable JavaScript

    说的可能比较长,实际上,F12 右上角 - 右小角 还是挺好找的.

  7. Rust GUI库 egui 的简单应用

    目录 简介 简单示例 创建项目 界面设计 切换主题 自定义字体 自定义图标 经典布局 定义导航变量 实现导航界面 实现导航逻辑 实现主框架布局 调试运行 参考资料 简介 egui(发音为"e ...

  8. ble的notification和indication的区别和联系

    Ble服务端传输消息有两个常用手段,notification和indication.那么这两者之间有什么区别呢? Notification 不需要应答,所以服务端发送的消息,它自己并不知道消息是否发送 ...

  9. Rust 标准库 Trait 指南

    部分内容来自 Rust 2021 年期刊 内容目录 引言 Trait 基础 自动 Trait 泛型 Trait 格式化 Trait 操作符 Trait 转换 Trait 错误处理 迭代器 Trait ...

  10. Git进阶命令-revert

    有关Git,之前有写过两篇文章: Git五个常见问题及解决方法 Git进阶命令-reset 一.revert命令使用场景 有一天项目经理跟你说,你开发上线的代码有问题,需要马上撤回. 撤回?你第一反应 ...