Java IO流(五)Netty实战[TCP|Http|心跳检测|Websocket]

news2024/11/19 3:42:11

Netty入门代码示例(基于TCP服务)

Server端

package com.bierce.io.netty.simple;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.CharsetUtil;
public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        //创建BossGroup和WorkerGroup线程池组,均属于自旋状态
        EventLoopGroup bossGroup = new NioEventLoopGroup(); //负责连接请求处理
        EventLoopGroup workerGroup = new NioEventLoopGroup(); //进行业务处理
        try {
            //创建服务器端启动,通过链式编程配置相关参数
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) //设置为服务端通道
                    .option(ChannelOption.SO_BACKLOG,128) //设置线程队列等待连接的个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true) //设置保持活动连接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() { //匿名创建通道初始对象
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new NettyServerHandler()); //为workerGroup下的NioEventLoop对应管道pipeline设置自定义处理器
                        }
                    });
            System.out.println("Server is start Successful !!!");
            ChannelFuture cf = bootstrap.bind(6668).sync(); //绑定指定端口并同步处理
            cf.channel().closeFuture().sync(); //监听关闭通道方法
        }finally { //关闭线程池资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
class NettyServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //读取客户端发送的数据
        //ctx:上下文对象,包含管道pipeline,通道等信息
        //msg:即客户端发送的数据
        ByteBuf buf = (ByteBuf) msg; //ByteBuf是Netty提供的缓冲区,性能更高
        System.out.println("客户端发送过来的msg = " + buf.toString((CharsetUtil.UTF_8)));
        System.out.println("客户端地址 = " + ctx.channel().remoteAddress());
    }
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { //读取客户端信息完成后进行的业务处理
//        super.channelReadComplete(ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, Client!",CharsetUtil.UTF_8)); //将数据写到缓存并刷新
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close(); //处理异常需要关闭通道
    }
}

 Client

package com.bierce.io.netty.simple;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.CharsetUtil;
public class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(); //客户端事件循环组
        try {
            Bootstrap bootstrap = new Bootstrap(); //客户端启动对象
            bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class) //客户端通道
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new NettyClientHandler()); //添加自定义处理器
                        }
                    });
            System.out.println("Client Start Successful!!!");
            ChannelFuture sync = bootstrap.connect("127.0.0.1", 6668).sync();
            sync.channel().closeFuture().sync(); //监听关闭通道
        }finally {
            eventLoopGroup.shutdownGracefully();
        }
    }
}
class NettyClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception { //通道就绪会触发该方法
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, Server!", CharsetUtil.UTF_8)); //将数据写到缓存并刷新
    }
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //读取服务端返回信息
        ByteBuf buf = (ByteBuf) msg; //ByteBuf是Netty提供的缓冲区,性能更高
        System.out.println("服务端发送过来的msg = " + buf.toString((CharsetUtil.UTF_8)));
        System.out.println("服务端地址 = " + ctx.channel().remoteAddress());
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close(); //处理异常需要关闭通道
    }
}

运行结果

Server
Client

Netty入门代码示例(基于HTTP服务)

package com.bierce.io.netty.http;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

import java.net.URI;

public class TestServer {
    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //创建服务器端启动,通过链式编程配置相关参数
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) //设置为服务端通道
                    .childHandler(new TestServerInitializer()); //设置为自定义的初始化
            System.out.println("Server is start Successful !!!");
            ChannelFuture cf = bootstrap.bind(9999).sync(); //绑定指定端口并同步处理
            cf.channel().closeFuture().sync(); //监听关闭通道方法
        }finally { //关闭线程池资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
class TestServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        //HttpServerCodec是Netty提供的处理Http的编-解码器 使用io.netty:netty-all:4.1.20Final版本,其他版本不支持会报错
        pipeline.addLast("MyHttpServerCodec", new HttpServerCodec());
        //增加自定义的handler
        pipeline.addLast("MyTestHttpServerHandler", new TestHttpServerHandler());
    }
}
class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
    //读取客户端数据
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
        if (httpObject instanceof HttpRequest){
            System.out.println("httpObject Type = " + httpObject.getClass());
            System.out.println("Client Address = " + channelHandlerContext.channel().remoteAddress());
            //对特定资源进行过滤
            HttpRequest httpRequest = (HttpRequest)httpObject;
            URI uri = new URI(httpRequest.getUri());
            if ("/favicon.ico".equals(uri.getPath())){
                System.out.println("favicon.ico资源不做响应");
                return;
            }
            //回复浏览器信息(http协议)
            ByteBuf content = Unpooled.copiedBuffer("Hello, I'm Server", CharsetUtil.UTF_8);
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());
            channelHandlerContext.writeAndFlush(response);
        }
    }
}

运行结果

Netty心跳检测机制

package com.bierce.io.netty.heartbeat;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;
public class MyServer {
    public static void main(String[] args) {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            //IdleStateHandler:Netty提供的处理空闲状态的处理器
                            //readerIdleTime:多长时间没有读操作,会发送心跳检测包检测是否连接
                            //writerIdleTime:多长时间没有写操作,会发送心跳检测包检测是否连接
                            //allIdleTime:多长时间没有读写操作,会发送心跳检测包检测是否连接
                            pipeline.addLast(new IdleStateHandler(3,5,7, TimeUnit.SECONDS));
                            //IdleStateHandler触发后,将传递给下一个Handler的userEventTriggered方法去处理
                            //通过自定义的Handler对空闲状态进一步处理
                            pipeline.addLast(new MyServerHandler());
                        }
                    });
            ChannelFuture sync = bootstrap.bind(9999).sync().channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
class MyServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent){
            IdleStateEvent IdleStateEvent = (IdleStateEvent) evt;
            String eventType = null;
            switch (IdleStateEvent.state()){
                case READER_IDLE:
                    eventType = "读空闲";
                    break;
                case WRITER_IDLE:
                    eventType = "写空闲";
                    break;
                case ALL_IDLE:
                    eventType = "读写空闲";
                    break;
            }
            System.out.println(ctx.channel().remoteAddress() + "-已超时,超时类型为: " + eventType );
            System.out.println("Server will deal with it instantly...");
            //发生空闲则关闭当前通道
            ctx.close();
        }
    }
}
class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(); //客户端事件循环组
        try {
            Bootstrap bootstrap = new Bootstrap(); //客户端启动对象
            bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class) //客户端通道
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new NettyClientHandler()); //添加自定义处理器
                        }
                    });
            System.out.println("Client Start Successful!!!");
            ChannelFuture sync = bootstrap.connect("127.0.0.1", 9999).sync();
            sync.channel().closeFuture().sync(); //监听关闭通道
        }finally {
            eventLoopGroup.shutdownGracefully();
        }
    }
}

 注意: 需要调整readerIdleTime|writerIdleTime|allIdleTime参数才会显示对应超时信息

Netty入门代码示例(基于WebSocket协议)

服务端

package com.bierce.websocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

import java.time.LocalDateTime;

public class MyWebsocketServer {
    public static void main(String[] args) {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            //基于Http协议,所以需要http解码编码
                            pipeline.addLast(new HttpServerCodec());
                            pipeline.addLast(new ChunkedWriteHandler()); //处理块方式的写操作
                            //http传输过程数据量非常大时会分段,而HttpObjectAggregator可以将多个分段聚合
                            pipeline.addLast(new HttpObjectAggregator(8192));
                            //webSocket采用帧方式传输数据
                            //WebSocketServerProtocolHandler作用是将http协议升级为ws协议,且保持长连接
                            pipeline.addLast(new WebSocketServerProtocolHandler("/hello"));
                            pipeline.addLast(new MyWebsocketServerHandler());
                        }
                    });
            ChannelFuture sync = bootstrap.bind(9999).sync().channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
class MyWebsocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        System.out.println("Server receive the Info: " + msg.text());
        ctx.channel().writeAndFlush(new TextWebSocketFrame("Server time " + LocalDateTime.now() + " --- " + msg.text()));
    }
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("有客户端连接成功 --" + ctx.channel().id().asLongText()); //asLongText唯一值
    }
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("有客户端已经离开 --" + ctx.channel().id().asLongText()); //asLongText唯一值
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("异常Info:" + cause.getMessage());
        ctx.close();
    }
}

客户端(浏览器)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Websocket</title>
</head>
<body>
<script>
    var socket;
    if (window.WebSocket) {
        socket = new WebSocket("ws://localhost:9999/hello");
        //相当于channelRead0,读取服务器端的消息
        socket.onmessage = function(ev){
            var rt = document.getElementById("responseText");
            rt.value = rt.value + "\n" + ev.data;
        }
        //开启连接
        socket.onopen = function(ev){
            var rt = document.getElementById("responseText");
            rt.value = "开启连接成功!";
        }
        //连接关闭
        socket.onclose = function(ev){
            var rt = document.getElementById("responseText");
            rt.value = rt.value + "\n" + "连接关闭成功!";
        }
    }
    //发送消息给服务器
    function send(msg){
        if(!window.socket){ //是否已创建socket
            return;
        }
        if(socket.readyState == WebSocket.OPEN){
            socket.send(msg);
        }else{
            alert("socket未连接");
        }
    }
</script>
    <form onsubmit="return false">
        <textarea name="message" style="height:300px;width:300px"></textarea>
        <input type="button" value="Send" onclick="send(this.form.message.value)">
        <textarea id="responseText" style="height:300px;width:300px"></textarea>
        <input type="button" value="Clear" onclick="document.getElementById('responseText').value=''">
    </form>
</body>
</html>

效果图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/919803.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

星际争霸之小霸王之小蜜蜂(五)--为小蜜蜂降速

目录 前言 一、思路 二、调整小蜜蜂的移速 三、限制活动范围 四、继续重构 总结 前言 前面我们已经让小蜜蜂左右移动起来了&#xff0c;而且是连续的左右移动&#xff0c;但是在使用的过程中&#xff0c;因为我使用的是笔记本电脑&#xff0c;所以屏幕比较小&#xff0c;设…

Diffusion Models for Time Series Applications: A Survey

Diffusion Models for Time Series Applications: A Survey (Paper reading) Lequan Lin, The University of Sydney Business School, arXiv2023,Cited:5, Code, Paper 1. 引言 扩散模型是一类基于深度学习的生成模型&#xff0c;在前沿的机器学习研究中变得越来越突出。在…

Linux线程 --- 生产者消费者模型(C语言)

在学习完线程相关的概念之后&#xff0c;本节来认识一下Linux多线程相关的一个重要模型----“ 生产者消费者模型” 本文参考&#xff1a; Linux多线程生产者与消费者_红娃子的博客-CSDN博客 Linux多线程——生产者消费者模型_linux多线程生产者与消费者_两片空白的博客-CSDN博客…

测试平台metersphere

metersphere可以做接口测试、UI测试、性能测试。 metersphere接口测试底层是jmeter&#xff0c;可以做API管理&#xff0c;快捷调试&#xff0c;接口用例管理&#xff0c;接口自动化场景执行一键选取用例范围&#xff0c;生成测试报告。 会用jmeter&#xff0c;metersphere会…

软年架构复用-架构师之路(十一)

软件架构复用 软件产品线是 一组产业密集型系统&#xff0c;规定用公用的 核心资产集成 开发而来。 机会复用 和 系统复用。 机会复用&#xff1a;临时发现有可服用资产立马复用。 系统复用&#xff1a;开发之前进行规划好哪些需要复用。 复用的三个阶段&#xff1a; 获取到…

高阶数据结构并查集

目录&#xff1a; 并查集的概念代码实现 并查集的概念 将n个不同的元素划分成一些不相交的集合。开始时&#xff0c;每个元素自成一个单元元素集合&#xff0c;然后按一定的规律将归于同一组元素的集合合并。在此过程中反复遇到查询某一个元素属于那个集合的运算&#xff0c;这…

储能运行约束的Matlab建模方法

最近一段时间有很多人问我最优潮流计算中储能系统的建模方法。部分朋友的问题我回复了&#xff0c;有些没有回消息的&#xff0c;我就不再一一回复了&#xff0c;在这里我写一篇博客统一介绍一下。 1.储能系统介绍 首先&#xff0c;让【GPT】简单介绍一下储能系统&#xff1a;…

【多天线传输技术】BPSK调制信号在AWGN信道下的理论误码率与仿真误码率

%% [0、预处理] clc; clear; close all&#xff1b;%% [1、配置参数] N1000000; %数据点数&#xff08;个&#xff09; SNR_dB0:10; %信噪比&#xff08;dB形式&#xff09; SNR10.^(SNR_dB/10); %信噪比&#xff08;一般形式&#xff0c;Eb/N0&#xff09;…

【业务功能篇78】微服务-前端后端校验- 统一异常处理-JSR-303-validation注解

5. 前端校验 我们在前端提交的表单数据&#xff0c;我们也是需要对提交的数据做相关的校验的 Form 组件提供了表单验证的功能&#xff0c;只需要通过 rules 属性传入约定的验证规则&#xff0c;并将 Form-Item 的 prop 属性设置为需校验的字段名即可 校验的页面效果 前端数据…

Android相机-HAL子系统

引言 应用框架要通过拍照预览摄像获得照片或者视频,就需要向相机子系统发出请求, 一个请求对应一组结果 一次可发起多个请求&#xff0c;并且提交请求是非阻塞的&#xff0c;始终按照接收的顺序以队列的形式先进先出地进行顺序处理 一个请求包含了拍摄和拍照配置的所有信息&…

企业数字化转型中,VR数字展厅能有哪些体验?

在数字化转型的浪潮下&#xff0c;企业纷纷开始注重数字展厅的开展&#xff0c;VR虚拟展厅结合VR全景技术&#xff0c;可以创造出许多有趣的玩法和体验&#xff0c;无论是虚拟参观、互动体验还是VR云会议对接&#xff0c;都为企业客户带来了全新的感知方式。 同传统展厅相比&am…

【LeetCode-中等题】560. 和为 K 的子数组

题目 题解一&#xff1a;逆序枚举数组 //方法一:枚举数组&#xff08;顺序&#xff09;int count 0;// 记录最终符合条件的数组个数int n nums.length;for(int end 0; end<n ; end){int sum 0;//记录每一次经过的元素总和for(int start end; start>0;start--){sum n…

漏洞挖掘和漏洞利用技术:讨论漏洞发现、利用和修复,深入研究不同类型漏洞的技术细节

章节一&#xff1a;引言 在当今数字化时代&#xff0c;计算机技术的迅猛发展为我们的生活带来了无数便利&#xff0c;然而也伴随着各种安全威胁。恶意黑客利用漏洞进行攻击已成为一种常见现象。本文将深入探讨漏洞挖掘和漏洞利用技术&#xff0c;以及如何修复这些漏洞&#xf…

微信小程序路由以及跳转页面传递参数

路由 在app.json的pages里面写 "pages/页面/页面" 直接保存pages直接生成非常方便 跳转页面 wx.navigateTo() 保留当前页面&#xff0c;跳转到应用内的某个非tabBar页面。 <text bindtap"daka">点击</text> daka:function () {wx.navigateTo…

第3篇:vscode搭建esp32 arduino开发环境

第1篇:Arduino与ESP32开发板的安装方法 第2篇:ESP32 helloword第一个程序示范点亮板载LED 1.下载vscode并安装 https://code.visualstudio.com/ 运行VSCodeUserSetup-x64-1.80.1.exe 2.点击扩展&#xff0c;搜索arduino,并点击安装 3.点击扩展设置&#xff0c;配置arduino…

java+springboot+mysql村务档案管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的村务档案管理系统&#xff0c;系统包含超级管理员、工作人员角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;系统用户管理&#xff08;工作人员管理&#xff09;&#xff1b;公开资料&#xff1b;会议记录&…

PDF校对:追求文档的精准与完美

随着数字化时代的到来&#xff0c;PDF已经成为了多数机构和个人首选的文件格式&#xff0c;原因在于它的稳定性、跨平台特性以及统一的显示效果。但是&#xff0c;对于任何需要公开或正式发布的文档&#xff0c;确保其内容的准确性是至关重要的&#xff0c;这就是PDF校对显得尤…

IDEA创建Spring,Maven项目没有resources文件夹

有时新建Spring或Maven项目时&#xff0c;会出现目录中main下无resources文件夹的情况&#xff0c;来一起解决一下&#xff1a; FIles|Project Structure 在Modules模块找到对应路径&#xff0c;在main下创建resources&#xff0c;右键main&#xff0c;选择新文件夹 输入文件…

瞎扯之synchronized

我是胡说八道君&#xff0c;鉴别一个人基础打得牢不牢&#xff0c;有没有这个举一反三、将学过的知识串联起来的能力&#xff0c;教你一个简单的方法&#xff1a;关键词联想法 有兴趣的童鞋也可以跟着我的思路去画一张思维导图哦!加入你自己联想道德的部分更重要 eg: 给你一个…

金桥跨越相伴岁月 桂冠加冕爱意时光 GP芝柏表演绎浪漫七夕

两个多世纪以前&#xff0c;康士坦特芝勒德 (Constant Girard) 与玛莉亚柏雷戈 (Marie Perregaux) 喜结连理&#xff0c;两颗心灵在爱意中交织&#xff0c;二人将姓氏结合&#xff0c;创立“Girard-Perregaux”芝柏表&#xff0c;成为数百年来瑞士高级制表中仅有的以夫妻双人姓…