呓语博客
type: channel
link: /
description: 博客园
items: 多线程按序执行
items: Linux服务器部署Java项目后无法渲染验证码
items: Java中如何将Markdown转成Word？
items: Nginx安装并配置国家/城市黑白名单限制访问
items: Linux部署项目时的常用命令
items: SpringBoot实现数据下资源的永久地址
items: Win10/11下安装WSL并修改WSL默认安装目录到其他盘（转载）
items: Nuxt教程
items: Java给图片添加水印
items: MongoDB快速入门并使用SpringBoot集成

多线程按序执行
type: item
date: 2024-10-04T23:13:32+08:00
description: 多线程按序执行三个不同的线程 A、B、C 将会共用一个 Foo 实例。线程 A 将会调用 first() 方法线程 B 将会调用 second() 方法线程 C 将会调用 third() 方法请设计程序，以确保 second() 方法在 first() 方法之后被执行，third() 方法在 second() 方法之后被执行。解决思路定义标记，如对应线程的标志为可运行时，线程才可执行。AtomicInteger 是 Java 并发包 (java.util.concurrent.atomic) 中的一个原子类，用于在多线程环境下安全地操作单个 int 类型的值。它提供了一种无锁的线程安全整数操作方式，性能通常优于使用同步锁的方法。以下是 AtomicInteger 的详细介绍：基本概念：AtomicInteger 封装了一个 int 值，所有对这个值的操作都是原子的。它使用了 CPU 的 CAS（Compare-And-Swap）指令来确保操作的原子性。适用于需要频繁更新单个整数值的多线程场景。主要方法：get(): 获取当前值set(int newValue): 设置为给定值getAndSet(int newValue): 设置新值并返回旧值compareAndSet(int expect, int update): 如果当前值等于预期值，则更新为新值getAndIncrement(): 自增并返回旧值getAndDecrement(): 自减并返回旧值incrementAndGet(): 自增并返回新值decrementAndGet(): 自减并返回新值getAndAdd(int delta): 加上给定值并返回旧值addAndGet(int delta): 加上给定值并返回新值使用场景：计数器（如请求计数、并发访问计数）序列号生成无锁算法中的版本控制使用CountDownLatch ，CountDownLatch 是 Java 并发包 (java.util.concurrent) 中的一个同步工具类，用于协调多个线程之间的同步。它允许一个或多个线程等待，直到其他线程完成一组操作后才继续执行基本概念：CountDownLatch 维护一个计数器，这个计数器被初始化为一个正整数，表示需要等待的事件数量。当事件发生时，计数器会递减。线程可以调用 await() 方法阻塞等待，直到计数器变为零。主要方法：countDown()：使计数器减 1。当计数器达到零时，所有等待的线程将被释放。await()：使当前线程等待，直到计数器为零，或者线程被中断。await(long timeout, TimeUnit unit)：带超时的等待。getCount()：获取当前的计数。使用场景：确保某个计算在其需要的所有资源都被初始化之后才执行。确保某个服务在其依赖的所有其他服务都已经启动之后才启动。等待多个并行执行的任务全部完成。使用原子变量进行标记public class ThA { static class Foo { public Foo() { } private final AtomicInteger third = new AtomicInteger(0); private final AtomicInteger second = new AtomicInteger(0); public void first() { System.out.println("first"); second.incrementAndGet(); } public void second() { while (second.get() != 1) { } System.out.println("second"); second.incrementAndGet(); } public void third() { while (third.get() != 1) { } System.out.println("third"); } } public static void main(String[] args) { long startTime = System.currentTimeMillis(); Foo foo = new Foo(); Thread thread1 = new Thread(foo::first); Thread thread2 = new Thread(foo::second); Thread thread3 = new Thread(foo::third); thread1.start(); thread2.start(); thread3.start(); try { thread1.join(); thread2.join(…

Linux服务器部署Java项目后无法渲染验证码
type: item
date: 2024-09-24T11:45:00+08:00
description: 安装字体包安装字体在哪个目录都可以输入的命令yum install fontconfig -y fc-cache --force安装完后在/usr/shared目录就可以看到fonts和fontconfig两个目录。然后重启项目，验证码能正常获取了并且后端也不再报错了。

Java中如何将Markdown转成Word？
type: item
date: 2024-09-14T14:06:15+08:00
description: Java中如何将Markdown转成Word？1、Maven依赖 com.vladsch.flexmark flexmark-all 0.64.8 org.apache.poi poi 5.3.0 org.apache.poi poi-ooxml 5.3.0 org.apache.poi poi-ooxml-schemas 4.1.2 2、工具类package com.pq.chat.ai.core.utils; import cn.hutool.core.util.IdUtil; import com.vladsch.flexmark.ext.tables.TablesExtension; import com.vladsch.flexmark.html.HtmlRenderer; import com.vladsch.flexmark.parser.Parser; import com.vladsch.flexmark.util.data.MutableDataSet; import lombok.extern.slf4j.Slf4j; import org.apache.poi.poifs.filesystem.DirectoryEntry; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import java.io.ByteArrayInputStream; import java.io.FileOutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; /** * Word工具类 * @author THF * @date 2024/9/13 14:15 */ @Slf4j public class WordUtil { /** * 将MarkDown转换成HTML * * @param markdown Markdown * @return HTML */ public static String markdownToHtml(String markdown) { // 设置解析器配置 MutableDataSet options = new MutableDataSet(); options.set(Parser.EXTENSIONS, List.of(TablesExtension.create())); // 创建Markdown解析器和HTML渲染器 Parser parser = Parser.builder(options).build(); HtmlRenderer renderer = HtmlRenderer.builder(options).build(); // 将Markdown转换为HTML return renderer.render(parser.parse(markdown)); } /** * HTML转换成Word * * @param html HTML * @return WORD文件 */ public static String htmlToWord(String html) { try { String html1 = " " + " " + " " + " " + // 你的内容 html + " "; // 文件名称 String fileName = IdUtil.fastSimpleUUID() + ".doc"; //目标路径 Path targetPath = Paths.get(FileProperties.BASE_PATH, fileName); Files.createDirectories(targetPath.getParent()); // 保存doc文档 FileOutputStream outputStream = new FileOutputStream(targetPath.toFile()); // 生成doc格式的word文档，需要手动改为docx byte[] by = html1.getBytes(StandardCharsets.UTF_8); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(by); POIFSFileSystem poifsFileSystem = new POIFSFileSystem(); …

Nginx安装并配置国家/城市黑白名单限制访问
type: item
date: 2024-08-12T17:51:00+08:00
description: 下载Nginx包Nginx官网下载地址安装GCC等环境# 安装gcc，源码编译依赖 gcc 环境 yum -y install gcc-c++ # 安装pcre，pcre是一个perl库，包括perl兼容的正则表达式库，nginx的http模块使用pcre来解析正则表达式，所以需要安装pcre库 yum install -y pcre pcre-devel # 安装zlib，zlib 库提供了很多种压缩和解压缩的方式，nginx 使用 zlib 对 http 包的内容进行 gzip yum install -y zlib zlib-devel # 安装OpenSSL库 yum install -y openssl openssl-devel下载Nginx-Geo模块下载地址解压到Linux服务器中例如：/env/nginx_lib/ngx_http_geoip2_module-3.4下载国家/城市数据库国家数据库城市数据库解压到Linux服务器中例如：/env/nginx_lib/GeiLite2-Country.mmdb国家数据库文件名：GeiLite2-Country.mmdb城市数据库文件名：GeiLite2-City.mmdb编译安装# 到下载的Nginx目录下执行命令 ./configure --prefix=[Nginx安装目录] --with-http_ssl_module --add-module=[ngx_http_geoip2_module模块文件路径] && make -j 4 && make install #到安装目录启动Nginx ./nginx #例如 # ./configure --prefix=/env/nginx --with-http_ssl_module --add-module=/env/nginx_lib/ngx_http_geoip2_module-3.4 && make -j 4 && make install ChatGPT解释这行命令是用于配置、编译和安装 Nginx 的。让我们分解一下每个部分的含义： 1. `./configure --prefix=/env/nginx --with-http_ssl_module --add-module=/env/nginx_lib/ngx_http_geoip2_module-3.4`: - `./configure`: 这是一个脚本，用于检查系统环境并配置 Nginx 的构建选项。 - `--prefix=/env/nginx`: 这个选项指定了 Nginx 将被安装到的目录。在这种情况下，Nginx 将被安装到 `/env/nginx` 目录下。 - `--with-http_ssl_module`: 这个选项启用了 HTTP SSL 模块，使 Nginx 支持 HTTPS。 - `--add-module=/env/nginx_lib/ngx_http_geoip2_module-3.4`: 这个选项用于添加一个额外的模块，在这里是 `ngx_http_geoip2_module`，该模块用于处理基于 GeoIP2 数据库的地理定位功能。模块的路径是 `/env/nginx_lib/ngx_http_geoip2_module-3.4`。 2. `&& make -j 4`: - `&&`: 这是一个逻辑操作符，用于在前一条命令成功后执行下一条命令。 - `make -j 4`: 这个命令用于并行编译 Nginx 代码。`-j 4` 表示使用 4 个并行线程来加快编译速度。 3. `&& make install`: - `make install`: 这个命令用于将编译完成的 Nginx 安装到前面指定的目录 `/ent-test/nginx` 中。 总结来说，这行命令是在配置、编译和安装 Nginx，同时启用了 SSL 支持并添加了 GeoIP2 模块。限制国家访问nginx.conf# 配置到http代码段中，/env/nginx_lib/GeoLite2-Country.mmdb为国家数据库路径 # 配置 GeoIP2 模块，指定使用的 GeoLite2-Country.mmdb 数据库 geoip2 /env/nginx_lib/GeoLite2-Country.mmdb { # 每5分钟自动重新加载数据库 auto_reload 5m; # 通过访问者IP获取国家代码，默认值为US（美国） $geoip2_data_country_code default=US source=$remote_addr country iso_code; # 通过访问者IP获取城市名称，默认值为Toronto（多伦多） $geoip…

Linux部署项目时的常用命令
type: item
date: 2024-07-26T14:09:26+08:00
description: 配置Java环境变量在/etc/profile文件最下方追加下面两行export JAVA_HOME=/env/jdk/jdk-17.0.8 export PATH=$PATH:$JAVA_HOME/bin刷新配置文件：source /etc/profile安装字体包安装字体在哪个目录都可以输入的命令yum install fontconfig -y fc-cache --force安装完后在/usr/shared目录就可以看到fonts和fontconfig两个目录。然后重启项目，验证码能正常获取了并且后端也不再报错了。

SpringBoot实现数据下资源的永久地址
type: item
date: 2024-07-15T22:34:18+08:00
description: SpringBoot实现数据下资源的永久地址目的：实现数据下资源的永久地址，无论这条数据下文件资源被替换成何种文件，但是预览地址始终不变/** * 预览或下载文件 * @param id 资源id * @return 文件 */ @GetMapping("/preview/{id}") public ResponseEntity<org.springframework.core.io.Resource> preview(@PathVariable("id") Long id) { LayoutResource layoutResource = layoutResourceService.getById(id); if(ObjectUtil.isEmpty(layoutResource)){ throw new ServiceException("资源不存在"); } SysOssVo sysOssVo = sysOssService.getById(layoutResource.getOssId()); String contentType = getContentType(sysOssVo.getUrl()); InputStream inputStream = sysOssService.getObjectContent(layoutResource.getOssId()); boolean hasImage = isImage(sysOssVo.getFileName()); if (contentType == null) { contentType = "application/octet-stream"; } return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, hasImage ? "inline" : "attachment; filename=\"" + java.net.URLEncoder.encode(sysOssVo.getOriginalName(),StandardCharsets.UTF_8) + "\"") .contentType(MediaType.parseMediaType(contentType)) .body(new InputStreamResource(inputStream)); }/** * 获取文件类型 * @param urlString URL地址 * @return 文件类型 */ private String getContentType(String urlString){ String contentType = null; try { URL url = new URL(urlString); URLConnection connection = url.openConnection(); connection.setUseCaches(false); connection.connect(); contentType = connection.getContentType(); } catch (Exception e) { e.printStackTrace(); } return contentType; }

Win10/11下安装WSL并修改WSL默认安装目录到其他盘（转载）
type: item
date: 2024-06-08T13:06:28+08:00
description: 转载至 https://blog.csdn.net/farer_yyh/article/details/133934904

Nuxt教程
type: item
date: 2024-06-06T22:40:43+08:00
description: Nuxt教程官网：https://nuxt.com/1、初始化项目如初始化项目失败请在WIndows的hosts文件中添加如下代码185.199.108.133 raw.githubusercontent.com2、认识项目文件.nuxt：运行项目生成的文件nuxt.config.ts：配置文件// https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ // 是否开启SSR服务端渲染，默认为true ssr:true, devtools: { enabled: true } })Nuxt自带是基于文件的路由系统，无需安装vue-router3、SEO优化通过设置网页 title 和 description 等SEO优化信息，由服务端渲染，可提高网页在搜索引擎页面中的排名和可见性app.vue 首页 视频 <NuxtPage />

Java给图片添加水印
type: item
date: 2024-05-04T15:15:00+08:00
description: Java给图片添加水印1、平铺水印package com.ruoyi.system.utils; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; public class ImageUtil { // 水印透明度 private static float alpha = 0.5f; // 水印文字大小 public static final int FONT_SIZE = 18; // 水印文字字体 private static Font font = new Font("宋体", Font.PLAIN, FONT_SIZE); // 水印文字颜色 private static Color color = Color.red; // 水印之间的间隔 private static final int XMOVE = 80; // 水印之间的间隔 private static final int YMOVE = 80; /** * 给图片添加水印文字 * * @param logoText 水印文字 * @param srcImgPath 源图片路径 * @param targerPath 目标图片路径 */ public static void ImageByText(String logoText, String srcImgPath, String targerPath) { ImageByText(logoText, srcImgPath, targerPath, null); } /** * 获取文本长度。汉字为1:1，英文和数字为2:1 */ private static int getTextLength(String text) { int length = text.length(); for (int i = 0; i < text.length(); i++) { String s = String.valueOf(text.charAt(i)); if (s.getBytes().length > 1) { length++; } } length = length % 2 == 0 ? length / 2 : length / 2 + 1; return length; } /** * 给图片添加水印文字、可设置水印文字的旋转角度 * * @param logoText * @param srcImgPath * @param targerPath * @param degree */ public static void ImageByText(String logoText, String srcImgPath, String targerPath, Integer degree) { InputStream is = null; OutputStream os = null; try { // 源图片 Image srcImg = ImageIO.read(new File(srcImgPath)); int width = srcImg.getWidth(null);// 原图宽度 int height = srcImg.getHeight(null);// 原图高度 BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null), srcImg.getHeight(null), BufferedImage.TYPE_INT_RGB); // 得到画笔对象 Graphics2D g = buffImg.createGraphics(); // 设置对线段的锯齿状边缘处理 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.drawImage(srcImg.getScaledInstance(srcImg.getWidth(null), srcImg.getHeight(null), Image.SCALE_SMOOTH), 0, 0, null); // 设置水印旋转 if (null != degree) { g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2); } // 设置水印…

MongoDB快速入门并使用SpringBoot集成
type: item
date: 2024-01-17T15:11:00+08:00
description: MongoDB百度百科：MongoDB是一个介于关系数据库和非关系数据库之间的产品，是非关系数据库当中功能最丰富，最像关系数据库的。它支持的数据结构非常松散，是类似json的bson格式，因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大，其语法有点类似于面向对象的查询语言，几乎可以实现类似关系数据库单表查询的绝大部分功能，而且还支持对数据建立索引。MongoDB是一种NoSQL数据库管理系统，它采用文档导向的数据模型，而不是传统的关系型数据库模型。介绍数据模型： MongoDB采用BSON（Binary JSON）文档存储数据，这些文档以键值对的形式组织在集合（Collection）中。文档可以包含嵌套的结构，使其更灵活。灵活性： 由于MongoDB采用文档导向的数据模型，数据的结构可以非常灵活，可以轻松地适应不断变化的业务需求。横向扩展性： MongoDB支持横向扩展，可以通过添加更多的节点来增加系统的处理能力，而无需修改应用程序代码。丰富的查询语言： MongoDB提供强大的查询语言，支持丰富的查询操作，包括范围查询、正则表达式匹配、排序等。索引支持： MongoDB支持各种类型的索引，可以提高查询性能。自动分片： MongoDB可以自动分片数据，支持水平扩展，使其适用于处理大规模数据。优点灵活性和模式自由： 可以轻松地处理不同结构和类型的数据。横向扩展： 可以通过添加更多的节点来实现横向扩展，提高性能和容量。高性能： MongoDB使用内存映射存储引擎，可以提供高性能的读写操作。JSON风格的文档： 数据以JSON风格的BSON文档存储，易于理解和使用。自动分片和负载均衡： MongoDB自动管理数据的分片和负载均衡，简化了扩展过程。社区支持： MongoDB有一个活跃的社区，提供丰富的文档和资源，便于开发者学习和解决问题。缺点事务支持的限制： 在某些版本中，MongoDB的事务支持相对较弱，不如关系型数据库那么强大。内存占用较大： MongoDB的内存占用相对较大，因为它使用内存映射文件来加速读写操作。不适合复杂的事务处理： 对于需要复杂事务处理的应用，MongoDB可能不是最佳选择。使用场景大数据量、高并发读写： 由于MongoDB的横向扩展能力和高性能，适用于处理大规模数据和高并发读写的场景，如日志处理、物联网数据等。需要灵活的数据模型： 对于数据结构经常变化、需要频繁调整的应用，MongoDB的灵活数据模型非常适合。实时分析和查询： 适用于需要实时分析和查询大量非结构化数据的场景，例如实时报表生成、实时监控等。文档存储需求： 对于需要存储和处理复杂文档结构的应用，MongoDB的文档导向模型非常方便。敏捷开发： 在敏捷开发环境中，由于MongoDB的模式自由性，可以更快地迭代和调整数据模型。体系机构数据类型MongoDB的最小存储单位就是文档document对象。文档document对象对应于关系型数据库的行。数据在MongoDB中以BSON（Binary-JSON）文档的格式存储在磁盘上。BSON（Binary Serialized Document Format）是一种类json的一种二进制形式的存储格式，简称 Binary JSON；BSON和JSON一样，支持内嵌的文档对象和数组对象，但是BSON有JSON没有的一些数据类型，如Date和Bin Data类型。BSON采用了类似于C语言结构体的名称、对表示方法，支持内嵌的文档对象和数组对象，具有轻量性、可遍历性、高效性的三个特点，可以有效描述非结构化数据和结构化数据。这种格式的优点是灵活性高，但它的缺点是空间利用率不是很理想。BSON中，除了基本JSON类型： string，integer，boolean，double，null，array和object，mongo还使用了特殊的数据类型。这些类型包括 date， object id， binary data， regular expression和code。每一个驱动都以特定语言的方式实现了这些类型，查看你的驱动的文档来获取详细信息1、安装笔者本次采用ZIP压缩包的格式安装传送门解压（将压缩包解压到全英文的文件夹下）解压后目录结构如下创建文件夹（data、logs）data为数据存储文件夹logs为日志存储文件夹在bin目录创建配置文件（mongod.cfg），配置文件如下# mongod.conf # for documentation of all options, see: # http://docs.mongodb.org/manual/reference/configuration-options/ # Where and how to store data. st…