• [技术干货] 自行搭建rustdesk服务器-转载
    应用介绍 RustDesk 是一款可以平替 TeamViewer 的开源软件,旨在提供安全便捷的自建方案。 描述  跨平台支持:RustDesk可以在Windows、Linux、MacOS以及Android等多个平台上使用,为用户提供了极大的便利,无需担心设备兼容性问题。 安全性:它采用了安全的加密传输技术,确保用户数据的安全。在数据传输过程中,RustDesk会对数据进行加密,以防止数据泄露或被篡改。 高性能和低延迟:RustDesk的高性能和低延迟特性使得用户在进行远程操作时几乎感觉不到延迟,大大提高了用户体验。 多功能性:RustDesk支持多屏幕显示,对于需要同时操作多个屏幕的用户来说非常实用。此外,它还支持文件传输、剪贴板共享以及多种连接方式,包括基于IP的连接和基于域名的连接,以满足不同用户的需求。 易用性:相较于其他远程工具,RustDesk无需繁琐配置,用户只需在受控机上安装RustDesk并获取其ID和密码,然后在主控机上输入这些信息,即可快速建立连接。这种简洁的操作方式使得用户无需专业知识即可轻松上手。 灵活性:用户可以选择使用RustDesk的官方服务器或自建服务器,同时,如果用户有自己的云服务器且服务器带宽足够,那么使用RustDesk的体验将会更加流畅。  特性:  随时随地访问任何设备 支持 Windows、macOS、Linux、iOS、Android、Web 等多个平台。 支持 VP8 / VP9 / AV1 软件编解码器和 H264 / H265 硬件编解码器。 完全掌控数据,轻松自建。 P2P 连接,端到端加密。 在 Windows上可以非管理员不安装运行,根据需要在本地或远程提升权限。 操作简单  前期准备 本文将通过Linux宝塔面板Docker部署RustDesk服务器  应用部署 创建应用目录,我的地址/www/server/rustdesk,为了保证后续操作成功,希望与我的目录设置统一。 创建docker-compose.yml配置文件,这里我已经帮大家写好了,直接复制修改即可 version: '3'  networks:   rustdesk-net:     external: false  services:   hbbs:     container_name: hbbs     ports:       - 21115:21115       - 21116:21116 # 自定义 hbbs 映射端口       - 21116:21116/udp # 自定义 hbbs 映射端口     image: rustdesk/rustdesk-server:latest # 注意这里要加:latest,防止docker镜像缓存未更新的问题     command: hbbs -r xxx.xxx.com:21117 -k _ # 填入个人域名或 IP + hbbr 暴露端口,这里填写你解析后的域名或服务器ip都行, -k _意为使用key进行认证     volumes:       - /www/server/rustdesk:/root # 自定义挂载目录     networks:       - rustdesk-net     depends_on:       - hbbr     restart: unless-stopped     deploy:       resources:         limits:           memory: 64M    hbbr:     container_name: hbbr     ports:       - 21117:21117 # 自定义 hbbr 映射端口     image: rustdesk/rustdesk-server:latest #注意,这里同样需要拉取最新镜像     command: hbbr -k _ #这里的key也是需要key认证的话则要加     volumes:       - /www/server/rustdesk:/root # 自定义挂载目录     networks:       - rustdesk-net     restart: unless-stopped     deploy:       resources:         limits:           memory: 64M 注意:  hbbr 与 hbbs 的挂载目录必须为同一个,否则后面链接会提示对方已挂断提示 如果你想所有人都可以通过你的服务器来进行链接rustdesk,则需要删掉配置文件中 -k _ 配置文件中xxx.xxx.com需要替换为解析到目标服务器的域名或目标服务器公网ip地址 设置服务器安全组开放端口规则 注意:  将自己服务器与上方配置文件中有关所有端口全部放开21115,21116/TCP,21116/UDP,21117 开放宝塔面板中端口,同上 执行配置文件下载并启动容器 docker-compose up -d 1 查看启动容器运行中 docker ps -a 1 设备链接 下载rustdesk客户端并完成服务器对接 DownloadFile  下载完成进入软件,打开软件网络设置  注意:  ID服务器为文件中配置的个人域名或ip。格式例:www.baidu.com or 127.0.0.1 如果配置文件中增加了上述提到的-k _配置,则需要找到文件挂载目录/www/server/rustdesk中的id_ed25519.pub文件,将内容复制即可。 如果没有配置则不需要进行配置 错误解决 如果完全按照以上操作步骤进行部署任然出现了错误请看这里👇  ID不存在 配置了key的情况下,如果两台电脑key不匹配则会提示此问题。将两边电脑key配置相同即可  链接被对方关闭 这个问题就是前面提到的,hbbr 和 hbbs的挂载目录必须相同。更新配置文件,删除旧容器,重新启动即可  结语 真的很推荐有自己服务器的自己去使用这个。真的比收费某些远程工具好用很多。也流畅很多。 如果部署出现其他问题请留言或私信我~ ————————————————                              版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                          原文链接:https://blog.csdn.net/qq_45602658/article/details/138702681 
  • [问题求助] obs java的sdk在流式下载的时候有几率io异常
    sdk版本为3.21.11,实现的功能是依次下载obs内多个文件,并打包生成压缩包放在硬盘路径内首先在本地pc测试无问题,均能正常依次下载文件,但在华为云服务器(华北北京4的服务器,带宽5M)上运行,有很高频率压缩包会生成失败使用文档提供的 带获取进度的下载 示例来测试,观察日志发现,压缩包生成失败的原因,是在某几个文件上会有很高的频率下载到一定进度后就无响应(进度百分比的日志输出到不固定的某个进度后就停止了),直到超过设置的ConnectionTimeout和SocketTimeout时间,才抛出了SocketTimeoutException: Read timed out的异常(未捕获到ObsException异常),进而造成压缩包生成失败问题1:是否有办法继续定位 文件下载到一定进度后就无响应 问题原因的办法?问题2:如果考虑 捕获到SocketTimeoutException: Read timed out后进行重试机制,这边就希望能将设置的ConnectionTimeout和SocketTimeout时间缩小以减少重试的等待时间,但如果因为下载的文件过大,导致文件没有在这两个时间内下载完成,是否也会直接下载失败?注:试过直接在服务器下的浏览器访问这几个文件的url地址,均能正常获取到,所以我猜不是网络原因
  • [问题求助] 华为鸿蒙系统 安卓原生APP做VPN连接时手机息屏后就断
    我开发了一个安卓VPN应用,安装在华为鸿蒙系统上   一按电源键息屏就会发现数据包不发送了,已经设置了wakelock和手机设置息屏状态下wifi始终保持连接均不好使,请教各位需要怎么做
  • [专题汇总] 6月份干货合集来了,速进。
     大家好,6月份干货合集又来了,本次带来的内容涵盖了,java,Android,html,git,mysql,linux,网络协议,Jenkins等诸多内容供您选择 1.模拟买票小练习-线程资源同步小练习-synchronized使用 https://bbs.huaweicloud.com/forum/thread-02109154511981591054-1-1.html  2.Android Intent-Filter匹配规则解析 https://bbs.huaweicloud.com/forum/thread-02109154511945084053-1-1.html  3.web前端入门面对的git、angular和web开发必备的技术以及前端开发如何的运用技术? https://bbs.huaweicloud.com/forum/thread-02109154511910212052-1-1.html  4.前端技术分享(html总结) https://bbs.huaweicloud.com/forum/thread-02109154511861684051-1-1.html  5.0基础小白如何玩转前端开发? https://bbs.huaweicloud.com/forum/thread-02109154466914607049-1-1.html  6.RTSP 和 RTMP通过ffmpeg实现将本地摄像头推流到RTSP服务器-转载 https://bbs.huaweicloud.com/forum/thread-0244153476749248016-1-1.html  7.mysql8.0 性能优化配置 innodb_buffer_pool_size-转载 https://bbs.huaweicloud.com/forum/thread-02109153476715536012-1-1.html  8.linux 服务器无 sudo 权限非 root 用户安装特定版本 cuda -转载 https://bbs.huaweicloud.com/forum/thread-0224153476680638017-1-1.html  9.网络网络层之(6)ICMPv4协议-转载 https://bbs.huaweicloud.com/forum/thread-0273153476617308017-1-1.html  10.Window下SRS服务器的搭建-转载 https://bbs.huaweicloud.com/forum/thread-0264153476579428008-1-1.html  11.探索SRS-GB28181:一款强大的国标GB28181视频服务器-转载 https://bbs.huaweicloud.com/forum/thread-0210153476525852014-1-1.html  12.容器化部署 Jenkins,并配置SSH远程操作服务器-转载 https://bbs.huaweicloud.com/forum/thread-0224153476500551016-1-1.html  13.如何查看ubuntu服务器上防火墙信息-转载 https://bbs.huaweicloud.com/forum/thread-02127153476446295011-1-1.html  14.探索GoServer:高效、易用的Golang服务器框架 -转载 https://bbs.huaweicloud.com/forum/thread-0210153476421991013-1-1.html  15.使用Linux命令修改服务器时间及设置时区-转载 https://bbs.huaweicloud.com/forum/thread-0273153476396290016-1-1.html  16.pg_rman在恢复服务器上恢复源库的备份-转载 https://bbs.huaweicloud.com/forum/thread-0244153476353118015-1-1.html  17.linux之用户和权限-转载     https://bbs.huaweicloud.com/forum/thread-0273153476326497015-1-1.html  18.Linux-查看服务器--硬件配置信息-转载 https://bbs.huaweicloud.com/forum/thread-0273153476291979014-1-1.html  19.Python如何对文件进行重命名操作?-转载 
  • [二次开发] 如何获取华为FusionInsight MRS二次开发Redis样例代码
    如何获取 华为FusionInsight MRS二次开发Redis样例代码 redis-examples项目呢?
  • [技术干货] Java中Volatile关键字详解及代码示例
    背景知识volatile 是 Java 中的一个关键字,主要用于确保多线程环境下的变量可见性和禁止指令重排序。当一个变量被声明为 volatile 时,它告诉 JVM 和其他线程,这个变量是不稳定的,每次使用它的时候都必须从主内存中读取,而当它改变时也必须立即同步回主内存。这可以确保多个线程在访问这个变量时能够获取到最新的值。可见性在多线程环境中,每个线程都有自己的工作内存(也称为本地内存),线程之间共享的数据存储在主内存中。当线程需要读取或修改共享数据时,它首先会在自己的工作内存中复制一份,完成操作后再将结果写回主内存。这种机制可能导致一个线程修改了共享变量的值,但其他线程无法立即看到这个修改,这就是所谓的“可见性问题”。volatile 关键字可以确保所有线程都能看到共享变量的最新值。禁止指令重排序在 Java 虚拟机中,为了提高执行效率,编译器和处理器可能会对指令进行重排序。但是,这种重排序可能会违反程序的语义。volatile 关键字可以禁止这种重排序,确保程序按照代码的顺序来执行。代码示例下面是一个简单的示例,展示了 volatile 关键字的使用:public class VolatileExample { // 使用 volatile 关键字修饰的变量 private volatile boolean flag = false; // 启动一个新线程来修改 flag 的值 public void startThread() { new Thread(() -> { try { // 等待一段时间,确保主线程已经开始运行 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 修改 flag 的值 flag = true; System.out.println("Flag in thread: " + flag); }).start(); } public void mainLoop() { while (!flag) { // 循环检查 flag 的值,直到它为 true // 由于 flag 是 volatile 的,所以每次循环都会从主内存中读取它的值 System.out.println("Waiting for flag to become true..."); } System.out.println("Flag in main thread: " + flag); } public static void main(String[] args) { VolatileExample example = new VolatileExample(); example.startThread(); // 启动一个新线程来修改 flag 的值 example.mainLoop(); // 在主线程中循环检查 flag 的值 } }在这个示例中,我们创建了一个 volatile 变量 flag,并在一个新线程中修改它的值。在主线程中,我们通过一个循环来检查 flag 的值,直到它变为 true。由于 flag 是 volatile 的,所以每次循环都会从主内存中读取它的值,确保我们能看到最新的修改。
  • [技术干货] Java 中使用 Optionals 解决 NullPointException(NPE)问题
    背景null 在 Java 中经常是一个问题源头,因为它可能导致 NullPointerException(NPE),这是 Java 应用程序中常见的运行时异常。为了解决这个问题,Java 8 引入了 Optional 类,这是一个可以为 null 的容器对象。它提供了一种更好的方法来处理可能不存在的值,从而避免了直接返回 null 导致的潜在问题。案例说明下面是您给出的反例和正例的详细解释:反例:public String getValue() { // TODO return null; // 这可能导致 NullPointerException 如果调用者没有检查返回值是否为 null }在上面的反例中,getValue 方法返回一个 String,但在某些情况下,它可能返回 null。任何调用 getValue 的代码都需要确保检查返回的字符串是否为 null,否则如果尝试在 null 上调用方法或访问字段,就会抛出 NullPointerException。正例:import java.util.Optional; public Optional<String> getValue() { // TODO return Optional.empty(); // 使用 Optional.empty() 代替 null }在上面的正例中,getValue 方法返回一个 Optional<String> 而不是 String。如果值不存在,则返回 Optional.empty() 而不是 null。这样,调用者就可以使用 Optional 类提供的方法来更明确地处理可能不存在的值。例如,他们可以使用 isPresent() 方法来检查值是否存在,或者使用 orElse()、orElseGet()、orElseThrow() 等方法来提供一个默认值或抛出异常。下面是如何使用 Optional 的一些示例:Optional<String> valueOptional = getValue(); // 检查值是否存在 if (valueOptional.isPresent()) { String value = valueOptional.get(); // 使用 value } // 提供默认值 String valueWithDefault = valueOptional.orElse("defaultValue"); // 使用 lambda 表达式提供默认值 String valueWithLambda = valueOptional.orElseGet(() -> createDefaultValue()); // 如果值不存在则抛出异常 valueOptional.orElseThrow(() -> new IllegalStateException("Value is not present"));总结通过使用 Optional,代码可以更清晰地表达其意图,并减少 NullPointerException 的风险。然而,需要注意的是,过度使用 Optional 也可能导致代码变得难以阅读和理解,因此应该谨慎使用。在大多数情况下,当返回的值可能不存在时,使用 Optional 是一个好选择。但在其他情况下,比如返回值始终存在,或者可以通过其他方式(如异常)来清晰地表达错误情况时,使用 Optional 可能就不是必需的。
  • [技术干货] Java中的原子操作
    一、什么是原子操作原子操作是指在一个操作序列中,要么全部执行,要么全部不执行,不会被其他线程中断的操作。在Java中,原子操作主要通过java.util.concurrent.atomic包下的类来提供,这些类中的方法都是线程安全的,可以在多线程环境中安全地进行数据更新操作。二、基本类型的原子操作Java的java.util.concurrent.atomic包提供了一系列原子操作类,用于对基本数据类型进行原子操作。这些类包括AtomicInteger、AtomicLong、AtomicBoolean等,它们分别提供了对int、long、boolean等基本数据类型的原子操作。三、AtomicIntegerAtomicInteger类提供了对int类型的原子操作。它提供了诸如增加、减少、设置、获取并设置等操作,这些操作都是线程安全的。3.1 使用案例import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerExample { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); // 原子性地增加并返回新的值 } public int getCount() { return count.get(); // 原子性地获取当前值 } public static void main(String[] args) { AtomicIntegerExample example = new AtomicIntegerExample(); // 模拟多线程环境 for (int i = 0; i < 1000; i++) { new Thread(() -> example.increment()).start(); } // 等待所有线程执行完毕 // ...(此处省略等待所有线程完成的代码) System.out.println("Final count: " + example.getCount()); // 应该接近1000 } }在上面的例子中,多个线程同时调用increment()方法来增加count的值,由于incrementAndGet()是原子操作,因此不会出现线程安全问题。四、AtomicLongAtomicLong类提供了对long类型的原子操作,其使用方式与AtomicInteger类似。4.1 使用案例import java.util.concurrent.atomic.AtomicLong; public class AtomicLongExample { private AtomicLong sequenceNumber = new AtomicLong(0); public long next() { return sequenceNumber.incrementAndGet(); // 原子性地获取并增加下一个序号 } public static void main(String[] args) { AtomicLongExample example = new AtomicLongExample(); // 演示获取几个序号 for (int i = 0; i < 5; i++) { System.out.println("Next sequence number: " + example.next()); } } }五、AtomicBooleanAtomicBoolean类提供了对boolean类型的原子操作,其使用方式与前面的类类似。5.1 使用案例import java.util.concurrent.atomic.AtomicBoolean; public class AtomicBooleanExample { private AtomicBoolean flag = new AtomicBoolean(false); public void toggleFlag() { flag.set(!flag.get()); // 原子性地切换标志位的状态 } public boolean isFlagSet() { return flag.get(); // 原子性地获取标志位的状态 } public static void main(String[] args) { AtomicBooleanExample example = new AtomicBooleanExample(); example.toggleFlag(); // 切换标志位的状态 System.out.println("Is flag set? " + example.isFlagSet()); // 输出: Is flag set? true example.toggleFlag(); // 再次切换标志位的状态 System.out.println("Is flag set? " + example.isFlagSet()); // 输出: Is flag set? false } }在上面的例子中,AtomicBoolean被用来存储一个标志位,通过toggleFlag()方法原子性地切换标志位的状态,并通过isFlagSet()方法原子性地获取标志位的状态。
  • [技术干货] Java中的各种锁
    在Java中,存在多种锁机制和类型,每种锁都有其特定的使用场景。以下是Java中常见的锁类型及其使用场景的列举:内置锁(synchronized)类型:内置于Java语言中的关键字,用于提供互斥访问。使用场景:适用于简单的情况,为方法或代码块提供互斥访问。在需要细粒度锁定的场景中使用,例如保护特定代码段的执行。显示锁(如ReentrantLock)类型:Java标准库中的Lock接口的一个实现,提供了更多的锁定功能。使用场景:需要更高级功能的场景,如尝试锁定、定时锁定和可中断锁定。在需要更细粒度控制锁或需要在等待锁时提供更多控制的情况下使用。读写锁(ReadWriteLock)类型:允许同时读取多个线程,但只允许一个线程进行写操作的锁。使用场景:读多写少的场景,允许多个线程同时读取共享资源,但在写入时提供独占访问。在数据库操作、缓存读取等场景中特别有用。乐观锁与悲观锁类型:乐观锁:认为一个线程去拿数据时不会有其他线程对数据进行更改,适合读操作多的场景。悲观锁:认为一个线程去拿数据时一定会有其他线程对数据进行更改,适合写操作多的场景。使用场景:乐观锁:CAS机制、版本号机制等实现,如AtomicBoolean、AtomicInteger等原子操作类。悲观锁:通过加锁来实现,如synchronized关键字和Lock的实现类。公平锁与非公平锁类型:公平锁:按照请求锁的顺序来获取锁。非公平锁:不保证按照请求锁的顺序来获取锁。使用场景:公平锁:适用于需要确保线程按照请求顺序访问共享资源的场景。非公平锁:在性能要求高且对公平性要求不高的场景下使用。可重入锁与不可重入锁类型:可重入锁:同一个线程可以多次获取同一把锁而不会发生死锁。不可重入锁:一个线程在持有锁的情况下,不能再次获取该锁。使用场景:可重入锁:适用于递归方法或嵌套方法调用中需要加锁的场景。自旋锁类型:尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁。使用场景:适用于同步代码块中的内容执行时间较短的场景,可以减少线程上下文切换的消耗。分段锁类型:将一个大的对象分割成多个小的部分,每个部分独立加锁。使用场景:在处理大数据结构(如哈希表)时,为了提高并发性能,可以使用分段锁来减少锁的竞争。偏向锁类型:针对加锁对象的一种优化手段,当一个线程第一次访问一个对象时,会将该对象设置为偏向自己的状态,后续访问时无需再进行加锁操作。使用场景:在只有一个线程长时间持有锁的情况下,偏向锁可以提高性能。这些锁类型各有特点,选择哪种锁取决于具体的应用场景和需求。在编写多线程程序时,正确选择和使用锁机制对于确保线程安全和提高程序性能至关重要。
  • [技术干货] Java 中 synchronized和Lock的区别
    在Java中,synchronized和Lock都是用于实现线程同步的机制,但它们之间存在一些显著的区别。以下是关于它们的主要区别和速度对比的详细解释:区别实现方式:synchronized是Java的一个关键字,它可以应用于方法或代码块。当使用synchronized时,Java会自动为你管理锁的获取和释放。Lock是Java的一个接口(通常使用ReentrantLock实现),它需要你手动创建锁对象,并显式地调用lock()和unlock()方法来获取和释放锁。粒度:synchronized通常锁定的是整个对象,即当一个线程获得了某个对象的锁后,其他线程无法获得该对象的任何锁。Lock可以实现更细粒度的锁定,例如可以对对象的某个属性或者某一段代码块进行加锁,从而提高并发性能。错误处理:在synchronized块中,如果发生异常,锁会在异常抛出后自动释放。在Lock中,如果发生异常,你需要确保在finally块中手动调用unlock()来释放锁,否则可能导致死锁。锁的类型和特性:synchronized只有一种类型的锁,即互斥锁,它是非公平锁。Lock提供了多种类型的锁,包括公平锁和非公平锁,以及更高级的特性,如可重入性、中断等待获取锁等。性能:synchronized在Java的实现中已经做了很多优化,如偏向锁、轻量级锁和重量级锁,这些优化使得它在低竞争情况下的性能几乎与Lock相当。Lock通常在高竞争环境下表现得更高效,因为它提供了更精细的锁控制,减少了不必要的线程上下文切换和资源浪费。速度对比速度对比的结果可能因具体的测试环境和场景而有所不同。但一般来说,以下是一些可能的结论:在低竞争环境下,synchronized和Lock的性能相差不大,因为synchronized的优化使得它在这种情况下表现得很好。在高竞争环境下,Lock通常比synchronized更高效,因为它提供了更精细的锁控制和更少的线程上下文切换。例如,在参考文章3中,通过一系列测试,作者发现:在单线程环境下,synchronized和Lock的性能相差不大。在多线程环境下,如果竞争复杂,则使用Lock的效率更高;如果竞争简单,则可使用synchronized。总结选择使用synchronized还是Lock取决于具体的应用场景和需求的复杂程度。如果你只需要简单的线程同步,并且竞争不激烈,那么synchronized可能是一个更好的选择,因为它使用起来更简单,且性能也足够好。但如果你需要更复杂的同步机制,如可重入锁、公平锁等,或者在高竞争环境下需要提高性能,那么Lock可能是更好的选择。
  • [技术干货] ThreadLocal 用法详解
    在Spring Boot中,ThreadLocal 是一个Java提供的类,它允许我们创建线程局部变量。这些变量与线程绑定,并且每个线程对其自己的实例拥有其自己的初始值副本。这意味着在一个线程中对该变量的修改不会影响其他线程中的变量。ThreadLocal 的函数声明ThreadLocal 类中有很多方法,但以下是最常用的几个:构造方法:ThreadLocal():创建一个线程局部变量。设置值:public void set(T value):设置当前线程的线程局部变量的值。获取值:public T get():返回此线程局部变量的当前线程的值。如果此线程局部变量是第一次被当前线程访问,并且还没有值,那么将调用其 initialValue() 方法(除非它已经被其他线程设置过值)。移除值:public void remove():移除此线程局部变量的值。如果此线程局部变量再次被当前线程访问,那么它将重新调用其 initialValue() 方法(除非它已经被其他线程设置过值)。初始值:protected T initialValue():返回此线程局部变量的初始值。此方法通常只会被 ThreadLocal 类本身调用,在 get() 方法被首次调用但变量尚未设置时。默认情况下,此方法返回 null,但可以通过继承 ThreadLocal 并重写此方法来自定义初始值。为什么要用到 ThreadLocalThreadLocal 主要用于解决多线程环境中数据共享和隔离的问题。在多线程编程中,有时我们需要在不同线程之间传递数据,但又不想使用线程不安全的共享变量或复杂的同步机制。在这种情况下,ThreadLocal 可以为每个线程提供一个独立的变量副本,从而避免了线程之间的数据竞争和同步问题。实战中的用法假设我们有一个Web应用程序,其中每个请求都需要访问一些与请求相关的数据(如用户ID、语言设置等)。我们可以使用 ThreadLocal 来存储这些数据,以便在请求处理过程中方便地访问它们。以下是一个简单的示例:public class RequestContext { private static final ThreadLocal<String> userIdThreadLocal = new ThreadLocal<>(); public static void setUserId(String userId) { userIdThreadLocal.set(userId); } public static String getUserId() { return userIdThreadLocal.get(); } public static void clear() { userIdThreadLocal.remove(); } } // 在某个过滤器或拦截器中设置用户ID @Component public class UserIdFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String userId = // 从请求中提取用户ID的逻辑 RequestContext.setUserId(userId); try { chain.doFilter(request, response); } finally { RequestContext.clear(); // 确保在请求处理完成后清除ThreadLocal中的数据 } } } // 在服务层或其他组件中访问用户ID @Service public class SomeService { public void doSomething() { String userId = RequestContext.getUserId(); // 获取当前线程的用户ID // ... 执行一些与用户ID相关的操作 ... } }请注意,在使用 ThreadLocal 时要小心内存泄漏。由于 ThreadLocal 的生命周期与线程的生命周期相同,如果线程长时间运行并且 ThreadLocal 变量没有被正确清除(通过调用 remove() 方法),那么这些变量可能会占用大量内存,导致内存泄漏。因此,在请求处理完成后,务必清除 ThreadLocal 中的数据。
  • [其他问题] 请问Java编写的生成三维图形的程序在哪里可以发布?
        我编写了一个有700多行代码的Java程序,已经打包为可以运行的Jar程序,双击运行后可以读取D分区下的建立的“boxs.txt”文件,读取其中的数据生成大小及位置任意设定的长方体,可以设定描边和填充颜色,可以设定透明度,可以旋转长方体,可以根据字符串来排列各个长方体的前后绘制循序,我想将其发布,不知在哪里可以呢?给看看截屏,运行程序读取文本文件的数据和字符串生成了一个桌子,还可以生成较简单的房子以及更为复杂的建筑等等。
  • [技术干货] 正则表达式匹配双引号常用例子总结【转】
    1.正则表达式匹配引号匹配双引号"用\"匹配单引号'用'2.正则表达式匹配正则表达式中用到的特殊符号时需加\\如()[]{}/|\-+匹配[用\\[匹配]用\\]匹配\用\\\\匹配/用\\/匹配|用\\|匹配-用\\-匹配+用\\+匹配大写英文或小写英文或数字或下划线用\\w或0-9a-zA-Z_3.正则表达式中各种扩号()[]{}作用中括号[]表示匹配单个字符,匹配中扩号里列出的任意一个字符1[dsa]//匹配d或s或a小括号()表示匹配字符串,匹配小扩号里列出的所有字符构成的字符串1(dsaff) //仅能匹配dsaff大括号{}表示匹配的次数,放于()或[]之后1[dsa]{1,8}//匹配1-8次[dsa],如匹配d,dd,dddddddd1(dsa){1,8}//匹配1-8次(dsa),如匹配dsa,dsadsadsadsadsadsadsadsa4.常用匹配例子例子(匹配英语键盘上的任意非空字符)12345QRegExp re("^[\\w~!@#$%^&*()+`={}:;<>?,.|'\"\[\\]\\-\\/\\\\]+$");   QString test("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`1234567890-=~!@#$%^&*()_+[]{}|;:'\"\\/,.<>?");bool match = re.exactMatch(test);  //match=true例子(匹配任意合法表示的有理数)12345QRegExp reg("^(\\-(?!0(?!\\.))|\\+(?!0(?!\\.)))?(0|[1-9]\\d*)(\\.\\d+)?$");    QString test("41424.4155346");bool match = re.exactMatch(test);  //match=true例子(匹配任意合法表示的非负有理数)12345QRegExp reg("^(\\+(?!0(?!\\.)))?(0|[1-9]\\d*)(\\.\\d+)?$");    QString test("41424.4155346");bool match = re.exactMatch(test);  //match=true例子(匹配任意合法表示的正有理数)12345QRegExp reg("^(\\+)?(0(?=\\.)|[1-9]\\d*)(\\.\\d+)?$");    QString test("41424.4155346");bool match = re.exactMatch(test);  //match=true例子(匹配任意合法表示的整型数字)12345QRegExp reg("^(\\-(?!0)|\\+(?!0))?(0|[1-9]\\d*)$");   QString test("414246");bool match = re.exactMatch(test);  //match=true例子(匹配任意合法表示的非负整型数字)12345QRegExp reg("^(\\+(?!0))?(0|[1-9]\\d*)$");    QString test("414246");bool match = re.exactMatch(test);  //match=true例子(匹配任意合法表示的正整型数字)12345QRegExp reg("^(\\+)?([1-9]\\d*)$");    QString test("414246");bool match = re.exactMatch(test);  //match=true例子(匹配任意合法表示的密码)123456789QRegExp reg("^[\\w~!@#$%^&*()+`={}:;<>?,.|'\"\[\\]\\-\\/\\\\]+$");        if (!reg.exactMatch(value.data())) {            message_ =                QObject::tr("The password can only contanin numbers, English "                            "characters or special characters  ")                    .toStdString();            return false;        }        return true;
  • [技术干货] java integer引用_JAVA中Integer对象的引用
    JAVA中没有指针一说,但也有引用的概念。这里要说的主要是Integer是不是同一个对象。 1、先看一段代码: public static void main(String[] args){ Integer a1 = 100; Integer b1 = a1;//另一种也可以b1=100 Field field = null; try { field = a1.getClass().getDeclaredField("value"); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); }field.setAccessible(true); try { field.set(a1, 5000); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("b1="+b1); Integer c1 = 100; System.out.println("c1="+c1); } 结果: b1=5000 c1=5000 从上面,首先这里要说明几个, 1)、对于Integer来说,-128-127之间的整型已经初始化放在IntegerCache中,如果是装箱的话,就会从这里面取对象。 2)、b1=a1到底是数字赋值还是同一个对象?这个从结果实际就可以看出来,b1和a1指向同一个对象,而不是同一个数值 3)、c1=100,说明对于-128-127之间的数值,都是从IntegerCache中获取的对象,100对应的Integer对象被改变后,后续对于100的装箱都被改变。因为获取cache中对象时用的是数组索引,而不是数值比较获取的。 不过修改这个缓存会比较危险,不介意。谁知道什么jar包或者什么平台来个100的装箱,但得到结果又不是100,到时就崩溃了。 2、通过上面描述,那么如果改成这样又是什么答案 public static void main(String[] args){ Integer a1 = 200; Integer b1 = a1; Field field = null; try { field = a1.getClass().getDeclaredField("value"); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } field.setAccessible(true); try { field.set(a1, 5000); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("b1="+b1); Integer c1 = 200; System.out.println("c1="+c1);  }  3、那么再改一下 public static void main(String[] args){ Integer a1 = new Integer(100); Integer b1 = a1; Field field = null; try { field = a1.getClass().getDeclaredField("value"); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); }  field.setAccessible(true); try { field.set(a1, 5000); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block  e.printStackTrace(); } catch (IllegalAccessException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  System.out.println("b1="+b1); Integer c1 = 100; System.out.println("c1="+c1); }这又是什么答案。对于new的操作,是不进行装箱的,而是在堆中生成对象的。 理解了装箱、缓存、引用就不难理解了。可以自己试试。 ————————————————            原文链接:https://blog.csdn.net/weixin_39637919/article/details/114523910 
  • [技术干货] java常用类---包装类(引用数据类型)Integer详解
    java八种基本数据类型分为四类八种 四类分别为整型、浮点型、布尔型、字符型; 八种分别为byte、short、int、long、float、double、boolean、char;  java八种基本数据类型的字节数 分别为1、2、4、8个字节;1字节(byte、boolean)、 2字节(short、char)、4字节(int、float)、8字节(long、double);  整数的默认类型为int,浮点数的默认类型为double; 八种基本数据类型的包装类:除了char的是Character、int类型的是Integer,其他都是首字母大写 关于值的范围问题,需要注意char类型是无符号的,不能为负,所以是0开始的 二、引用数据类型 1.数组 2.接口 3.类 正文 一、包装类(Integer) 1.所在包位置 2.类继承关系 3.接口实现关系 4.final修饰(不能有子类不能被继承) 5.包装类是对基本数据类型的封装        Integer 类在对象中包装了一个基本类型 int 的值。Integer 类型的对象包含一个 int 类型   的字段 1.装箱 基本数据类型------》包装类 int-----》integer 2. 拆箱 包装类------》基本数据类型 integer---int 6.构造器(有参)  1.底层源码分析 1.根据Integer(int value)有参构造器编写代码如下  public class Test01 {         public  static void main(String [] arge){                 Integer integer=new Integer(10);//实例化传入参数         System.out.println(integer.toString());     }  } Integerl类的有参构造方法  public Integer(int value) {     this.value = value;     } Integer类final修饰的属性  private final int value; 总结 根据Integer类的有参构造方法(Integer(int value))进行实例化(new Integer(10))然后根据Integer类有参构造方法接收value值并且赋予给final修饰的int变量 归根接地Integer的底层就是int 2.根据Integer(String s)有参构造器分析 ———————————————— 原文链接:https://blog.csdn.net/m0_67929156/article/details/124162285 
总条数:696 到第
上滑加载中