JAVA socket FTPserver HTTPserver chatting RMI(Remote Method Invocation)

本文主要是介绍JAVA socket FTPserver HTTPserver chatting RMI(Remote Method Invocation),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录(?)[-]

  1. github-httpserverftpserverchattingRoomRMI
  2. RMI Remote Method Invocation
  3. httpserver
    1. 遇到的问题
  4. FTP
    1. 客户端连接到服务器端 c语言伪码Java版见github
    2. 客户端连接到 FTP 服务器接收欢迎信息
    3. 客户端发送用户名和密码登入 FTP 服务器
    4. 让服务器进入被动模式在数据端口监听
    5. 客户端通过被动模式下载文件
      1. 遇到的问题
  5. Chatting功能
    1. 服务器和客户端通信协议
    2. 客户端发送请求数据格式
    3. 服务器响应数据格式
      1. 基于socket的一个简单的android聊天工具
    4. 遇到的问题

  • github-httpserverftpserverchattingRoomRMI
  • RMI Remote Method Invocation
  • httpserver
      • 遇到的问题
  • FTP
    • 客户端连接到服务器端 c语言伪码Java版见github
    • 客户端连接到 FTP 服务器接收欢迎信息
    • 客户端发送用户名和密码登入 FTP 服务器
    • 让服务器进入被动模式在数据端口监听
    • 客户端通过被动模式下载文件
      • 遇到的问题
  • Chatting功能
    • 服务器和客户端通信协议
    • 客户端发送请求数据格式
    • 服务器响应数据格式
        • 基于socket的一个简单的android聊天工具
      • 遇到的问题

github-httpserver/ftpserver/chattingRoom/RMI

RMI Remote Method Invocation

调用不同JVM上的方法

httpserver

这里并不需要解析xml/html, 根据request请求,返回html让浏览器解析

遇到的问题

  • 第一个问题,之前在创建文件的时候程序一直报错,说文件路径不对或者不存在,之后发现在写路径的时候’/’这些元字符是需要转义的。

  • 第二个问题,是服务器运行后,无法在网页上查看图片等信息,同时服务端抛出异常,但是html网页可以正常显示。这个问题最后通过询问同学和查资料,得知我所使用的发送和接收消息的流不对,不能够使用datainputstream和dataoutputstream,并且wirteUTF方法不能用于http服务器中因为这个方法一开始会写入两个字节,即为将要写入的字节数(不是字符串的长度)。后来改成了printstream和bufferedreader就成功了。

  • 第三个问题,是没有意识到浏览器解析html时,对于html内嵌的图片和视频等资源会在解析之后再次送一个get请求。所以通过浏览器访问服务端网页时,服务端不用进行标签解析。

  • 第四个问题,在服务器发送响应体的时候,我发现出现一个奇怪的现象,就是程序运行的时候,总是无法下载完成,打开对应的客户端文件夹发现文件没有下载完成(即为0字节),但是在关闭客户端运行之后,那个文件夹里的文件就下载好了。最后发现,是服务器在发送响应体的时候,最后忘记关闭了文件发送流,所以导致客户端一直在读取服务器的信息,导致失败。后来添加了close,判断-1才能成功,接受所有信息并关闭文件

FTP:

Resume file upload/download after lost connection 
使用 Socket 通信实现 FTP 客户端程序

客户端连接到服务器端 c语言伪码(Java版见github)

客户端连接到服务器端

客户端连接到 FTP 服务器,接收欢迎信息

<code class="language-c hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">SOCKET control_sock;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> hostent *hp;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> sockaddr_in server;
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">memset</span>(&server, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> sockaddr_in));<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 初始化socket */</span>
control_sock = socket(AF_INET, SOCK_STREAM, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);
hp = gethostbyname(server_name);
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">memcpy</span>(&server.sin_addr, hp->h_addr, hp->h_length);
server.sin_family = AF_INET;
server.sin_port = htons(port);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 连接到服务器端 */</span>
connect(control_sock,(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> sockaddr *)&server, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(server));
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端接收服务器端的一些欢迎信息 */</span>
read(control_sock, read_buf, read_len);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

客户端发送用户名和密码,登入 FTP 服务器

<code class="language-c hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 命令 ”USER username\r\n” */</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">sprintf</span>(send_buf,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"USER %s\r\n"</span>,username);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*客户端发送用户名到服务器端 */</span>
write(control_sock, send_buf, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">strlen</span>(send_buf));
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端接收服务器的响应码和信息,正常为 ”331 User name okay, need password.” */</span>
read(control_sock, read_buf, read_len);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 命令 ”PASS password\r\n” */</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">sprintf</span>(send_buf,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"PASS %s\r\n"</span>,password);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端发送密码到服务器端 */</span>
write(control_sock, send_buf, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">strlen</span>(send_buf));
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端接收服务器的响应码和信息,正常为 ”230 User logged in, proceed.” */</span>
read(control_sock, read_buf, read_len);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

让服务器进入被动模式,在数据端口监听

<code class="language-c hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 命令 ”PASV\r\n” */</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">sprintf</span>(send_buf,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"PASV\r\n"</span>);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端告诉服务器用被动模式 */</span>
write(control_sock, send_buf, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">strlen</span>(send_buf));
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*客户端接收服务器的响应码和新开的端口号,
* 正常为 ”227 Entering passive mode (<h1,h2,h3,h4,p1,p2>)” */</span>
read(control_sock, read_buf, read_len);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

客户端通过被动模式下载文件

<code class="language-c hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 连接服务器新开的数据端口 */</span>
connect(data_sock,(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> sockaddr *)&server, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(server));
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 命令 ”CWD dirname\r\n” */</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">sprintf</span>(send_buf,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"CWD %s\r\n"</span>, dirname);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端发送命令改变工作目录 */</span>
write(control_sock, send_buf, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">strlen</span>(send_buf));
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端接收服务器的响应码和信息,正常为 ”250 Command okay.” */</span>
read(control_sock, read_buf, read_len);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 命令 ”SIZE filename\r\n” */</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">sprintf</span>(send_buf,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"SIZE %s\r\n"</span>,filename);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端发送命令从服务器端得到下载文件的大小 */</span>
write(control_sock, send_buf, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">strlen</span>(send_buf));
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端接收服务器的响应码和信息,正常为 ”213 <size>” */</span>
read(control_sock, read_buf, read_len);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 命令 ”RETR filename\r\n” */</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">sprintf</span>(send_buf,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"RETR %s\r\n"</span>,filename);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端发送命令从服务器端下载文件 */</span>
write(control_sock, send_buf, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">strlen</span>(send_buf));
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端接收服务器的响应码和信息,正常为 ”150 Opening data connection.” */</span>
read(control_sock, read_buf, read_len);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端创建文件 */</span>
file_handle = open(disk_name, CRFLAGS, RWXALL);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>( ; ; ) {
... ...
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端通过数据连接 从服务器接收文件内容 */</span>
read(data_sock, read_buf, read_len);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端写文件 */</span>
write(file_handle, read_buf, read_len);
... ... 
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 客户端关闭文件 */</span>
rc = close(file_handle);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li></ul>

遇到的问题

  • 第一个问题是很迷茫,应为是第一个做的实验,不知道如何进行文件上传和下载。后来在网上查询,明白了可以分成两部分,第一部分把文件从硬盘里读取到内存中,再把数据从内存中发送到另一端,由另一端读取到内存,再从内存写入到文件。其中使用了一个字节数组当做一个缓冲,就像一辆运输车一样,一趟一趟的运送货物,直到最后read()==-1就读完了。

  • 第二个问题是下载文件夹。逻辑较为复杂,首先要使用isDirectory方法判断是否是文件夹,然后在本地判断是否存在同名文件夹,通过file.list方法获得文件列表,进而得到文件个数,然后对每个文件进行下载即可,此处隐含了list,cwd,retr等指令,较为复杂,并且dos dis使用后要及时flush和关闭。

  • 第三个问题是阻塞方法的调用。多线程间的协作和socket通信容易混淆,了解到相关原则是尽量少开线程,并时刻注意线程同步异步问题,如上传文件时,服务端使用线程同步(synchronized)的方法,即一个线程访问该方法时,他就获得了该object的对象锁,另一个线程对该object的访问将被暂时阻塞, 保证只存在一个同名文件且后上传的不会覆盖之前的。由于实验末尾才稍微了解了java并发的锁机制,所以所有实验都可以用线程锁等java并发编程知识进行优化,这也是下一步的改进方向

Chatting功能:

登录
发送文件、表情、信息
多人同时聊天
离线发送消息(上线后就能看到)

服务器和客户端通信协议

客户端登录,客户端取得用户列表,以及客户端和客户端的通信都必须跟服务器交互,我们约定客户端和服务器端的通信协议如下: 
请求数据格式

客户端发送请求数据格式:

请求码 请求数据

请求码: 
101 用户登录 
102 取得用户列表 
103 发送消息

如登录请求,客户端向服务器发送的请求数据为: 
101|用户名,密码

如取得用户列表,客户端向服务器发送的请求数据为: 
102|

如发送消息,客户端向服务器发送的请求数据为: 
103|消息发送方,消息接收方,消息内容 
响应数据格式

服务器响应数据格式:

响应码 响应数据

响应码: 
1 响应成功 
0 响应失败

如登录请求,服务器端的响应数据为: 
1| 或者 0|

如取得用户列表,服务器端的响应数据为: 
1|消息类型(102)@消息发送方(Server)@用户1,用户2,用户3@消息发送时间

如服务器给客户端发送消息 
1|消息类型(103)@消息发送方@消息内容@消息发送时间 
服务器消息队列格式

服务器端接收到客户的请求后(取得用户列表和用户信息)将请求结果放在消息队列中,发送消息的线程用队列中取消息,发送给客户端,

我们约定消息队列中消息的格式如下: 
消息发送方 消息接收方 内容 发送时间 消息类别 
Server tom Tom,jack,luly,lily 2016-1-29 11:11:11 102 
Jack tom How are you doing? 2016-1-29 12:12:12 103

基于socket的一个简单的android聊天工具

socket采用TCP/IP时,应有可自由分配的IP(内外网)。对于蓝牙协议,上层接口无法得到IP,所以与wifi组成网络时比较困难,需修改底层框架结构。

遇到的问题

  • 第一个问题是对该设计模式的理解。这个模型类似于生产-消费者模型,将该模型的订阅模式和p2p模式结合,就实现了即能群聊,又能单独聊天的功能。一开始看通信流程图,认为是每个用户一个消息信道,直到想明白生产-消费者模型,才开始正确的实验过程。网上相关资料实现了jms接口进行开发,这也是可以进一步改进的方向

  • 第二个问题是初始化用户列表的时机,后来发现了问题,添加了构造函数,初始化了用户列表。但是主线程里并没有初始化任何一个用户包对象,仅仅是调用了一个静态方法,所以我在服务器建立伊始就初始化了一个用户包对象,虽然这个对象没有被使用,但是成功初始化了用户列表。同样的,消息列表类(MessageDAO)我也使用了此种方法,只不过不在建立服务器时,是在用户登录成功过后。

这篇关于JAVA socket FTPserver HTTPserver chatting RMI(Remote Method Invocation)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/850290

相关文章

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

Java.lang.InterruptedException被中止异常的原因及解决方案

《Java.lang.InterruptedException被中止异常的原因及解决方案》Java.lang.InterruptedException是线程被中断时抛出的异常,用于协作停止执行,常见于... 目录报错问题报错原因解决方法Java.lang.InterruptedException 是 Jav

深入浅出SpringBoot WebSocket构建实时应用全面指南

《深入浅出SpringBootWebSocket构建实时应用全面指南》WebSocket是一种在单个TCP连接上进行全双工通信的协议,这篇文章主要为大家详细介绍了SpringBoot如何集成WebS... 目录前言为什么需要 WebSocketWebSocket 是什么Spring Boot 如何简化 We

java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)

《java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)》:本文主要介绍java中pdf模版填充表单踩坑的相关资料,OpenPDF、iText、PDFBox是三... 目录准备Pdf模版方法1:itextpdf7填充表单(1)加入依赖(2)代码(3)遇到的问题方法2:pd

Java Stream流之GroupBy的用法及应用场景

《JavaStream流之GroupBy的用法及应用场景》本教程将详细介绍如何在Java中使用Stream流的groupby方法,包括基本用法和一些常见的实际应用场景,感兴趣的朋友一起看看吧... 目录Java Stream流之GroupBy的用法1. 前言2. 基础概念什么是 GroupBy?Stream

SpringBoot监控API请求耗时的6中解决解决方案

《SpringBoot监控API请求耗时的6中解决解决方案》本文介绍SpringBoot中记录API请求耗时的6种方案,包括手动埋点、AOP切面、拦截器、Filter、事件监听、Micrometer+... 目录1. 简介2.实战案例2.1 手动记录2.2 自定义AOP记录2.3 拦截器技术2.4 使用Fi

最新Spring Security的基于内存用户认证方式

《最新SpringSecurity的基于内存用户认证方式》本文讲解SpringSecurity内存认证配置,适用于开发、测试等场景,通过代码创建用户及权限管理,支持密码加密,虽简单但不持久化,生产环... 目录1. 前言2. 因何选择内存认证?3. 基础配置实战❶ 创建Spring Security配置文件

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

Java Thread中join方法使用举例详解

《JavaThread中join方法使用举例详解》JavaThread中join()方法主要是让调用改方法的thread完成run方法里面的东西后,在执行join()方法后面的代码,这篇文章主要介绍... 目录前言1.join()方法的定义和作用2.join()方法的三个重载版本3.join()方法的工作原