Java随记

这篇博客详细介绍了Java开发中的实用技巧,包括保留两位小数的方法、基本数据类型和分页查询的实现。此外,还深入探讨了websocket实时通信、excel导入导出以及程序运行内存管理。在数据库方面,讲解了存储过程、触发器、定时任务的配置以及数据库连接池的使用。此外,还涵盖了Mybatis和Spring的相关操作,以及Git和Docker的基础应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

Java

java保留两位小数

基本数据类型

分页查询

websocket实时通信

excel导入导出

随机数

调用第三方接口

Java API

Apache HttpClient

 POST请求:

GET请求:

多线程

同步机制

synchronized

ReentrantLock

ThreadLocal

ConcurrentLinkedQueue

工具

hutool构建树形结构

日志

数据库

MySQL

配置项

导入导出

存储过程

触发器

定时任务

Oracle

存储过程

定时任务

导入导出

配置druid数据库连接池

数据库日期字符串转换

SQL判空

聚合数据

递归树形层次查询

修改字段名和字段类型

插入数据将自增id赋值给实体的id属性

mysql中varchar和 text的区别

JDBC操作

MySQL数据类型

Mybatis

批量操作

批量更新

批量插入

参数类型设置typeAliasesPackage

增删改查

查询返回数组集合

映射map类型的属性值

查询结果包含双list集合

查询结果包含实体对象association

Spring

加载配置文件yml

工具类中获取配置类

SpringBoot

多数据源

系统启动和关闭钩子

Git

初始化提交

docker

docker离线安装容器方法

程序部署

一些bug 


Java

java保留两位小数

1、使用String.format()方法:

public static void stringFormatdecimalFormatKeepTwoDecimalPlaces(){
        double number = 3.1415926;
        String result = String.format("%.2f", number);
        System.out.println(result);
    }

输出:3.14

2、BigDecimal保留两位小数

import java.math.BigDecimal;

public static void bigdecimalKeepTwoDecimalPlaces(){
        double number = 3.1415926;
        BigDecimal decimal = new BigDecimal(number);
        BigDecimal rounded = decimal.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println(rounded);
    }

输出:3.14

3、使用DecimalFormat类:

public static void decimalFormatKeepTwoDecimalPlaces(){
        double number = 3.1415926;
        DecimalFormat decimalFormat = new DecimalFormat("#.00");
        String result = decimalFormat.format(number);
        System.out.println(result);
    }

输出:3.14

基本数据类型

/**
 * 基本数据类型,在定义的时候根据不同的类型在内存中分配不同的大小进行存储。
 *
 *
 * 整数:
 *      byte(1字节byte=8位)
 *      1000 0000 ~ 01111111 最高位是符号位0表示正 1表示负
 *      byte值的范围:-128 ~ 127
 *
 *
 *      short(2字节) -32768~32767
 *
 *      \ int(4字节) -2,147,483,648 ~ 21 4748 3647(21亿多)
 *
 *      \ long(8字节)
 *
 * 浮点型:
 *      float(4字节) 定义float类型变量时,变量要以"f"或"F"结尾
 *      单精度浮点数 提供大约6-7位的有效数字。
 *
 *      \ double(8字节)
 *      双精度浮点数 提供大约15-16位的有效数字。
 *      推荐使用double,因为现代计算机硬件通常更擅长处理双精度浮点数。
 *
 *      简单来说double精度更高,可以表示更细的浮点数,通俗的讲就是小数点后面可以表示更多的数字。
 *
 * 布尔型:
 *      boolean(1字节)
 *
 * 字符型:
 *      char(2字节)
 *
 *
 */


/**
     * 运算
     *
     * 整数除法运算,结果是取整
     * 浮点数除整数 结果为 浮点数
     * 整数 除 浮点数 结果为 浮点数
     *
     * 文件大小 23435.12 MB
     *
     * 速率 = 文件大小 / 用时
     * 用时
     */
    @Test
    public void test3(){
        int fileSizeB = 46960880; // 44.7 MB
        int fileSizeMB = fileSizeB / 1024 / 1024;
        System.out.println(fileSizeMB);// 44 整数除整数结果也是取整

        double fileSizeMB1 = fileSizeB / 1024 / 1024;
        System.out.println(fileSizeMB1); // 44.0 只是将整数赋值给了一个浮点数double

        double fileSizeB1 = 46960880;
        double fileSizeMB2 = fileSizeB1 / 1024 / 1024;
        System.out.println(fileSizeMB2);// 44.78538513183594 浮点数除整数 结果为 浮点数

        // 结果保留一位小数
        System.out.println(String.format("%.1f", fileSizeMB2));// 44.8 会自动四舍五入

        DecimalFormat decimalFormat = new DecimalFormat("#.0");
        System.out.println(decimalFormat.format(fileSizeMB2));// 44.8 会自动四舍五入

        // 向下截断小数部分
        System.out.println(Math.floor(fileSizeMB2));// 44.0

        // 向上截断小数部分
        System.out.println(Math.ceil(fileSizeMB2));// 45.0

        // 保留一位小数,不进行四舍五入
        System.out.println((int) (fileSizeMB2 * 10));
        double truncatedNumber = (int) (fileSizeMB2 * 10) / 10.0; // 整数 除 浮点数 结果为 浮点数
        System.out.println(truncatedNumber);// 44.7


        int mil = 23435; // 毫秒
        double second = mil / 1000.0;
        System.out.println(second);

        double speed = (int)((fileSizeMB2 / second) * 10) / 10.0;
        System.out.println(speed + " MB/S");// 1.9 MB/S
    }

分页查询

https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md

        <!--分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>

yml配置

pagehelper:
  helperDialect: mysql或者oracle
  supportMethodsArguments: true
  params: count=countSql
  • helperDialect: mysql:指定了数据库方言为 MySQL。
  • supportMethodsArguments: true:开启了支持方法参数,允许在方法中传递参数进行分页。
  • params: count=countSql:通过传递 count 参数来执行 countSql,这通常是用于执行查询总记录数的 SQL。
// 分页
if(highSearchVO.getPageNo() != null) PageHelper.startPage(highSearchVO.getPageNo(),highSearchVO.getPageSize());
List<Map<String, Object>> maps = dynamicDataRetrievalMapper.highSearch(highSearchVO);

在需要分页查询之前调用PageHelper.startPage设置,会自动limit

websocket实时通信

业务中,客户端和服务端经常需要实时返回一些状态等消息,现总结一下websocket实时通信用法。

服务端

服务端一般用来接收客户端的ws连接,然后给客户端发送消息,不能主动发送连接。

<!--ws-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 开启WebSocket
 */
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
package com.lin.ws;

/**
 *
 */
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lin.entity.vo.UploadMsgVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import javax.swing.Timer;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
@ServerEndpoint("/webSocket/{topic}")
@Slf4j
public class WebSocketServer {
    private Session session;
    private String topic;
    /**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
    private static int onlineCount = 0;
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();

    private static List<UploadMsgVO> uploadMsgList = new ArrayList<>(3);

    private javax.swing.Timer timer = new Timer(3000, e -> {
        sendMessage(JSONObject.toJSONString(uploadMsgList),"upload");
        uploadMsgList.clear();
    });

    /**
     * concurrent包的线程安全set,用来存放每个客户端对应的MyWebSocket对象
     */
    private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap();

    /**
     * 保存ws会话
     * 为了保存在线用户信息,在方法中新建一个list存储一下【实际项目依据复杂度,可以存储到数据库或者缓存】
     */
    private final static List<Session> SESSIONS = Collections.synchronizedList(new ArrayList<>());

    /**
     * 建立连接
     *  ws://192.168.31.47:9988/webSocket/{topic}
     * 当客户端发送: ws://192.168.31.47:9988/webSocket/upload ws请求,就可以和这个ws服务端建立ws连接了。
     *
     * @param session ws连接会话
     * @param topic ws连接主题
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("topic") String topic) {
        this.session = session;
        this.topic = topic;
        webSocketSet.add(this);
        SESSIONS.add(session);
        if (webSocketMap.containsKey(topic)) {
            webSocketMap.remove(topic);
            webSocketMap.put(topic,this);
        } else {
            webSocketMap.put(topic,this);
            addOnlineCount();
        }

        if("upload".equals(topic)) timer.start();
        // log.info("【websocket消息】有新的连接, 总数:{}", webSocketSet.size());
        log.info("[连接topic:{}] 建立连接, 当前连接数:{}", this.topic, webSocketMap.size());
        System.out.println(this);
    }

    /**
     * 断开连接
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        if (webSocketMap.containsKey(topic)) {
            webSocketMap.remove(topic);
            subOnlineCount();
        }

        if("upload".equals(topic)) timer.stop();
        // log.info("【websocket消息】连接断开, 总数:{}", webSocketSet.size());
        log.info("[连接topic:{}] 断开连接, 当前连接数:{}", topic, webSocketMap.size());
    }

    /**
     * 发送错误
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("[连接topic:{}] 错误原因:{}", this.topic, error.getMessage());
        error.printStackTrace();
    }

    /**
     * 收到消息
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        // log.info("【websocket消息】收到客户端发来的消息:{}", message);
        log.info("[连接topic:{}] 收到消息:{}", this.topic, message);

        UploadMsgVO uploadMsgVO = null;
        try {
            uploadMsgVO = JSON.parseObject(message, UploadMsgVO.class);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (uploadMsgVO != null) {
            int index = uploadMsgList.indexOf(uploadMsgVO);
            if(index == -1) uploadMsgList.add(uploadMsgVO);
            else uploadMsgList.set(index,uploadMsgVO);
        }

//        sendMessage(uploadMsgList.toString(),"upload");
    }

    /**
     * 发送消息
     * @param message 消息
     * @param topic 接收消息的主题(只要订阅这个主题都会收到消息)
     */
    public void sendMessage(String message,String topic) {
        WebSocketServer webSocketServer = webSocketMap.get(topic);
        if (webSocketServer!=null){
            log.info("【websocket消息】推送消息, message={}", message);
            try {
                webSocketServer.session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("[连接topic:{}] 发送消息失败, 消息:{}", this.topic, message, e);
            }
        }
    }

    /**
     * 发送object消息
     * @param message
     * @param topic
     */
    public void sendObjectMessage(Object message,String topic) {
        WebSocketServer webSocketServer = webSocketMap.get(topic);
        if (webSocketServer!=null){
            log.info("【websocket消息】推送消息, message={}", message);
            try {
                webSocketServer.session.getBasicRemote().sendObject(message);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("[连接topic:{}] 发送消息失败, 消息:{}", this.topic, message, e);
            }
        }
    }

    /**
     * 群发消息
     * @param message
     */
    public void sendMassMessage(String message) {
        try {
            for (Session session : SESSIONS) {
                if (session.isOpen()) {
                    session.getBasicRemote().sendText(message);
                    log.info("[连接topic:{}] 发送消息:{}",session.getRequestParameterMap().get("topic"),message);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取当前连接数
     * @return
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 当前连接数加一
     */
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    /**
     * 当前连接数减一
     */
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

}

Java客户端

有个需求需要Java发送ws连接,将业务处理后的消息都汇总到ws服务端,由ws服务端汇总处理发送给客户端。

        <!--websocket作为客户端-->
        <dependency>
            <groupId>org.java-websocket</groupId>
            <artifactId>Java-WebSocket</artifactId>
            <version>1.3.5</version>
        </dependency>

Java客户端代码

package com.example.web.socket;

import com.example.config.MyConfig;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;

@Component
@Slf4j
public class MyWebSocketClient {
    @Autowired
    private MyConfig myConfig;

    @Bean
    public WebSocketClient webSocketClient() throws URISyntaxException, UnknownHostException {
        String IP = InetAddress.getLocalHost().getHostAddress();

        // 建立ws连接对象
        org.java_websocket.client.WebSocketClient webSocketClient =
                new org.java_websocket.client.WebSocketClient(
                        new URI("ws://"+myConfig.getJavaIP()+":"+myConfig.getJavaPort()+"/webSocket/" + IP),
                        new Draft_6455()) {

            @Override
            public void onOpen(ServerHandshake handshakedata) {
                log.info("[websocket] 连接成功");
            }

            @Override
            public void onMessage(String message) {
                log.info("[websocket] 收到消息={}", message);

            }

            @Override
            public void onClose(int code, String reason, boolean remote) {
                log.info("[websocket] 退出连接");
            }

            @Override
            public void onError(Exception ex) {
                log.info("[websocket] 连接错误={}", ex.getMessage());
            }
        };

        // 连接
        webSocketClient.connect();

        return webSocketClient;
    }
}

使用

    @Autowired
    private WebSocketClient webSocketClient;

    // 发送消息
    webSocketClient.send(JSON.toJSONString(uploadMsg));

excel导入导出

直接使用阿里的easy-excel

EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel (alibaba.com)

我的代码在gitee:excel-process: excel导入、导出、下载数据模板

随机数

// 获取0-6不包含6的随机整数
Random random = new Random();
random.nextInt(6);

IO流

字节流

字节流是处理所有 I/O 操作的基础。它用于处理原始二进制数据(例如图片、音频文件、视频文件等),它不管数据的内容是文本、图片还是其他格式,都是以字节的形式进行读写。

字节流的两个最常用的基类是:
InputStream:所有字节输入流的父类。
OutputStream:所有字节输出流的父类

字节流提供的常见实现类:
FileInputStream 和 FileOutputStream:用于从文件读取或写入字节数据。
BufferedInputStream 和 BufferedOutputStream:用于提高输入输出效率,使用缓冲区减少读取次数。
DataInputStream 和 DataOutputStream:可以处理基本数据类型(例如 int, float 等)的读取和写入。
ObjectInputStream 和 ObjectOutputStream:用于序列化和反序列化对象。

字符流

字符流用于处理文本数据,字符流通过字符编码(通常是 UTF-8 或 GBK 等)来处理文本,因此它专门用于处理文本文件。

字符流的两个最常用的基类是:Reader:所有字符输入流的父类。Writer:所有字符输出流的父类。


字符流提供的常见实现类:

FileReader 和 FileWriter:用于从文件中读取和写入字符数据。
BufferedReader 和 BufferedWriter:可以使用缓冲区来提高读取和写入字符数据的效率。
PrintWriter:用于打印格式化的文本。

缓冲流(Buffered Streams)

缓冲流是对字节流和字符流的封装,提供了一个缓冲区,减少了磁盘和内存之间的读写次数,从而提高性能。

BufferedInputStream 和 BufferedOutputStream:适用于字节流。
BufferedReader 和 BufferedWriter:适用于字符流。

数据流(Data Streams)

数据流允许你读写原始数据类型(如 int, float, long 等),并提供了一个标准的格式,可以跨平台读写数据。

DataInputStream:用于从输入流中读取原始数据。

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class DataInputStreamExample {
    public static void main(String[] args) {
        try (DataInputStream dis = new DataInputStream(new FileInputStream("example.dat"))) {
            int number = dis.readInt();
            System.out.println("Read number: " + number);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


DataOutputStream:用于向输出流写入原始数据。

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataOutputStreamExample {
    public static void main(String[] args) {
        try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("example.dat"))) {
            int number = 42;
            dos.writeInt(number);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


对象流(Object Streams)

对象流用于对象的序列化和反序列化。通过对象流,我们可以将 Java 对象保存到文件中(序列化)或从文件中恢复 Java 对象(反序列化)。

ObjectInputStream:用于从输入流中读取 Java 对象。
ObjectOutputStream:用于将 Java 对象写入输出流。

调用第三方接口

Java API

使用标准的 Java API 中的 java.net 包来进行 HTTP 请求。GET

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class ApiCaller {

    public static void main(String[] args) {
        try {
            // 第三方接口的URL
            String apiUrl = "https://api.example.com/data";

            // 创建 URL 对象
            URL url = new URL(apiUrl);

            // 打开连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            // 设置请求方法
            connection.setRequestMethod("GET");

            // 获取响应代码
            int responseCode = connection.getResponseCode();

            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 读取响应内容
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();

                // 处理响应内容
                System.out.println("Response: " + response.toString());
            } else {
                System.out.println("HTTP Request Failed with response code: " + responseCode);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

post 

public static String sendPostRequest(String remoteUrl,String requestBody){
        String result = null;
        try {

            // 创建 URL 对象
            URL url = new URL(remoteUrl);

            // 打开连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            // 设置请求方法为 POST
            connection.setRequestMethod("POST");

            connection.setRequestProperty("Content-Type", "application/json");

            // 启用输入输出流
            connection.setDoOutput(true);

            // 设置请求体
            try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
                outputStream.write(requestBody.getBytes(StandardCharsets.UTF_8));
            }

            // 获取响应代码
            int responseCode = connection.getResponseCode();

            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 读取响应内容
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();

                // 处理响应内容
                log.info("响应内容:{}",response.toString());

                result = response.toString();
            } else {
                log.error("请求失败,响应码是:{} " , responseCode);
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("出错了:",e);
        }
        return result;
    }

Apache HttpClient

Apache HttpClient 是一个功能强大、灵活且可扩展的 HTTP 客户端库,它提供了更高级的功能,如连接池、Cookie 管理等。

<!-- http通信 -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺着听Jay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值