MXBLOG - java
type: channel
link: https://www.moonjer.com/category/java/
items: 解决Docker容器中MySQL连接因LANG环境变量缺失导致的问题
items: Java面试一
items: 【MacOS】安装JDK并配置环境变量
items: java生成签名过程
items: docker搭建maven私有仓库
items: java实现WebSocket服务端
items: Java实现WebSocket服务
items: java分割String字符串成list
items: ExcelUtils.java
items: Andorid Studio问题“gradle sync failed”

解决Docker容器中MySQL连接因LANG环境变量缺失导致的问题
type: item
date: 2025-08-27T15:29:00+08:00
description: 解决Docker容器中MySQL连接因LANG环境变量缺失导致的问题问题描述在使用Docker容器部署Spring Boot应用时，遇到以下错误：java.lang.IllegalStateException: DBAppender cannot function if the JDBC driver does not support getGeneratedKeys method *and* without a specific SQL dialect环境信息：Docker容器：基于Ubuntu 22.04，运行宝塔面板数据库：MySQL 8.0.26（独立容器）应用：Spring Boot + Logback + MySQL Connector 8.0.16关键发现：同样的JAR包在虚拟机上运行正常，在容器中无法启动快速解决方案根本解决方案（推荐）：apt-get update && apt-get install -y locales && locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8 && export LANG=en_US.UTF-8 && export LC_ALL=en_US.UTF-8 && echo 'export LANG=en_US.UTF-8' >> ~/.bashrc && echo 'export LC_ALL=en_US.UTF-8' >> ~/.bashrc && source ~/.bashrc临时解决方案（连接参数）：在数据库连接URL中添加：allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8spring: datasource: url: jdbc:mysql://127.0.0.1:3306/your_database?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8或者在启动容器时添加环境变量：docker run -d \ --name your-container \ --net=host \ --restart always \ --privileged \ -e LANG=C.UTF-8 \ -e LC_ALL=C.UTF-8 \ your-image:tag详细排查过程初期错误理解最初看到错误信息，以为是Logback配置问题，尝试了多种方案：取消注释SQL方言配置 ❌<sqlDialect class="ch.qos.logback.core.db.dialect.MySQLDialect"/>使用DriverManagerConnectionSource ❌升级/降级Logback版本 ❌使用HikariCP替代Commons DBCP ❌暂时禁用DBAppender ✅（临时方案，不是根本解决）转换思路：环境差异分析经过两天的配置调试无果后，开始从环境角度分析问题。1. Java版本对比# 容器和虚拟机都是相同版本 java version "1.8.0_381" Java(TM) SE Runtime Environment (build 1.8.0_381-b09)2. 环境变量对比容器环境：JAVA_HOME=/home/root/soft/jdk1.8.0_381 PATH=/home/root/soft/jdk1.8.0_381/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin # 缺失 LANG 和 LC_* 变量虚拟机环境：JAVA_HOME=/home/root/soft/jdk1.8.0_381 LANG=en_US.UTF-8 # 关键差异！ PATH=/home/root/soft/jdk1.8.0_381/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin3. MySQL驱动行为测试创建测试程序验证MySQL驱动的getGeneratedKeys支持：import java.sql.*; public class TestMySQLDriver { public static void main(String[] args) { try { Class.forName("com.…

Java面试一
type: item
date: 2024-11-11T16:41:38+08:00
description: 面试概况本次面试为快手商业化部门日常实习生的一轮面试，面试时长约为40分钟。面试内容主要集中在Java基础知识、数据库、并发编程、算法等方面。以下是详细的面试问题及回答整理。面试问题及回答1. Java 的集合类知道哪些？Java 的集合类主要分为以下几类：List：有序集合，允许重复元素。常见实现类有 ArrayList、LinkedList、Vector。Set：不允许重复元素的集合。常见实现类有 HashSet、LinkedHashSet、TreeSet。Map：键值对集合，键唯一但值可以重复。常见实现类有 HashMap、LinkedHashMap、TreeMap、Hashtable、ConcurrentHashMap。Queue：队列集合，支持 FIFO（先进先出）操作。常见实现类有 LinkedList、PriorityQueue、ArrayDeque。2. 说说 HashMap？HashMap 是 Java 中常用的集合类，基于哈希表实现，允许存储键值对。其主要特点如下：无序存储：HashMap 不保证元素的顺序。允许空键和空值：但最多只能有一个空键。线程不安全：在多线程环境下使用 HashMap 可能会导致数据不一致。时间复杂度：插入、删除、查找操作的时间复杂度均为 O(1)（理想情况下）。3. HashMap 线程安全吗，如何变线程安全？HashMap 本身是线程不安全的。可以通过以下几种方式使其线程安全：使用 Collections.synchronizedMap：将 HashMap 包装成线程安全的 Map。Map<String, String> map = Collections.synchronizedMap(new HashMap<>());使用 ConcurrentHashMap：ConcurrentHashMap 是线程安全的 Map 实现，性能优于 Hashtable。Map<String, String> map = new ConcurrentHashMap<>();手动同步：在访问 HashMap 的地方手动加锁。synchronized (map) { map.put(key, value); }4. ConcurrentHashMap 如何实现的？ConcurrentHashMap 通过分段锁（Segment）机制实现线程安全。具体实现如下：分段锁：将整个哈希表分成多个段（Segment），每个段内部是一个小的哈希表。锁粒度：每次操作只锁定当前段，而不是整个哈希表，提高了并发性能。JDK 1.8 改进：取消了 Segment，改为使用 CAS 操作和锁竞争机制，进一步提高了性能。5. synchronized 原理以及升级过程synchronized 是 Java 中的内置锁，用于实现线程同步。其原理如下：锁的状态：锁有四种状态，依次是无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。锁升级：锁可以从较低状态升级到较高状态，但不能降级。无锁状态：没有任何线程持有锁。偏向锁：偏向于第一个获取锁的线程，减少锁的竞争。轻量级锁：使用 CAS 操作尝试获取锁，如果失败则升级为重量级锁。重量级锁：使用操作系统互斥量实现，性能较差。6. 线程池的参数？ThreadPoolExecutor 是 Java 中创建线程池的类，其构造方法参数如下：corePoolSize：核心线程数。maximumPoolSize：最大线程数。keepAliveTime：线程空闲时间。unit：keepAliveTime 的时间单位。workQueue：任务队列，用于存储等待执行的任务。threadFactory：线程工厂，用于创建线程。handler：拒绝策略，当任务队列满且线程数达到最大值时的处理策略。7. full gc, minor gc?Minor GC：回收年轻代（Young Generation）的垃圾收集操作。当年轻代空间不足时触发。Full GC：回收整个堆（包括年轻代和老年代）的垃圾收集操作。通常在以下情况下触发：老年代空间不足。系统显式调用 System.gc()。Minor GC 时发现老年代空间不足。8. 垃圾回收算法？常见的垃圾回收算法有：标记-清除：标记所有需要回收的对象，然后清除这些对象。标记-整理：标记所有需要回收的对象，然后将存活对象移动到一端，清除边界外的对象。复制：将内存分为两个区域，每次只使用其中一个区域，将存活对象复制到另一个区域。分代收集：将内存分为年轻代和老年代，分别使用不同的回收算法。9. CPU 密集型和 IO 密集型下如何设置核心线程数？CPU 密集型：任务主要消耗 CPU 资源，核心线程数一般设置为 CPU 核心数 + 1。int corePoolSize = R…

【MacOS】安装JDK并配置环境变量
type: item
date: 2023-10-31T02:05:00+08:00
description: JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home PATH=$JAVA_HOME/bin:$PATH //给环境变量赋值 export JAVA_HOME //导出使其生效 export PATH 参考链接：https://blog.csdn.net/m0_51520179/article/details/131295356

java生成签名过程
type: item
date: 2022-12-16T17:24:45+08:00
description: set PATH=%PATH%;"D:\Program Files\Java\jre1.8.0_25\bin" keytool -genkey -alias testapp -keyalg RSA -keysize 2048 -validity 36500 -keystore testapp.keystore Enter keystore password: //testapp1992 Re-enter new password: //testapp1992 What is your first and last name? [Unknown]: //testapp What is the name of your organizational unit? [Unknown]: //starg What is the name of your organization? [Unknown]: //starg What is the name of your City or Locality? [Unknown]: //xiamen What is the name of your State or Province? [Unknown]: //xiamen What is the two-letter country code for this unit? [Unknown]: //CN Is CN=XX, OU=XX, O=XX, L=XX, ST=XX, C=XX correct? [no]: //确认上面输入的内容是否正确，输入y，回车 Enter key password for <testalias> (RETURN if same as keystore password): //确认证书密码与证书文件密码一样（HBuilder|HBuilderX要求这两个密码一致），直接回车就可以 keytool -list -v -keystore testapp.keystore 别名: testapp 创建日期: 2021-8-4 条目类型: PrivateKeyEntry 证书链长度: 1 证书[1]: 所有者: CN=testapp, OU=starg, O=starg, L=xiamen, ST=xiamen, C=CN 发布者: CN=testapp, OU=starg, O=starg, L=xiamen, ST=xiamen, C=CN 序列号: 18728bc0 有效期开始日期: Wed Aug 04 10:30:32 CST 2021, 截止日期: Fri Jul 11 10:30:32 CST 2121 证书指纹: MD5: B4:14:19:EA:7A:D4:8F:E4:AB:D7:E9:04:11:C7:EB:7D SHA1: 46:6E:CA:FA:58:45:05:29:5E:FF:00:D0:53:A0:D6:45:B4:63:B4:CB SHA256: 91:8C:A9:14:E2:77:27:C6:36:EE:AC:DD:D6:08:22:2F:95:77:9A:63:E2:CE:34:A1:38:6C:F5:CF:13:31:9B:22 签名算法名称: SHA256withRSA 版本: 3 扩展: #1: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: FF ED 61 5C 25 46 D5 40 30 1C 5D FA B8 D9 8C 8A ..a\%F.@0.]..... 0010: AD 72 4D 0D .rM. ] ] ******************************************* *******************************************

docker搭建maven私有仓库
type: item
date: 2022-12-13T09:48:00+08:00
description: （一）引言在实际开发工作中，通常需要搭建maven私有仓库。（二）Nexus介绍 Nexus 是Maven仓库管理器，如果你使用Maven，你可以从Maven中央仓库 下载所需要的构件（artifact），但这通常不是一个好的做法，你应该在本地架设一个Maven仓库服务器，在代理远程仓库的同时维护本地仓库，以节省带宽和时间，Nexus就可以满足这样的需要。此外，他还提供了强大的仓库管理功能，构件搜索功能，它基于REST，友好的UI是一个extjs的REST客户端，它占用较少的内存，基于简单文件系统而非数据库。这些优点使其日趋成为最流行的Maven仓库管理器。（三）安装docker请参考 Docker安装_Icoolkj的博客（四）docker中安装nexus31、拉取镜像## 通过docker search nexus 命令搜索一下docker公有库在的 nexus相关的镜像 [root@icoolkj ~]# docker search nexus## 拉取nexus3镜像 [root@icoolkj /]# docker pull sonatype/nexus3 Using default tag: latest latest: Pulling from sonatype/nexus3 f70d60810c69: Pull complete 545277d80005: Pull complete 10b49635409a: Pull complete Digest: sha256:3fd7e90bcf49fb55d87d852cab854e5669ed115b09bdb25f47c45ee0797231aa 147.6MB/295.3MB Status: Downloaded newer image for sonatype/nexus3:latest docker.io/sonatype/nexus3:latest [root@icoolkj /]# 2、建立数据储存文件夹## 建立数据存放文件夹，用于docker中nexus的数据与本地物理机映射 [root@icoolkj /]# mkdir -p /usr/local/nexus3/nexus-data [root@icoolkj /]# ll /usr/local/nexus3/ 总用量 4 drwxr-xr-x 2 root root 4096 6月 3 18:06 nexus-data ## 更改权限 [root@icoolkj /]# chmod 777 /usr/local/nexus3/nexus-data/ [root@icoolkj /]# ll /usr/local/nexus3/ 总用量 4 drwxr-xr-x 2 777 root 4096 6月 3 18:06 nexus-data [root@icoolkj /]# 3、安装并运行容器## 编写启动脚本docker-nexus3-start.sh docker rm -f docker-nexus3 || true docker run --name docker-nexus3 \ -p 8081:8081 \ -v /usr/local/nexus3/nexus-data:/nexus-data \ --restart=always \ -d sonatype/nexus3 ## 参数说明 --name nexus #启动该容器的名字，可以自己更改为自己想要的名字 -p 8081:8081 #端口映射，将本地8081端口映射为容器的8081端口,第一个8081可以改成自己想要放开的端口 -v /docker/nexus/nexus-data:/nexus-data # 将容器的/nexus-data地址 代理到 本地/docker/nexus/nexus-data文件夹下 --restart=always #在重启docker时，自动重启改容器。 -d sonatype/nexus3 #即为后台运行一直sonatype/nexus34、获取容器的日志[root@icoolkj nexus3]# docker logs -f --tail 20 docker-nexus3（五）使用nexus31、浏览器访问2、配置Nexus提示输入密码，并告知你的密码储存位置Your admin user password is located in /nexus-data/admin.password on the server.因为docker中nexus3的数据储存位置与本地物理机建立了映射关系，所有在物理机上的地址应该是/usr/local/nexus3/nexus-data/admin.pass…

java实现WebSocket服务端
type: item
date: 2022-12-12T17:23:00+08:00
description: WebSocket服务端配置类import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Service; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.server.standard.ServerEndpointExporter; /** * websocket配置类 * @author daiyg * @date 2021/8/24 17:19 */ @Service @Configuration @EnableWebSocket public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }服务端代码import com.caso.common.core.utils.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; /** * @author daiyg * @date 2021/8/24 18:15 */ @Component @ServerEndpoint(value = "/websocket/{id}/{key}", subprotocols = {"protocol"}) public class WebSocketServer { private static int onlineCount = 0; private static ConcurrentHashMap<String, WebSocketServer> webSocketSet = new ConcurrentHashMap<>(); private static ConcurrentHashMap<String, List<String>> map = new ConcurrentHashMap<>(); //与某个客户端的连接会话，需要通过它来给客户端发送数据 private Session session; private static Logger log = LogManager.getLogger(WebSocketServer.class); private String id = ""; private String key= ""; /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(@PathParam(value = "id") String id,@PathParam("key") String key, Session session) { this.session = session; this.id = id;//接收到发送消息的人员编号 this.key = key; if ("1".equals(id)) { log.info("非门岗用户连接！"); } else { List<String> ids = new ArrayList<>(); ids = map.get(id); if(StringUtils.isEmpty(ids)){ ids = new ArrayList<>(); } ids.add(key); map.put(id,ids); webSocketSet.put(key, this); //加入set中 } addOnlineC…

Java实现WebSocket服务
type: item
date: 2022-12-12T17:16:00+08:00
description: 一、使用Tomcat提供的WebSocket库 Java可以使用Tomcat提供的WebSocket库接口实现WebSocket服务，代码编写也非常的简单。现在的H5联网游戏基本上都是使用WebSocket协议，基于长连接，服务器可以主动推送消息，而不是传统的网页采用客户端轮询的方式获取服务器的消息。下面给出简单使用Tomcat的WebSocket服务的基本代码结构。@ServerEndpoint("/webSocket") public class WebSocket { @OnOpen public void onOpen(Session session) throws IOException{ logger.debug("新连接"); } @OnClose public void onClose(){ logger.debug("连接关闭"); } @OnMessage public void onMessage(String message, Session session) throws IOException { logger.debug("收到消息"); } @OnError public void onError(Session session, Throwable error){ error.printStackTrace(); } }二、WebSocket协议的整个流程1. 基于TCP协议WebSocket本质是基于TCP协议的，采用Java编写WebSocket服务时可以使用NIO或者AIO实现高并发的服务。2. 握手过程客户端采用TCP协议连接服务器指定端口后，首先需要发送一条HTTP的握手协议GET /web HTTP/1.1 Upgrade: websocket Connection: Upgrade Host: 127.0.0.1:8001 Origin: http://127.0.0.1:8001 Sec-WebSocket-Key: hj0eNqbhE/A0GkBXDRrYYw== Sec-WebSocket-Version: 13请求的头里面必须包含以下内容：Connection 其值为Upgrade，表示升级协议Upgrade 其值为websocket，表示升级为WebSocket协议Sec-WebSocket-Key 客户端发送给服务器的密钥，用于标识每个客户端，其值是16位的随机base64编码。Sec-WebSocket-Version WebSocket的协议版本服务器收到这条协议验证成功后进行协议升级，并且不会关闭Socket连接，并发送给客户端响应升级握手成功的HTTP协议包。HTTP/1.1 101 Switching Protocols Content-Length: 0 Upgrade: websocket Sec-Websocket-Accept: ZEs+c+VBk8Aj01+wJGN7Y15796g= Connection: Upgrade Date: Wed, 21 Jun 2017 03:29:14 GMT 响应的协议包里面，首先是101的状态码，更换协议；其中最重要的就是Sec-WebSocket-Accept字段。其值是通过客户端的Key加上固定的"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"密钥，通过采用16位的base64编码后发送给客户端验证，如果客户端也验证成功就表示握手完成。String acc = secKey + WEBSOCK_MAGIC_TAG; MessageDigest sh1 = MessageDigest.getInstance("SHA1"); String key = Base64.getEncoder().encodeToString(sh1.digest(acc.getBytes()));3. 数据的读写握手成功后就可以进行数据发送和读取，WebSocket的数据可以是二进制或者纯文本。每次读取和发送数据需要打包成帧数据，需要按照其标准的格式进行发送或读取才能够正常的进行数据通信。上图就是帧数据的结构图，解析帧数据的代码如下，由于是摘录的部分代码，所以只能作为理解和参考，不可直接使用。protected WebSocketFrameData ParseFrame(NetPacketBuffer bytes){ bytes.mark(); WebSocketFrameData frame = new WebSocketFrameData(); int opData = bytes.readByte(); frame.UnPackOpCodeHeader(opData); // 第一步 int le…

java分割String字符串成list
type: item
date: 2022-08-17T18:09:03+08:00
description: String sn = “1234,567,8910”; List<String> snList = Arrays.asList(sn.split(","));

ExcelUtils.java
type: item
date: 2022-03-27T17:43:01+08:00
description: package com.landicorp.cash.util; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.DecimalFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.beanutils.BeanMap; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.DataFormat; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import com.landicorp.core.util.common.DateUtil; import com.landicorp.core.util.export.annotations.CollectionExcelTarget; import com.landicorp.core.util.export.annotations.ExcelField; public class ExcelUtil { private Workbook workbook; private OutputStream os; private String pattern;// 日期格式 public void setPattern(String pattern) { this.pattern = pattern; } public ExcelUtil(Workbook workboook) { this.workbook = workboook; } public ExcelUtil(InputStream is, String version) throws FileNotFoundException, IOException { if ("2003".equals(version)) { workbook = new HSSFWorkbook(is); } else { workbook = new XSSFWorkbook(is); } } public String toString() { return "共有 " + getSheetCount() + "个sheet 页！"; } public String toString(int sheetIx) throws IOException { return "第 " + (sheetIx + …

Andorid Studio问题“gradle sync failed”
type: item
date: 2021-11-28T17:37:18+08:00
description: 1.选择gradleAndroid Studio安装后可能会出现gradle sync failed错误首先打开设置界面（Ctrl+Alt+S）选择 Build,Execution,Deployment选择Gradle重新设置你的Service directory path目录安装Android Studio时默认会安装Gradle在 "C:/Users/用户名/.gradle" 此路径下，你只需要把 Service directory path 的路径修改为更详细点就可以了（eg:C:/Users/EraJi/.gradle/wrapper/dists/gradle-4.4-all）。直接指定路径中的 gradle 文件夹。你也可以自己下载对应版本的Gradle，然后把这个路径指向你下载好的Gradle目录。下载地址：这里就不细讲了，其实我弄不太懂重新编译下工程就可以了2.检查Jdk选择自带的jdk11或者默认的jdk83.sdk设置在目录 D:\\{YOUR_SDK_PATH}\Android\Sdk\tools\bin 执行命令sdkmanager --licenses一路选择 yes