Java 富文本转word
前言:
本文的目的是将传入的富文本内容(html标签,图片)并且分页导出为word文档。
所使用的为docx4j
一、依赖导入
<!-- 富文本转word --><dependency><groupId>org.docx4j</groupId><artifactId>docx4j</artifactId><version>6.1.2</version><exclusions><exclusion><artifactId>slf4j-log4j12</artifactId><groupId>org.slf4j</groupId></exclusion><exclusion><artifactId>log4j</artifactId><groupId>log4j</groupId></exclusion><exclusion><artifactId>commons-io</artifactId><groupId>commons-io</groupId></exclusion><exclusion><artifactId>commons-compress</artifactId><groupId>org.apache.commons</groupId></exclusion><exclusion><artifactId>guava</artifactId><groupId>com.google.guava</groupId></exclusion><exclusion><artifactId>mbassador</artifactId><groupId>net.engio</groupId></exclusion></exclusions></dependency><dependency><groupId>org.docx4j</groupId><artifactId>docx4j-ImportXHTML</artifactId><version>8.0.0</version></dependency><dependency><groupId>org.docx4j</groupId><artifactId>docx4j-JAXB-ReferenceImpl</artifactId><version>8.1.0</version><exclusions><exclusion><artifactId>docx4j-core</artifactId><groupId>org.docx4j</groupId></exclusion></exclusions></dependency>
二、字体文件
将字体文件上传到子项目resources的static.fonts目录中
三、工具类
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Decoder;import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;/** * 编码工具类 * 实现aes加密、解密 */
public class AESEncryptUtils {public static final String aesKey = "this-is-aescrypt";private AESEncryptUtils(){throw new AssertionError();}/*** 算法 */ private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding"; public static void main(String[] args) throws Exception {System.out.println(AESEncryptUtils.aesEncrypt("html2Pdf", "this-is-aescrypt"));}public static String aesEncryptToString(String content) throws Exception {return aesEncrypt(content, aesKey);}public static String aesDecryptToString(String content) throws Exception {return aesDecrypt(content, aesKey);}/** * 将byte[]转为各种进制的字符串 * @param bytes byte[] * @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制 * @return 转换后的字符串 */ public static String binary(byte[] bytes, int radix){ return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数 } /** * base 64 encode * @param bytes 待编码的byte[] * @return 编码后的base 64 code */ public static String base64Encode(byte[] bytes){ return Base64.encodeBase64String(bytes);} /** * base 64 decode * @param base64Code 待解码的base 64 code * @return 解码后的byte[] * @throws Exception */ public static byte[] base64Decode(String base64Code) throws Exception{ return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);} /*** AES加密 * @param content 待加密的内容 * @param encryptKey 加密密钥 * @return 加密后的byte[] * @throws Exception */ public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128); Cipher cipher = Cipher.getInstance(ALGORITHMSTR); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES")); return cipher.doFinal(content.getBytes("utf-8")); } /*** AES加密为base 64 code * @param content 待加密的内容 * @param encryptKey 加密密钥 * @return 加密后的base 64 code * @throws Exception */ public static String aesEncrypt(String content, String encryptKey) throws Exception { return base64Encode(aesEncryptToBytes(content, encryptKey)); } /** * AES解密 * @param encryptBytes 待解密的byte[] * @param decryptKey 解密密钥 * @return 解密后的String * @throws Exception */ public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128); Cipher cipher = Cipher.getInstance(ALGORITHMSTR); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES")); byte[] decryptBytes = cipher.doFinal(encryptBytes); return new String(decryptBytes); } /** * 将base 64 code AES解密 * @param encryptStr 待解密的base 64 code * @param decryptKey 解密密钥 * @return 解密后的string * @throws Exception */ public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception { return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey); } }
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;@Data
@Configuration
@ConfigurationProperties(prefix = "html.convert")
public class HtmlConvertproperties {/** 生成的文件保存路径 */private String fileSavePath;/** echarts转换后的图片保存路径 */private String echartsImgSavePath;
}
import org.docx4j.Docx4J;
import org.docx4j.convert.in.xhtml.XHTMLImporterImpl;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFont;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.jaxb.Context;
import org.docx4j.model.structure.PageSizePaper;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.RFonts;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Entities;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;import static cn.aotu.sss.module.sss.util.text.word.HtmlConverter.RemoveTag.*;/*** html转换工具类** 图片长宽乘积不能太大,不然会导致内存溢出** HtmlConverter* @author: huangbing* @date: 2020/8/7 2:32 下午*/
public class HtmlConverter {/*** 页面大小*/public enum PageSize {/** 大小*/LETTER("letter"),LEGAL("legal"),A3("A3"),A4("A4"),A5("A5"),B4JIS("B4JIS");PageSize(String code){this.code = code;}private String code;public String getCode() {return code;}}/*** 移除的标签*/enum RemoveTag {/** 移除的标签*/SCRIPT("script"), A("a"), LINK("link"), HREF("href");RemoveTag(String code){this.code = code;}private String code;public String getCode() {return code;}}/*** 参数类*/private static class Params {/** 默认字体库*/private final static String DEFAULT_FONT_FAMILY = "STSongStd-Light";/** 默认字体库路径*/private final static String DEFAULT_FONT_PATH = "/static/fonts/STSongStd-Light.ttf";/** 默认是否横版*/private final static boolean DEFAULT_LAND_SCAPE = false;/** 默认页面尺寸*/private final static String DEFAULT_PAGE_SIZE = PageSize.A4.getCode();/** 字体库*/private String fontFamily = DEFAULT_FONT_FAMILY;/** 字体库路径*/private String fontPath = DEFAULT_FONT_PATH;/** 页面尺寸*/private String pageSize = DEFAULT_PAGE_SIZE;/** 是否横版*/private boolean isLandScape = DEFAULT_LAND_SCAPE;/** 保存的文件的路径 */private String saveFilePath = HtmlConverter.class.getResource("/").getPath() + "output/";}private final Logger logger = LoggerFactory.getLogger(HtmlConverter.class);private Builder builder;public HtmlConverter(Builder builder) {this.builder = builder;}/*** 构建类*/public static class Builder {private Params params;public Builder() {this.params = new Params();this.params.fontFamily = Params.DEFAULT_FONT_FAMILY;this.params.fontPath = Params.DEFAULT_FONT_PATH;this.params.pageSize = Params.DEFAULT_PAGE_SIZE;this.params.isLandScape = Params.DEFAULT_LAND_SCAPE;}public Builder fontFamily(String fontFamily) {this.params.fontFamily = fontFamily;return this;}public Builder fontPath(String fontPath) {this.params.fontPath = fontPath;return this;}public Builder pageSize(String pageSize) {this.params.pageSize = pageSize;return this;}public Builder isLandScape(boolean isLandScape) {this.params.isLandScape = isLandScape;return this;}public Builder saveFilePath(String saveFilePath) {this.params.saveFilePath = saveFilePath;return this;}/*** 数据处理完毕之后处理逻辑放在构造函数里面** @return*/public HtmlConverter builder() {return new HtmlConverter(this);}}/*** 将页面保存为 docx** @param url* @param fileName* @return* @throws Exception*/public File saveUrlToDocx(String url, String fileName) throws Exception {return saveDocx(url2word(url), fileName);}/*** 将页面保存为 pdf** @param url* @param fileName* @return* @throws Exception*/public File saveUrlToPdf(String url, String fileName) throws Exception {return savePdf(url2word(url), fileName);}/*** 将页面转为 {@link WordprocessingMLPackage}** @param url* @return* @throws Exception*/public WordprocessingMLPackage url2word(String url) throws Exception {return xhtml2word(url2xhtml(url));}/*** 将 {@link WordprocessingMLPackage} 存为 docx** @param wordMLPackage* @param fileName* @return* @throws Exception*/public File saveDocx(WordprocessingMLPackage wordMLPackage, String fileName) throws Exception {File file = new File(genFilePath(fileName) + ".docx");//保存到 docx 文件wordMLPackage.save(file);if (logger.isDebugEnabled()) {logger.debug("Save to [.docx]: {}", file.getAbsolutePath());}return file;}/*** 将 {@link WordprocessingMLPackage} 存为 pdf** @param wordMLPackage* @param fileName* @return* @throws Exception*/public File savePdf(WordprocessingMLPackage wordMLPackage, String fileName) throws Exception {File file = new File(genFilePath(fileName) + ".pdf");OutputStream os = new FileOutputStream(file);Docx4J.toPDF(wordMLPackage, os);os.flush();os.close();if (logger.isDebugEnabled()) {
// logger.debug("Save to [.pdf]: {}", file.getAbsolutePath());}return file;}/*** 将 {@link Document} 对象转为 {@link WordprocessingMLPackage}* xhtml to word** @param doc* @return* @throws Exception*/protected WordprocessingMLPackage xhtml2word(Document doc) throws Exception {//A4纸,//横版:trueWordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(PageSizePaper.valueOf(this.builder.params.pageSize), this.builder.params.isLandScape);//配置中文字体configSimSunFont(wordMLPackage);XHTMLImporterImpl xhtmlImporter = new XHTMLImporterImpl(wordMLPackage);//导入 xhtmlwordMLPackage.getMainDocumentPart().getContent().addAll(xhtmlImporter.convert(doc.html(), doc.baseUri()));return wordMLPackage;}/*** 将页面转为{@link Document}对象,xhtml 格式** @param url* @return* @throws Exception*/protected Document url2xhtml(String url) throws Exception {// 添加头部授权参数防止被过滤String token = AESEncryptUtils.aesEncryptToString("html2File");Document doc = Jsoup.connect(url).header("Authorization", token).get();if (logger.isDebugEnabled()) {
// logger.debug("baseUri: {}", doc.baseUri());}//除去所有 scriptfor (Element script : doc.getElementsByTag(SCRIPT.getCode())) {script.remove();}//除去 a 的 onclick,href 属性for (Element a : doc.getElementsByTag(A.getCode())) {a.removeAttr("onclick");
// a.removeAttr("href");}//将link中的地址替换为绝对地址Elements links = doc.getElementsByTag(LINK.getCode());for (Element element : links) {String href = element.absUrl(HREF.getCode());if (logger.isDebugEnabled()) {
// logger.debug("href: {} -> {}", element.attr(HREF.getCode()), href);}element.attr(HREF.getCode(), href);}//转为 xhtml 格式doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml).escapeMode(Entities.EscapeMode.xhtml);if (logger.isDebugEnabled()) {String[] split = doc.html().split("\n");for (int c = 0; c < split.length; c++) {
// logger.debug("line {}:\t{}", c + 1, split[c]);}}return doc;}/*** 为 {@link WordprocessingMLPackage} 配置中文字体** @param wordMLPackage* @throws Exception*/protected void configSimSunFont(WordprocessingMLPackage wordMLPackage) throws Exception {Mapper fontMapper = new IdentityPlusMapper();wordMLPackage.setFontMapper(fontMapper);//加载字体文件(解决linux环境下无中文字体问题)URL simsunUrl = this.getClass().getResource(this.builder.params.fontPath);PhysicalFonts.addPhysicalFont(simsunUrl);PhysicalFont simsunFont = PhysicalFonts.get(this.builder.params.fontFamily);fontMapper.put(this.builder.params.fontFamily, simsunFont);//设置文件默认字体RFonts rfonts = Context.getWmlObjectFactory().createRFonts();rfonts.setAsciiTheme(null);rfonts.setAscii(this.builder.params.fontFamily);wordMLPackage.getMainDocumentPart().getPropertyResolver().getDocumentDefaultRPr().setRFonts(rfonts);}/*** 直接通过HTML字符串生成Word处理包(核心修改点)*/public WordprocessingMLPackage htmlString2word(String htmlContent) throws Exception {// 解析 HTML 字符串为 Document 对象Document doc = Jsoup.parse(htmlContent);// 配置输出设置(修正后的关键步骤)doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml).escapeMode(Entities.EscapeMode.xhtml);// 清理不安全标签(复用原有逻辑)cleanHtml(doc);// 转换为 Word 处理包return xhtml2word(doc);}/*** 清理HTML标签(提取公共方法)*/private void cleanHtml(Document doc) {// 移除script标签doc.getElementsByTag(RemoveTag.SCRIPT.getCode()).remove();// 移除a标签的事件和链接属性doc.getElementsByTag(RemoveTag.A.getCode()).forEach(a -> {a.removeAttr("onclick");
// a.removeAttr("href");});// 处理link标签的绝对路径(如需加载外部资源,可保留此逻辑)doc.getElementsByTag(RemoveTag.LINK.getCode()).forEach(link -> {String href = link.absUrl(RemoveTag.HREF.getCode());link.attr(RemoveTag.HREF.getCode(), href);});}/*** 公共文件下载处理方法*/public void handleFileDownload(File file,String displayFileName,HttpServletRequest request,HttpServletResponse response) throws Exception {// 文件名编码处理String encodedFileName = URLEncoder.encode(displayFileName, "UTF-8").replaceAll("\\+", "%20"); // 处理空格问题// 设置响应头response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);response.setHeader("Content-Length", String.valueOf(file.length()));// 流传输try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {byte[] buffer = new byte[1024 * 8];int bytesRead;while ((bytesRead = bis.read(buffer)) != -1) {bos.write(buffer, 0, bytesRead);}bos.flush();}}/*** 生成文件位置** @return*/protected String genFilePath(String fileName) {return this.builder.params.saveFilePath + fileName;}public static void main(String[] args) throws Exception {
// //输入要转换的网址
// String url = "http://192.168.20.56:8080/viewReport";
// new Builder().saveFilePath("/Users/huangbing/Desktop/echartsImages/")
// .builder()
// .saveUrlToDocx(url, "test");String s = "[img1] [img1] [img1]";String s1 = s.replaceAll("\\[img1\\]", "22");System.out.println(s1);}
}
四、controller
@Autowired
private HtmlConvertproperties htmlConvertproperties; // 注入配置类获取文件路径/*** 直接接收HTML富文本内容生成Word文档* @param htmlContent 富文本HTML代码(如:<p>富文本内容</p>)*/@PostMapping("/export")@Operation(summary = "导出word")@Parameter(name = "htmlContent", description = "富文本内容", required = true)public void generateWord(@RequestParam("htmlContent") String htmlContent,HttpServletRequest request,HttpServletResponse response) throws Exception {// 1. 初始化HtmlConverter(使用配置中的文件保存路径)HtmlConverter htmlConverter = new HtmlConverter.Builder().saveFilePath(htmlConvertproperties.getFileSavePath()) // 从配置获取路径.builder();// 2. 转换HTML字符串为Word处理包WordprocessingMLPackage wordMLPackage = htmlConverter.htmlString2word(htmlContent);// 3. 生成临时文件并设置响应String fileName = "report_" + System.currentTimeMillis();File tempFile = htmlConverter.saveDocx(wordMLPackage, fileName); // 调用原有保存逻辑// 4. 处理文件下载(兼容不同浏览器)htmlConverter.handleFileDownload(tempFile, "报告.docx", request, response);// 5. 清理临时文件(根据需求可选,生产环境建议异步清理或设置过期策略)tempFile.deleteOnExit();}
五、引用说明
工具类参考github上的文章,但是对于工具类中的的具体逻辑作了修改。
https://github.com/FTOLs/report-demo
六、测试
相关文章:

Java 富文本转word
前言: 本文的目的是将传入的富文本内容(html标签,图片)并且分页导出为word文档。 所使用的为docx4j 一、依赖导入 <!-- 富文本转word --><dependency><groupId>org.docx4j</groupId><artifactId>docx4j</artifactId&…...

多模态大语言模型arxiv论文略读(四十三)
InteraRec: Screenshot Based Recommendations Using Multimodal Large Language Models ➡️ 论文标题:InteraRec: Screenshot Based Recommendations Using Multimodal Large Language Models ➡️ 论文作者:Saketh Reddy Karra, Theja Tulabandhula …...

GPU加速-系统CUDA12.5-Windows10
误区注意 查看当前系统可支持的最高版本cuda:nvidia-smi 说明: 此处显示的12.7只是驱动对应的最高版本,不一定是 / 也不一定需要是 当前Python使用的版本。但我们所安装的CUDA版本需要 小于等于它(即≤12.7)因此即使…...

kafka课后总结
Kafka是由LinkedIn开发的分布式发布 - 订阅消息系统,具备高吞吐量、低延迟、可扩展性、持久性、可靠性、容错性和高并发等特性。其主要角色包括Broker、Topic、Partition、Producer、Consumer、Consumer Group、replica、leader、follower和controller。消息系统中存…...
排序算法(快排+推排序+归并排序)
一、快排(不稳定O(NlogN)) 分治思想,随机选一个数作为pivot,然后放到数组最后去,比这个元素小的放左边,比这个元素大的放右边。最后再交换左边放完后的下一个元素和pivot,这样就把一个元素排好…...

【股票系统】使用docker本地构建ai-hedge-fund项目,模拟大师炒股进行分析。人工智能的对冲基金的开源项目
股票系统: https://github.com/virattt/ai-hedge-fund 镜像地址: https://gitcode.com/gh_mirrors/ai/ai-hedge-fund 项目地址: https://gitee.com/pythonstock/docker-run-ai-hedge-fund 这是一个基于人工智能的对冲基金的原理验证项目。本项目旨在探讨利用人工智能进行…...

施工安全巡检二维码制作
进入新时代以来,人们对安全的重视程度越来越高。特别在建筑施工行业,安全不仅是关乎着工人的性命,更是承载着工人背后家庭的幸福生活。此时就诞生了安全巡检的工作,而巡检过程中内容庞杂,安全生产检查、隐患排查、施工…...
什么是函数依赖中的 **自反律(Reflexivity)**、**增广律(Augmentation)** 和 **传递律(Transitivity)?
文章目录 1. 自反律(Reflexivity Rule)规则定义实际例子应用意义 2. 增广律(Augmentation Rule)规则定义实际例子应用意义 3. 传递律(Transitivity Rule)规则定义实际例子应用意义 综合应用场景:…...

基于 Google Earth Engine (GEE) 的土地利用变化监测
一、引言 土地利用变化是全球环境变化的重要组成部分,对生态系统、气候和人类社会产生深远影响。利用遥感技术可以快速、准确地获取土地利用信息,监测其变化情况。本文将详细介绍如何使用 GEE 对特定区域的 Landsat 影像进行处理,实现土地利…...
Java基础语法10分钟速成
Java基础语法10分钟速成,记笔记版 JDKhello world变量字符串 类,继承,多态,重载 JDK JDK即Java development key,Java环境依赖包 在jdk中 编译器javac将代码的Java源文件编译为字节码文件(.classÿ…...
如何在Spring Boot中实现热加载以避免重启服务器
在 Spring Boot 开发中,频繁修改代码(如 Java 类、配置文件或静态资源)通常需要重启服务器,这会中断开发流程并降低效率。热加载(Hot Reloading)允许开发者在不重启服务器的情况下重新加载更改,…...

BT169-ASEMI无人机专用功率器件BT169
编辑:ll BT169-ASEMI无人机专用功率器件BT169 型号:BT169 品牌:ASEMI 封装:SOT-23 批号:最新 引脚数量:3 特性:单向可控硅 工作温度:-40℃~150℃ BT169单向可控硅ÿ…...
C++学习笔记(三十六)——STL之排序算法
一、STL 算法 C的STL(Standard Template Library) 提供了一组高效、通用的算法,这些算法适用于各种容器(如 vector、list、set、map)。 这些算法主要位于 <algorithm> 和 <numeric> 头文件中。 通用性&a…...

AI图像编辑器 Luminar Neo 便携版 Win1.24.0.14794
如果你对图像编辑有兴趣,但又不想花费太多时间学习复杂的软件操作,那么 Luminar Neo 可能就是你要找的完美工具。作为一款基于AI技术的创意图像编辑器,Luminar Neo简化了复杂的编辑流程,即使是没有任何图像处理经验的新手…...

发币流程是什么,需要多少成本?
这是一个专注于Web3相关开发的账号,具体会讲解步骤以及开发方案 偶尔会有科普,有兴趣的可以点右上角关注一下 发币(发行数字货币)的流程通常涉及技术实现、法律合规、经济模型设计等多个环节,以下是关键步骤的简要说明…...

【fork初体验】
文章目录 Linux 实验:深入理解 fork 系统调用一、实验目的二、实验环境三、实验内容与步骤(一)打印进程的进程 ID 和父进程 ID1. 编写程序2. 编译与运行3. 运行结果 (二)使用 fork 系统调用创建进程并加入循环语句1. 编…...

学习设计模式《六》——抽象工厂方法模式
一、基础概念 抽象工厂模式的本质是【选择产品簇(系列)的实现】; 抽象工厂模式定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类; 抽象工厂模式功能:抽象工厂的功能是为一系列相关对象或相互依…...

python_BeautifulSoup提取html中的信息
目录 描述: 过程: step one 下载html网页到本地 step two 提取html信息 list_con soup.select(.list-con) [0] li_list list_con.find_all(li) a li.find(span).find(a) title a.get(title) url a.get(href) span li.find(span).find(spa…...
单例设计模式之懒汉式以及线程安全问题
在单例设计模式中,懒汉式(Lazy Initialization) 通过延迟实例化来优化资源使用,但在多线程环境下存在线程安全问题。以下是其核心问题及解决方案的详细解析: 一、基础懒汉式代码(线程不安全) pu…...

今日头条如何查看IP归属地?详细教程与常见问题解答
在当今互联网时代,IP属地信息已成为各大社交平台展示用户真实性的重要标识。今日头条作为国内领先的资讯平台,也提供了IP属地显示功能。那么,今日头条怎么查看IP归属地?本文将详细介绍在今日头条11.9.0版本中如何查看自己和他人的…...
React-Hook
一、基础 Hooks 1、useState - 状态管理 useState 是 React 提供的一个函数,用来在函数组件中声明和修改状态,没有它,函数组件只是一个“静态模板”;有了它,函数组件可以保存和更新数据(比如计数器数值、输…...
前端节流、防抖函数
节流 什么是节流? 节流就是同一个事件 一秒钟他执行了很多次。但是我不想他执行这么多次,我只想让他执行一次 或者两次。 那该怎么办? why baby why 那我想就是他执行的时候 我就设置一个定时器,如果定时器是空的,等会…...
高级java每日一道面试题-2025年4月26日-基础篇[反射篇]-什么是类型擦除?它与反射之间有什么关系?
如果有遗漏,评论区告诉我进行补充 面试官: 什么是类型擦除?它与反射之间有什么关系? 我回答: 类型擦除与反射的深度解析 一、类型擦除(Type Erasure) 类型擦除是Java泛型实现的核心机制,旨在通过编译期处理确保向…...
Centos7系统防火墙使用教程
CentOS 7是一种常见的Linux操作系统,防火墙作为网络安全的第一道防线,对于服务器的安全至关重要。本文将介绍CentOS 7系统中防火墙的使用教程,包括如何开启、关闭、配置以及防火墙规则的添加和删除。 一、查看防火墙状态 在开始操作之前&am…...
缓存与数据库数据一致性:旁路缓存、读写穿透和异步写入模式解析
旁路缓存模式、读写穿透模式和异步缓存写入模式是三种常见的缓存使用模式,以下是对三种经典缓存使用模式在缓存与数据库数据一致性方面更全面的分析: 一、旁路缓存模式(Cache - Aside Pattern) 1.数据读取流程 应用程序首先向缓…...

【物联网】基于LORA组网的远程环境监测系统设计(机智云版)
基于LORA组网的远程环境监测系统设计(机智云版) 演示视频: 简介: 1.本系统有一个主机,两个从机。 2.一主多从的LORA组网通信,主机和两个从机都配备了STM32F103单片机与 LoRa 模块,主机作为中心设备及WIFI网关,负责接收和发送数据到远程物联网平台和手机APP,两个从机…...
Pygame事件处理详解:键盘、鼠标与自定义事件
Pygame事件处理详解:键盘、鼠标与自定义事件 在游戏开发中,玩家的交互是至关重要的。无论是移动角色、触发动作还是暂停游戏,都需要通过各种输入来实现。Pygame作为一个功能强大的Python库,提供了丰富的API来处理这些输入,包括键盘、鼠标以及自定义事件。本文将详细介绍如…...

制作一款打飞机游戏22:表格导出
编辑器功能扩展 今天,我想让编辑器能够处理一个数组,这是编辑器将要编辑的东西,它只编辑数组。这些区域在后续的不同版本的编辑器中会有不同的含义,但现在我想创建一个模板,能够加载一个二维数组,并将二维…...

Linux内核源码结构
目录 Linux内核源码结构 Linux内核版本命名 Linux内核版本选择 内核源码结构 arch:与CPU架构相关的源代码 block:磁盘设备的支持 COPYING文件 CREDITS文件 crypto:加密相关 Documentation: drivers:设备驱动 firmware:固件 fs:文件系统 include:头文件…...

72.评论日记
【巫师】中美关税战02:应给人民爆装备,以及普通人如何应对(7条建议)_哔哩哔哩_bilibili 2025年4月26日11:03:31...