java使用Apache POI 操作word文档
项目背景:
当我们对一些word文档(该文档包含很多的标题比如 1.1 ,1.2 , 1.2.1.1, 1.2.2.3)当我们删除其中一项或者几项时,需要手动的对后续的进行补充。该功能主要是对标题进行自动的补充。
具体步骤:
导入依赖:
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.2</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></dependency>
官网网址:(觉得麻烦不可也许)
Apache Poi 官方链接 可以看官方文档,其实更方便的可以直接导入依赖后,下载源代码,直接看源码的注释也许
跑一下代码熟悉一下
首先把下面的代码复制到编译器跑一下,看看是否正常运行,顺便了解基本使用
package codeByZyc;import org.apache.poi.xwpf.usermodel.*;import java.io.FileInputStream;
import java.io.IOException;public class rederWordTest {public static void main(String[] args) throws IOException {FileInputStream file = new FileInputStream("输入你的word文档地址");XWPFDocument document = new XWPFDocument(file);// 获取word中的段落,无法获取表格System.out.println("获取到的段落");for (XWPFParagraph paragraph : document.getParagraphs()) {System.out.println(paragraph.getText());}// 这是只能获取word中的表格System.out.println("获取到的表给内容");for (XWPFTable table : document.getTables()) {for (XWPFTableRow row : table.getRows()) {for (XWPFTableCell cell : row.getTableCells()) {System.out.print(cell.getText() + " \t");}System.out.println();}}document.close();file.close();}}
api说明
通过上面的代码,我们可以知道poi是用过XWPFDocument这个类去获取的word内容。 下面从段落和表格两部分进行代码说明
段落api说明
对于word中的段落他的操作如下:
XWPFDocument(最大的模块).getParagraphs->Paragraph(负责每一个段落).getRuns->Run(这是最小处理的元素)
下面是进行调式的图片,配合图片更好理解:
XWPFDocument:就是最大的那个模块 信息很大
Paragraphs:这是所有的段落集合
Paragraph:存放的就是每一段了 里面的runs 是按照格式进行分割的
Runs run的集合
具体看下面
Run(最基础的元素)
这是最重要的那个元素,他是构成所有段落和表格的最小单位。
一个段落他是如何划分成几个run的?
他是按照每个字的前后 是否同一个格式(字体,加粗否,大小等)必须完全一样才能分到一个run里面。具体分割还得调式看
下图是一些run的切割:
这个就是特殊的符号会被划开
这个更离谱 注意 1.3.1后面的空格没有 ,这个的空格是被划开的。是因为空格的格式和标题不一样
段落代码(直接看结尾的整合代码,写得更详细注释更全面):里面有注释 应该算比较清楚了 有问题可以下面评论
文件路径自己填写一下
package codeByZyc;import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class word {// 匹配数字开头,小数点隔开 空格后接内容static Pattern headerPattern = Pattern.compile("^(\\d+(?:\\.\\d+)*)(\\s+.*)");//用于计算层级static ArrayList<Integer> headerlist= new ArrayList();//用于存放段落开头有单个特殊符号的static ArrayList<String> kaitou =new ArrayList<>();// 匹配中文括号列表项(如 (1))
// static Pattern listItemPattern = Pattern.compile("^((\\d+))(.*)$");public static void main(String[] args) {String path="文件路径";//初始化计算器for (int i = 0; i < 10; i++) {headerlist.add(0);}//初始化开头特殊字符kaitou.add("★");kaitou.add("*");//执行代码updateWord(path);}public static void updateWord(String path){try {// 1. 读取 .docx 文件FileInputStream fis = new FileInputStream(path);XWPFDocument document = new XWPFDocument(fis);//获取word每一个段落元素(不包含表格的)List<XWPFParagraph> paragraphs = document.getParagraphs();// //一个段落一个段落的处理for (int i = 0; i < paragraphs.size(); i++) {wordDuanluo(paragraphs.get(i));}//开始村存回去FileOutputStream out = new FileOutputStream("文件路径代码生成.docx");document.write(out);// 4. 关闭流document.close();fis.close();out.close();} catch (Exception e) {e.printStackTrace();}}//处理段落private static void wordDuanluo(XWPFParagraph paragraph) {//每个段落下面还有更小的元素,叫run 所以处理runList<XWPFRun> runs = paragraph.getRuns();//直接匹配第一个 是那就是标题 不是那就是正文if (runs.size()==1){wordRun(runs.get(0));}else if (runs.size()==2){//只有两个识别开头是不是包含特殊 时走一个通道 不是走二通道//标志是否匹配boolean flagkaitou= false;for (int i = 0; i < kaitou.size(); i++) {if (kaitou.get(i).equals(runs.get(0).text())){flagkaitou=true;break;}}if (flagkaitou==true){//证明开头匹配走一同到wordRun(runs.get(1));}else {//不匹配wordRun(runs.get(0),runs.get(1));}}else if (runs.size()>2){//数量在三个及以上//标志是否匹配boolean flagkaitou= false;for (int i = 0; i < kaitou.size(); i++) {if (kaitou.get(i).equals(runs.get(0).text())){flagkaitou=true;break;}}if (flagkaitou==true){//证明开头匹配wordRun(runs.get(1),runs.get(2));}else {//不匹配wordRun(runs.get(0),runs.get(1));}}}// 处理非常特殊的 标题后面跟的空格字体和标题不一样分开了 进行拼接private static void wordRun(XWPFRun run1, XWPFRun run2) {//run是作为操作word的非常小的元素了,他会把每个段落换分成几个run组成 具体划分规则我也不知道 (我看案列 是按格式进行 格式一样的情况大概率是在一起)//采用正则表达式进行匹配Matcher matcher = headerPattern.matcher(run1.text()+run2.text());if (matcher.find()) {//匹配成功//保存序号后面的文章用于拼接String contex = matcher.group(2);//按照.进行切割String[] originalParts = matcher.group(1).split("\\.");//根据长度判断层级 一个就一级int length = originalParts.length;//文档按照顺序1 1.1 1.1.1//将子层级覆盖掉for (int i = length; i < headerlist.size(); i++) {headerlist.set(i,0);}headerlist.set(length - 1, (headerlist.get(length - 1) + 1));StringBuffer result = new StringBuffer();//拼接正确的序号for (int i = 0; i < length; i++) {result.append(headerlist.get(i));result.append(".");}//多出一个. 进行删除result.deleteCharAt(result.length()-1);//序号放到run1 空格+正文放到run2run1.setText(result.toString(),0);run2.setText(contex,0);}}private static void wordRun(XWPFRun run) {//run是作为操作word的非常小的元素了,他会把每个段落换分成几个run组成 具体划分规则我也不知道 (我看案列 是按格式进行 格式一样的情况大概率是在一起)//采用正则表达式进行匹配Matcher matcher = headerPattern.matcher(run.text());if (matcher.find()) {//匹配成功//保存序号后面的文章用于拼接String contex = matcher.group(2);//按照.进行切割String[] originalParts = matcher.group(1).split("\\.");//根据长度判断层级 一个就一级int length = originalParts.length;//文档按照顺序1 1.1 1.1.1//将子层级覆盖掉for (int i = length; i < headerlist.size(); i++) {headerlist.set(i,0);}headerlist.set(length - 1, (headerlist.get(length - 1) + 1));StringBuffer result = new StringBuffer();//拼接正确的序号for (int i = 0; i < length; i++) {result.append(headerlist.get(i));result.append(".");}//多出一个. 进行删除result.deleteCharAt(result.length()-1);result.append(contex);//将内容替换到runrun.setText(result.toString(),0);}}}
表格api说明 基本上和段落一样 有一点点不一样
XWPFDocument(最大的模块).getTables->XWPFTable(负责每一个表格).getRows->Row(代表一行).getTableCells->XWPFTableCell(每一格子)[由于cell无法更改具体看下图] 需要深入到 run
注意,我原来以为在cell就可以更改他的文本
但是看源码可以知道 他是在尾部追加并不是覆盖,所以还是只能追到run去覆盖。
表格代码:(直接看结尾的整合代码,写得更详细注释更全面)
import org.apache.poi.xwpf.usermodel.*;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class TestWord {// 匹配表格的 结尾开头是数字 空格几个都行static Pattern tablePattern = Pattern.compile("^(\\d+)(\\s*)$");static Integer tableCount=0;//用于存放段落开头有单个特殊符号的static ArrayList<String> kaitou =new ArrayList<>();public static void main(String[] args) {String path="测试table.docx";//初始化开头特殊字符kaitou.add("★");kaitou.add("*");readWord(path);}public static void readWord(String filePath){try {// 1. 读取 .docx 文件FileInputStream fis = new FileInputStream(filePath);XWPFDocument document = new XWPFDocument(fis);//直接一层一层找一下找到 run 试过在cell进行修改 但是cell的修改是 原来的基础上进行了新的增加 不能进行替换 直接找到run进行替换for (XWPFTable table : document.getTables()) {//一个table 清除一次计数器tableCount=0;for (XWPFTableRow row : table.getRows()) {for (XWPFTableCell cell : row.getTableCells()) {for (XWPFParagraph paragraph : cell.getParagraphs()) {List<XWPFRun> runs = paragraph.getRuns();//直接匹配第一行if (runs.size()==1){tableup(runs.get(0));}else if (runs.size()>1){//这边就是 考虑到前面有个特殊符号的情况 就需要判断了XWPFRun run1 = runs.get(0);//第一个不是特殊那就直接走第一通道boolean flag=false;for (int i = 0; i < kaitou.size(); i++) {if (kaitou.get(i).equals(run1.text())){flag=true;break;}}if (flag){tableup(runs.get(1));}else {tableup(run1);}}}}}}System.out.println("测试完成");FileOutputStream out = new FileOutputStream("生成的table.docx");document.write(out);// 4. 关闭流document.close();fis.close();out.close();} catch (Exception e) {e.printStackTrace();}}public static void tableup(XWPFRun run){Matcher matcher = tablePattern.matcher(run.text());if (matcher.find()){//匹配成功 开始更换层级String content = matcher.group(2);String originalParts = matcher.group(1);//开始覆盖掉序号 并拼接后面的内容tableCount++;StringBuffer result=new StringBuffer();result.append(tableCount+content);//写入run.setText(result.toString(),0);}}
}
总结
整合代码:
package codeByZyc;import org.apache.poi.xwpf.usermodel.*;import java.io.FileInputStream;import java.io.FileOutputStream;import java.util.ArrayList;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;public class Upword {// 匹配数字开头,小数点隔开 空格后接内容static Pattern headerPattern = Pattern.compile("^(\\D?)(\\d+(?:\\.\\d+)*)(\\s+)");//用于段落计算层级static ArrayList<Integer> headerlist= new ArrayList();//用于存放段落开头有单个特殊符号的// 匹配表格的 结尾开头是数字 空格几个都行static Pattern tablePattern = Pattern.compile("^(\\D?)(\\d+)(\\s*)$");//匹配表格的层级static Integer tableCount=0;// 匹配中文括号列表项(如 (1))
// static Pattern listItemPattern = Pattern.compile("^((\\d+))(.*)$");public static void main(String[] args) {String path="测试专用删除部分标题.docx";//初始化段落层级计算器for (int i = 0; i < 10; i++) {headerlist.add(0);}//执行代码updateWord(path);}public static void updateWord(String path){try {// 1. 读取 .docx 文件FileInputStream fis = new FileInputStream(path);XWPFDocument document = new XWPFDocument(fis);//获取word每一个段落元素(不包含表格的)List<XWPFParagraph> paragraphs = document.getParagraphs();// //一个段落一个段落的处理for (int i = 0; i < paragraphs.size(); i++) {wordDuanluo(paragraphs.get(i));}//获取word的表格
// 直接一层一层找一下找到 run 试过在cell进行修改 但是cell的修改是 原来的基础上进行了新的增加 不能进行替换 直接找到run进行替换for (XWPFTable table : document.getTables()) {wordtable(table);}//开始村存回去FileOutputStream out = new FileOutputStream("代码生成.docx");document.write(out);// 4. 关闭流document.close();fis.close();out.close();} catch (Exception e) {e.printStackTrace();}}//处理表格private static void wordtable(XWPFTable table){//一个table 清除一次计数器tableCount=0;for (XWPFTableRow row : table.getRows()) {for (XWPFTableCell cell : row.getTableCells()) {for (XWPFParagraph paragraph : cell.getParagraphs()) {List<XWPFRun> runs = paragraph.getRuns();//直接匹配第一行if (runs.size()==1){wordTableRun(runs.get(0));}else if (runs.size()==2){wordTableRun(runs.get(0),runs.get(1));}}}}}//处理段落private static void wordDuanluo(XWPFParagraph paragraph) {//每个段落下面还有更小的元素,叫run 所以处理runList<XWPFRun> runs = paragraph.getRuns();/* 这里需要注意一下因为我的测试文档的需求标题是这样的 *1.2.1 背景展望 像这个 要是格式不一样会被划分成 三个部分 * 1.2.1 还有一个空格 。 但是要是格式一样 就直接化成一个了主要是我的测试文档是有些一样 有些不一样所以需要考虑的比较多。*/if (runs.size()==1){//针对只划分一个的 那没得说 直接走第一个wordRun(runs.get(0));}else if (runs.size()==2){//这就是两个 那可能是两种情况: *1.2.1 空格 或者 * 1.2.1空格 就是两种了wordRun(runs.get(0),runs.get(1));}else if (runs.size()>2){//数量在三个及以上//这种 就是我上面说的 三个格式都不一样wordRun(runs.get(0),runs.get(1),runs.get(2));}}private static void wordRun(XWPFRun run) {//run是作为操作word的非常小的元素了,他会把每个段落换分成几个run组成 具体划分规则我也不知道 (我看案列 是按格式进行 格式一样的情况大概率是在一起)//采用正则表达式进行匹配Matcher matcher = headerPattern.matcher(run.text());if (matcher.find()) {//匹配成功String oldxuaho=matcher.group(2);//按照.进行切割String[] originalParts =oldxuaho.split("\\.");//根据长度判断层级 一个就一级int length = originalParts.length;//文档按照顺序1 1.1 1.1.1//将子层级覆盖掉for (int i = length; i < headerlist.size(); i++) {headerlist.set(i,0);}headerlist.set(length - 1, (headerlist.get(length - 1) + 1));StringBuffer result = new StringBuffer();//拼接正确的序号//把序号前面的放进来result.append(matcher.group(1));for (int i = 0; i < length; i++) {result.append(headerlist.get(i));result.append(".");}//多出一个. 进行删除result.deleteCharAt(result.length()-1);//替换if(run.text().contains(oldxuaho)){//进行替换String s = run.text();s.replace(oldxuaho,result.toString());run.setText(s,0);}}}// 处理非常特殊的 标题后面跟的空格字体和标题不一样分开了 进行拼接private static void wordRun(XWPFRun run1, XWPFRun run2) {//run是作为操作word的非常小的元素了,他会把每个段落换分成几个run组成 具体划分规则我也不知道 (我看案列 是按格式进行 格式一样的情况大概率是在一起)//采用正则表达式进行匹配Matcher matcher = headerPattern.matcher(run1.text()+run2.text());if (matcher.find()) {//匹配成功String oldxuaho=matcher.group(2);//按照.进行切割String[] originalParts =oldxuaho.split("\\.");//根据长度判断层级 一个就一级int length = originalParts.length;//文档按照顺序1 1.1 1.1.1//将子层级覆盖掉for (int i = length; i < headerlist.size(); i++) {headerlist.set(i,0);}headerlist.set(length - 1, (headerlist.get(length - 1) + 1));StringBuffer result = new StringBuffer();//把前面的放进来result.append(matcher.group(1));//拼接正确的序号for (int i = 0; i < length; i++) {result.append(headerlist.get(i));result.append(".");}//多出一个. 进行删除result.deleteCharAt(result.length()-1);//查找替换 具体思路看一看下面的if(run1.text().contains(oldxuaho)){//进行替换String s = run1.text();s.replace(oldxuaho,result.toString());run1.setText(s,0);}else if (run2.text().contains(oldxuaho)){String s = run2.text();s.replace(oldxuaho,result.toString());run2.setText(s,0);}}}private static void wordRun(XWPFRun run1, XWPFRun run2,XWPFRun run3) {//run是作为操作word的非常小的元素了,他会把每个段落换分成几个run组成 具体划分规则我也不知道 (我看案列 是按格式进行 格式一样的情况大概率是在一起)//采用正则表达式进行匹配Matcher matcher = headerPattern.matcher(run1.text()+run2.text()+run3.text());if (matcher.find()) {//匹配成功String oldxuaho=matcher.group(2);//按照.进行切割String[] originalParts = oldxuaho.split("\\.");//根据长度判断层级 一个就一级int length = originalParts.length;//文档按照顺序1 1.1 1.1.1//将子层级覆盖掉for (int i = length; i < headerlist.size(); i++) {headerlist.set(i,0);}headerlist.set(length - 1, (headerlist.get(length - 1) + 1));StringBuffer result = new StringBuffer();//直接将他们拼起来result.append(matcher.group(1));//拼接正确的序号for (int i = 0; i < length; i++) {result.append(headerlist.get(i));result.append(".");}//多出一个. 进行删除result.deleteCharAt(result.length()-1);/*下面就需要考虑 run1 2 3 如何划分了因为我的matcher.group 把他们三个合并的 拆分成了 三部分 (数字标题前面的部分) (数字标题) 空格内容(内容可能有可能无)* 情况1: 最开始说到的 * 1.2.1 空格内容(内容可能有可能无)* 情况2: 也有可能是: *1.2.1 空格内容(内容可能有可能无) 内容情况3: 也有可能是: * 1.2.1空格内容(内容可能有可能无) 内容情况4: *1.2.1空格内容(内容可能有可能无) 内容 内容解决思路: group(2)匹配的序号 只需要 挨个便利 看看 哪个run包含 进行替换就行其他的保持不变。* *///查找if(run1.text().contains(oldxuaho)){//进行替换String s = run1.text();s.replace(oldxuaho,result.toString());run1.setText(s,0);}else if (run2.text().contains(oldxuaho)){String s = run2.text();s.replace(oldxuaho,result.toString());run2.setText(s,0);}else {String s = run3.text();s.replace(oldxuaho,result.toString());run3.setText(s,0);}}}//处理表格的单元格private static void wordTableRun(XWPFRun run){Matcher matcher = tablePattern.matcher(run.text());if (matcher.find()){//匹配成功 开始更换层级String oldxuhao = matcher.group(2);//开始覆盖掉序号 并拼接后面的内容tableCount++;String s = run.text();s.replace(oldxuhao,tableCount.toString());//写入run.setText(s,0);}}private static void wordTableRun(XWPFRun run1,XWPFRun run2){Matcher matcher = tablePattern.matcher(run1.text()+run2.text());if (matcher.find()){String oldxuhao=matcher.group(2);//开始覆盖掉序号 并拼接后面的内容tableCount++;String s;if (run1.text().contains(oldxuhao)){s=run1.text();s.replace(oldxuhao,tableCount.toString());run1.setText(s,0);}else if (run2.text().contains(oldxuhao)){s=run2.text();s.replace(oldxuhao,tableCount.toString());run2.setText(s,0);}}}}
难点:
我感觉最大的难点就是对Api的熟悉,需要看看源码或者文档。以及利用正则表达式对标题进行匹配
相关文章:
java使用Apache POI 操作word文档
项目背景: 当我们对一些word文档(该文档包含很多的标题比如 1.1 ,1.2 , 1.2.1.1, 1.2.2.3)当我们删除其中一项或者几项时,需要手动的对后续的进行补充。该功能主要是对标题进行自动的补充。 具…...
【Linux网络编程】网络基础
目录 1、OSI分层思想2、数据的封装3、ip地址ipv4的ip地址分类:为什么这样划分?举例 4、端口号5、tcp三次握手为什么需要三次握手?tcp连接的标识为什么 IP 地址不能单独标识一条连接? 6、tcp四次挥手为什么需要四次挥手为什么需要三…...
国内首家,百度智能云千帆AppBuilder全面兼容MCP协议
百度智能云千帆 AppBuilder 已兼容 MCP 协议!作为国内首家支持 MCP 协议的大模型应用开发平台(Claude、LangGraph、Cursor、Cline、N8N等海外平台已支持),千帆 AppBuilder 完成兼容后,用户可通过千帆 AppBuilder 轻松调…...
eclipse [jvm memory monitor] SHOW_MEMORY_MONITOR=true
eclipse虚拟机内存监控设置SHOW_MEMORY_MONITORtrue D:\eclipse-jee-oxygen-2-win32-x86_64\workspace\.metadata\.plugins\org.eclipse.core.runtime\.settings org.eclipse.ui.prefs (文件比较多,别找错了) SHOW_MEMORY_MONITORtrue 重启 -xms 1024…...
k8s中的组件
1.namespace Namespace 用于将集群资源划分为不同的逻辑组,方便管理和隔离 kubectl get namespace 查看所有逻辑组 kubectl describe namespace <namespace-name> 查看某个逻辑组信息详情 kubectl create namespace ... 创建逻辑组 kubectl delete names…...
单目3d detection算法记录
1、centernet object as points 这篇文章的核心单目3d检测主要是利用中心点直接回归出3d模型的所有属性,head共享整个backbone,其中3d属性包括:2d目标中心点、2dw和h、2d offsets、3doffsets、3d dimmession、rot还有depth。 其中对应的dep…...
vue3二次封装tooltip实现el-table中的show-overflow-tooltip效果
开发过程中遇到需要根据后端返回的数据长度来判断是否需要使用el-tooltip的情况,想到el-table里面就有这种交互效果,如果不论文字是否超出容器长度都展示tooltip的话,交互效果难免会差很多,所以二次封装了这个组件: 给…...
STM32八股【1】-----启动流程和startup文件理解
启动流程 知识点 MCU 上电复位。MSP从向量表第0个地址读取一个32位(2字节)的值并保存,该值为栈顶地址。PC计数器从第1个地址读取一个两字节的值并保存,该值为程序入口,一般是Reset_Handler。想了解FLASH地址映射可以…...
Go语言中package的使用规则《二》
在 Go 语言中,包(Package) 是代码组织和复用的核心单元。以下是其定义、引用规则及使用习惯的详细说明: 一、包的定义规则 目录与包名 一个包对应一个目录(文件夹),目录名通常与包名一致。 包名…...
初级:控制流程面试题精讲
一、引言 在Java开发中,控制流程语句是构建程序逻辑的基础。面试官通过相关问题考察候选人对if-else、switch、循环等语句的理解和运用能力,以及在复杂业务场景下合理选择控制流程语句的水平。本文将深入剖析常见的控制流程面试题,结合实际开…...
HTTP 失败重试(重发)方案
在 Qt 网络开发中,使用 QNetworkAccessManager 进行 HTTP 请求时,可能会遇到网络超时、服务器错误等情况。为了提高请求的可靠性,可以实现 HTTP 失败重试(重发) 机制。下面介绍几种常见的 失败重发方案: 单…...
TNNLS 2024 | 基于残差超密集网络的高光谱图像空间光谱融合方法
A Spatio-Spectral Fusion Method for Hyperspectral Images Using Residual Hyper-Dense Network IEEE Transactions on Neural Networks and Learning Systems 2024 这篇文章的研究背景是针对高光谱图像(HS)与全色图像(PAN)的…...
深入探究 JVM 堆的垃圾回收机制(二)— 回收
GC Roots 枚举需要遍历整个应用程序的上下文,而在进行可达性分析或者垃圾回收时,如果我们还是进行全堆扫描及收集,那么会非常耗时。JVM 将堆分为新生代及老生代,它们的回收频率及算法不一样。 1 回收算法 在进行可达性分析时&am…...
【ELK】节省存储 之 压缩存储方式调整
目录 集群版本: 7.17.6 解释几个概念: 段(Segment) 合并(Merge) 索引设置: 压缩方式(index.codec): 测试设置前提条件 对比 在创建的时候指定压缩类型(index.codec) 对比 在…...
MATLAB 控制系统设计与仿真 - 26
状态空间控制系统概述 状态空间描述 现代控制理论是建立在状态空间基础上的控制系统分析和设计理论,它用状态变量来刻画系统的内部特征,用‘一节微分方程组’来描述系统的动态特性。系统的状态空间模型描述了系统输入/输出与内部状态之间的关系&#x…...
下载与快速上手 NVM:Node.js 版本管理工具
一、准备工作:卸载旧版 Node.js 重要提示:在安装 NVM 前,请先彻底删除已安装的 Node.js,避免路径冲突: 检查安装路径 bash where node常见路径: C:\Program Files\nodejs\C:\Users\用户名\AppData\Local\n…...
SQL Server Management Studio(SSMS)安装教程
目录 一、SSMS的下载 二、SSMS 的安装 三、连接服务器 四、卸载 SSMS 一、SSMS的下载 1.进入 SQL Server Management Studio 官方下载页面:SQL Server Management Studio点击进入下载页面 2.点击链接开始下载,浏览器右上角会显示下载进度;…...
运维知识:Linux下Vim编辑器使用详解
运维知识:Linux下Vim编辑器使用详解 引言 在Linux的世界里,Vim不仅仅是一个文本编辑器,更是程序员的「瑞士军刀」。从1991年Bram Moolenaar发布第一个版本至今,Vim以其高效的模态编辑、高度可定制性和跨平台兼容性,成…...
复习HCIA
一、网络基础概念 1. OSI七层模型与TCP/IP四层模型 OSI七层模型详解: 物理层(Physical Layer): 功能:传输原始比特流(0/1),定义电气、机械特性(如电压、线缆类型&#…...
在QT中进行控件提升操作
目录 一、概述 二、功能需求 三、提升操作 1)拖入标准控件 2)自定义类 3)提升控件 一、概述 QT中提供的标准控件能够满足我们大多数情况下的功能需求,但是在一些特殊应用场合,我们可能需要对控件的功能进行扩展&am…...
Linux下JDK1.8安装配置
目录 1.下载完上传到Linux系统中 2.解压JDK压缩包 3.配置JDK环境变量 4.设置环境变量生效 5.查看环境变量是否配置成功 官网下载地址:Java Downloads | Oracle 1.下载完上传到Linux系统中 2.解压JDK压缩包 tar -zxvf jdk-8u151-linux-x64.tar.gz -C /usr/local (解压…...
JVM 知识点梳理
JDK 、JRE、JVM JDK( Java Development Kit ) Java开发工具包 JRE 开发命令工具(运行java.exe、编译javac.exe、javaw.exe) JRE( Java Runtime Environment )Java运行环境 JVM Java核心类库(l…...
求职招聘网站源码,找工作招工系统,支持H5和各种小程序
招聘找活招工平台系统源码 招聘求职找工作软件 发布信息积分充值招聘系统,里面带纤细教程 功能介绍: 招工小程序主要针对工地招工工人找工作,工地可以发布招工信息,工人可以发布找活信息,招工信息可以置顶,置顶需要积分,积分可以通过签到、分享邀请好友、充值获取,后…...
拓展 Coco AI 功能 - 智能检索 Hexo 博客
在之前的文章中,我们成功让 Coco AI 检索 Hugo 博客,这对于博客作者来说是一大福音。然而,从 Hexo 迁移到 Hugo 的成本不容小觑,毕竟大多数开发者对 Node.js 更熟悉,而 Golang 相对陌生。那么,既然 Coco AI…...
深入解析 Java Stream API:从 List 到 Map 的优雅转换!!!
🚀 深入解析 Java Stream API:从 List 到 Map 的优雅转换 🔧 大家好!👋 今天我们来聊聊 Java 8 中一个非常常见的操作:使用 Stream API 将 List 转换为 Map。🎉 具体来说,我们将深入…...
【一起学Rust | Tauri2.0框架】基于 Rust 与 Tauri 2.0 框架实现全局状态管理
前言 在现代应用程序开发中,状态管理是构建复杂且可维护应用的关键。随着应用程序规模的增长,组件之间共享和同步状态变得越来越具有挑战性。如果处理不当,状态管理可能会导致代码混乱、难以调试,并最终影响应用程序的性能和可扩…...
金桔网桥路由版3
上一集我们讲到了二层云交换机,我把在云上搭建的桥接模式的VPN服务器称为二层云交换机。 那么现在我家到办公室的网络结构就变成这样的, 这样的好处就是我的电视盒子通过网线看电视,走的是OpenWrt路由器通过二层云交换机由办公室的OpenWrt路由…...
前沿分享|处理LLM幻觉问题-CoN|笔记链:增强检索增强语言模型的鲁棒性
检索增强语言模型(RALMs)在大型语言模型的能力方面取得了重大进步,特别是在减少事实幻觉方面,这得益于外部知识来源的利用。 然而,检索到的信息的可靠性并不总是有保证。 检索到无关数据可能导致误导性回答ÿ…...
OpenWrt开发第4篇:设置开发板的IP-基于Raspberry Pi 4B开发板
文/指尖动听知识库-谷谷 文章为付费内容,商业行为,禁止私自转载及抄袭,违者必究!!! 文章专栏:Openwrt开发-基于Raspberry Pi 4B开发板 有时候开发过程中经常会使用其他路由器,很多时候固件烧上去之后板子IP基本都是192.168.1.1,这时就需要修改板子的IP,下面介绍一下板…...
浅谈跨平台框架的演变(H5混合开发->RN->Flutter)
引言 这里分为四个阶段: 第一阶段 : 原生开发 第二阶段 : H5混合开发 第三阶段: 跨平台RN 第四阶段: 跨平台Flutter 正文 第一阶段: 原生开发 开发成本比较大 : 需要Android 和ios 开发两…...
Android数据加密方案
Android数据加密方案 前言 在移动应用开发中,数据安全是一个永恒的话题。Android应用中往往需要存储和传输敏感数据,如用户密码、支付信息、个人隐私等。本文将深入介绍Android平台上的数据加密方案,帮助开发者构建安全可靠的数据保护机制。 基础知识 1. 加密算法分类 …...
深入理解traceroute命令及其原理
traceroute 是一个网络诊断工具(Windows上叫tracert),用于显示数据包从本地主机到远程主机经过的路由(跳数)。它可以帮助您了解数据包在网络中的传输路径,以及每跳的延迟情况。这对于网络故障排除、分析网络…...
PostgreSQL_安装
目录 前置: 安装过程: 1 下载软件 2 创建安装文件夹和放置数据的文件夹 3 双击安装 4 连接服务 前置: PostgreSQL 15 windows 10 专业版 安装过程: 1 下载软件 PostgreSQL: Downloads 大小326MB 2 创建安装文件夹和放…...
leetcode684.冗余连接
依旧是并查集问题,这道题目正好给定顶点数目和边的数目相等,只要找到其中的一条边删除将图转化为树就行,而这个多余的边起始就是并查集的添加过程中二者是同一个根(两个顶点早已经联通了),这时直接返回这条…...
Python学习第二十一天
爬虫 概念 网络爬虫(Web Crawler),也称为网络蜘蛛(Web Spider),是一种自动化程序,用于从互联网上抓取数据。爬虫通过模拟浏览器行为,访问目标网站并提取所需的信息,然后…...
matlab近似计算联合密度分布
在 Matlab 中,当A和B是两个序列数据时,可以通过以下步骤来近似求出A大于B的概率分布:数据准备:确保序列A和B具有相同的长度。如果长度不同,需要进行相应的处理(例如截取或插值)。计算A大于B的逻…...
OpenCV图像处理基础2
接着上一篇OpenCV图像处理基础1继续说。 图像阈值处理 1、简单阈值处理 ret, thresholded_image = cv2.threshold(image, thresh, maxval, cv2.THRESH_BINARY)thresh 是阈值,maxval 是最大值。 2、自适应阈值处理 thresholded_image = cv2.adaptiveThreshold(image, maxv…...
Prometheus Exporter系列-Mysql_Exporter一键部署
新项目旧项目都需要给研发配置mysql监控,这里mysql监控对应aws 阿里云 腾讯云 华为云的云mysql产品或开源自建mysql。 exporter安装虽然简单,经常手动操作不免让人心烦,一键完成省去繁琐的常规操作。 配置信息对的情况下测试多次都可以正常安…...
A l密码学(Deepseek)
我:qwertyuiopasdfghjklzxcvbnm deepseek:深度思考中. Okay, lets see. The user input is "qwertyuiopasdfghjklzxcvbnm". At first glance, it looks like a jumbled sequence of letters with some spaces or maybe other characters in …...
「Java-API帮助文档」
「Java-API帮助文档」,链接:https://pan.quark.cn/s/d7ced3b48f33 java.applet提供创建 applet 所必需的类和 applet 用来与其 applet 上下文通信的类。java.awt包含用于创建用户界面和绘制图形图像的所有类。java.awt.color提供用于颜色空间的类。java…...
卷积神经网络 - 梯度和反向传播算法
在卷积网络中,参数为卷积核中权重以及偏置。和全连接前馈网络类似,卷积网络也可以通过误差反向传播算法来进行参数学习。本文我们从数学角度,来学习卷积神经网络梯度的推导和其反向传播算法的原理。 一、梯度:损失函数 L 关于第 …...
ripro 主题激活 问题写入授权Token失败,可能无文件写入权限
ripro 主题激活 问题 写入授权Token失败,可能无文件写入权限 找到主题下面的functions.php文件,给其他写入权限。就好了。...
MySQL 中,查看执行频次、慢查询日志、SHOW PROFILE和 EXPLAIN性能分析和优化
在 MySQL 中,查看执行频次、慢查询日志、SHOW PROFILE 和 EXPLAIN 是性能分析和优化的核心工具。以下是它们的详细用法和高级语法: 一、查看 SQL 执行频次 通过 SHOW STATUS 命令可以查看 SQL 的执行频次,帮助定位高频查询。 1. 查看全局 SQL 执行频次 SHOW GLOBAL STATU…...
Springdoc 全部注解一文解释清楚
文章目录 **1. 核心注解****Tag-Class类上** **2. 方法级别注解****Operation-方法描述****ApiResponse 和 ApiResponses-方法的返回结果** **3. 参数相关注解****Parameter-方法参数****Parameters方法参数(单个)** **4. 实体模型相关注解****Schema-描…...
1.angular介绍
初級使用视频添加链接描述 angular工具 angular.module(‘名’, [依赖模块]) 模块 angular.bind(*) : 修改this指向 angualr.copy() // a angular.copy(a, b) —a完全覆盖了b,c就是a angular.extend(a, b) a里面集成了b属性 angular.isArray angular.isDate angular.isDefin…...
StarRocks vs Doris:深度剖析与选型分析
StarRocks vs Doris:深度剖析与选型分析 在大数据技术蓬勃发展的当下,企业对于高效的数据分析工具的需求日益增长。StarRocks 和 Doris 作为两款优秀的 MPP(大规模并行处理)数据库,在数据仓库和数据分析领域备受关注。…...
Ambari、Bigtop源码编译最新支持情况汇总
以下是目前的版本情况 支持了绝大部分的组件编译及安装 版本组件名称组件版本env 版本v1.0.5Ozone1.4.11.0.5Impala4.4.11.0.5Nightingale7.7.21.0.5Categraf0.4.11.0.5VictoriaMetrics1.109.11.0.5Cloudbeaver24.3.31.0.5Celeborn0.5.31.0.5v1.0.4Doris2.1.71.0.4v1.0.3Phoen…...
【sql靶场】第23、25,25a关过滤绕过保姆级教程
目录 【sql靶场】第23、25-28关过滤绕过保姆级教程 第二十三关 第二十五关 1.爆出数据库 2.爆出表名 3.爆出字段 4.爆出账号密码 【sql靶场】第23、25,25a关过滤绕过保姆级教程 第二十三关 从本关开始又是get传参,并且还有了对某些字符或字段的过…...
coding ability 展开第五幕(二分查找算法)超详细!!!!
. . 文章目录 前言二分查找搜索插入的位置思路 x的平方根思路 山脉数组的峰顶索引思路 寻找旋转排序数组中的最小值思路 总结 前言 本专栏上篇博客已经把滑动指针收尾啦 现在还是想到核心——一段连续的区间,有时候加上哈希表用起来很爽 今天我们来学习新的算法知识…...
存算分离是否真的有必要?从架构之争到 Doris 实战解析
引言:一场关于 “存与算” 的N年辩论 在数据库与大数据领域,“存算一体” 与 “存算分离” 的架构之争从未停歇。有人质疑:“存算分离真的有必要吗?本地盘性能难道不够?” 答案并非非黑即白 —— 技术选型的关键&…...