SpringBoot整合Netty並使用Protobuf進行資料傳輸(附工程)
前言
本篇文章主要介紹的是SpringBoot整合Netty以及使用Protobuf進行資料傳輸的相關內容。Protobuf會簡單的介紹下用法,至於Netty在之前的文章中已經簡單的介紹過了,這裡就不再過多細說了。
Protobuf
介紹
protocolbuffer(以下簡稱PB)是google 的一種資料交換的格式,它獨立於語言,獨立於平臺。google 提供了多種語言的實現:java、c#、c++、go 和python,每一種實現都包含了相應語言的編譯器以及庫檔案。由於它是一種二進位制的格式,比使用 xml進行資料交換快許多。可以把它用於分散式應用之間的資料通訊或者異構環境下的資料交換。作為一種效率和相容性都很優秀的二進位制資料傳輸格式,可以用於諸如網路傳輸、配置檔案、資料儲存等諸多領域。
官方地址: https://github.com/google/protobuf
使用
這裡的使用就只介紹Java相關的使用。
首先我們需要建立一個proto檔案,在該檔案定義我們需要傳輸的檔案。
例如我們需要定義一個使用者的資訊,包含的欄位主要有編號、名稱、年齡。
那麼該protobuf檔案的格式如下:
注:這裡使用的是proto3,相關的註釋我已寫了,這裡便不再過多講述了。需要注意一點的是proto檔案和生成的Java檔名稱不能一致!
syntax = "proto3"; // 生成的包名 option java_package="com.pancm.protobuf"; //生成的java名 option java_outer_classname = "UserInfo"; message UserMsg { // ID int32 id = 1; // 姓名 string name = 2; // 年齡 int32 age = 3; // 狀態 int32 state = 4; }
建立好該檔案之後,我們把該檔案和protoc.exe(生成Java檔案的軟體)放到E盤目錄下的protobuf資料夾下,然後再到該目錄的dos介面下輸入:protoc.exe --java_out=檔案絕對路徑名稱
。
例如:
protoc.exe --java_out=E:\protobuf User.proto
輸入完之後,回車即可在同級目錄看到已經生成好的Java檔案,然後將該檔案放到專案中該檔案指定的路徑下即可。
注:生成protobuf的檔案軟體和測試的protobuf檔案我也整合到該專案中了,可以直接獲取的。
Java檔案生成好之後,我們再來看怎麼使用。
這裡我就直接貼程式碼了,並且將註釋寫在程式碼中,應該更容易理解些吧。。。
程式碼示例:
// 按照定義的資料結構,建立一個物件
UserInfo.UserMsg.Builder userInfo = UserInfo.UserMsg.newBuilder();
userInfo.setId(1);
userInfo.setName("xuwujing");
userInfo.setAge(18);
UserInfo.UserMsg userMsg = userInfo.build();
// 將資料寫到輸出流
ByteArrayOutputStream output = new ByteArrayOutputStream();
userMsg.writeTo(output);
// 將資料序列化後傳送
byte[] byteArray = output.toByteArray();
// 接收到流並讀取
ByteArrayInputStream input = new ByteArrayInputStream(byteArray);
// 反序列化
UserInfo.UserMsg userInfo2 = UserInfo.UserMsg.parseFrom(input);
System.out.println("id:" + userInfo2.getId());
System.out.println("name:" + userInfo2.getName());
System.out.println("age:" + userInfo2.getAge());
注:這裡說明一點,因為protobuf是通過二進位制進行傳輸,所以需要注意下相應的編碼。還有使用protobuf也需要注意一下一次傳輸的最大位元組長度。
輸出結果:
id:1
name:xuwujing
age:18
SpringBoot整合Netty
說明:如果想直接獲取工程那麼可以直接跳到底部,通過連結下載工程程式碼。
開發準備
環境要求
JDK::1.8
Netty::4.0或以上(不包括5)
Protobuf:3.0或以上
如果對Netty不熟的話,可以看看我之前寫的一些文章。大神請無視~。~
地址:https://blog.csdn.net/column/details/17640.html
首先還是Maven的相關依賴:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<netty.version>4.1.22.Final</netty.version>
<protobuf.version>3.5.1</protobuf.version>
<springboot>1.5.9.RELEASE</springboot>
<fastjson>1.2.41</fastjson>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${springboot}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${springboot}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>${springboot}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
添加了相應的maven依賴之後,配置檔案這塊暫時沒有什麼可以新增的,因為暫時就一個監聽的埠而已。
程式碼編寫
程式碼模組主要分為服務端和客戶端。
主要實現的業務邏輯:
服務端啟動成功之後,客戶端也啟動成功,這時服務端會發送一條protobuf格式的資訊給客戶端,然後客戶端給予相應的應答。客戶端與服務端連線成功之後,客戶端每個一段時間會發送心跳指令給服務端,告訴服務端該客戶端還存過中,如果客戶端沒有在指定的時間傳送資訊,服務端會關閉與該客戶端的連線。當客戶端無法連線到服務端之後,會每隔一段時間去嘗試重連,只到重連成功!
服務端
首先是編寫服務端的啟動類,相應的註釋在程式碼中寫得很詳細了,這裡也不再過多講述了。不過需要注意的是,在之前的我寫的Netty文章中,是通過main方法直接啟動服務端,因此是直接new一個物件的。而在和SpringBoot整合之後,我們需要將Netty交給springBoot去管理,所以這裡就用了相應的註解。
程式碼如下:
@Service("nettyServer")
public class NettyServer {
private static final int port = 9876; // 設定服務端埠
private static EventLoopGroup boss = new NioEventLoopGroup(); // 通過nio方式來接收連線和處理連線
private static EventLoopGroup work = new NioEventLoopGroup(); // 通過nio方式來接收連線和處理連線
private static ServerBootstrap b = new ServerBootstrap();
@Autowired
private NettyServerFilter nettyServerFilter;
public void run() {
try {
b.group(boss, work);
b.channel(NioServerSocketChannel.class);
b.childHandler(nettyServerFilter); // 設定過濾器
// 伺服器繫結埠監聽
ChannelFuture f = b.bind(port).sync();
System.out.println("服務端啟動成功,埠是:" + port);
// 監聽伺服器關閉監聽
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 關閉EventLoopGroup,釋放掉所有資源包括建立的執行緒
work.shutdownGracefully();
boss.shutdownGracefully();
}
}
}
服務端主類編寫完畢之後,我們再來設定下相應的過濾條件。
這裡需要繼承Netty中ChannelInitializer類,然後重寫initChannel該方法,進行新增相應的設定,如心跳超時設定,傳輸協議設定,以及相應的業務實現類。
程式碼如下:
@Component
public class NettyServerFilter extends ChannelInitializer<SocketChannel> {
@Autowired
private NettyServerHandler nettyServerHandler;
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline ph = ch.pipeline();
//入參說明: 讀超時時間、寫超時時間、所有型別的超時時間、時間格式
ph.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
// 解碼和編碼,應和客戶端一致
//傳輸的協議 Protobuf
ph.addLast(new ProtobufVarint32FrameDecoder());
ph.addLast(new ProtobufDecoder(UserMsg.getDefaultInstance()));
ph.addLast(new ProtobufVarint32LengthFieldPrepender());
ph.addLast(new ProtobufEncoder());
//業務邏輯實現類
ph.addLast("nettyServerHandler", nettyServerHandler);
}
}
服務相關的設定的程式碼寫完之後,我們再來編寫主要的業務程式碼。
使用Netty編寫業務層的程式碼,我們需要繼承ChannelInboundHandlerAdapter 或SimpleChannelInboundHandler類,在這裡順便說下它們兩的區別吧。
繼承SimpleChannelInboundHandler類之後,會在接收到資料後會自動release掉資料佔用的Bytebuffer資源。並且繼承該類需要指定資料格式。
而繼承ChannelInboundHandlerAdapter則不會自動釋放,需要手動呼叫ReferenceCountUtil.release()等方法進行釋放。繼承該類不需要指定資料格式。
所以在這裡,個人推薦服務端繼承ChannelInboundHandlerAdapter,手動進行釋放,防止資料未處理完就自動釋放了。而且服務端可能有多個客戶端進行連線,並且每一個客戶端請求的資料格式都不一致,這時便可以進行相應的處理。
客戶端根據情況可以繼承SimpleChannelInboundHandler類。好處是直接指定好傳輸的資料格式,就不需要再進行格式的轉換了。
程式碼如下:
@Service("nettyServerHandler")
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
/** 空閒次數 */
private int idle_count = 1;
/** 傳送次數 */
private int count = 1;
/**
* 建立連線時,傳送一條訊息
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("連線的客戶端地址:" + ctx.channel().remoteAddress());
UserInfo.UserMsg userMsg = UserInfo.UserMsg.newBuilder().setId(1).setAge(18).setName("xuwujing").setState(0)
.build();
ctx.writeAndFlush(userMsg);
super.channelActive(ctx);
}
/**
* 超時處理 如果5秒沒有接受客戶端的心跳,就觸發; 如果超過兩次,則直接關閉;
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
if (obj instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) obj;
if (IdleState.READER_IDLE.equals(event.state())) { // 如果讀通道處於空閒狀態,說明沒有接收到心跳命令
System.out.println("已經5秒沒有接收到客戶端的資訊了");
if (idle_count > 1) {
System.out.println("關閉這個不活躍的channel");
ctx.channel().close();
}
idle_count++;
}
} else {
super.userEventTriggered(ctx, obj);
}
}
/**
* 業務邏輯處理
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("第" + count + "次" + ",服務端接受的訊息:" + msg);
try {
// 如果是protobuf型別的資料
if (msg instanceof UserMsg) {
UserInfo.UserMsg userState = (UserInfo.UserMsg) msg;
if (userState.getState() == 1) {
System.out.println("客戶端業務處理成功!");
} else if(userState.getState() == 2){
System.out.println("接受到客戶端傳送的心跳!");
}else{
System.out.println("未知命令!");
}
} else {
System.out.println("未知資料!" + msg);
return;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
ReferenceCountUtil.release(msg);
}
count++;
}
/**
* 異常處理
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
還有個服務端的啟動類,之前是通過main方法直接啟動, 不過這裡改成了通過springBoot進行啟動,差別不大。
程式碼如下:
@SpringBootApplication
public class NettyServerApp {
public static void main(String[] args) {
// 啟動嵌入式的 Tomcat 並初始化 Spring 環境及其各 Spring 元件
ApplicationContext context = SpringApplication.run(NettyServerApp.class, args);
NettyServer nettyServer = context.getBean(NettyServer.class);
nettyServer.run();
}
}
到這裡服務端相應的程式碼就編寫完畢了。
客戶端
客戶端這邊的程式碼和服務端的很多地方都類似,我就不再過多細說了,主要將一些不同的程式碼拿出來簡單的講述下。
首先是客戶端的主類,基本和服務端的差不多,也就是多了監聽的埠和一個監聽器(用來監聽是否和服務端斷開連線,用於重連)。
主要實現的程式碼邏輯如下:
public void doConnect(Bootstrap bootstrap, EventLoopGroup eventLoopGroup) {
ChannelFuture f = null;
try {
if (bootstrap != null) {
bootstrap.group(eventLoopGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
bootstrap.handler(nettyClientFilter);
bootstrap.remoteAddress(host, port);
f = bootstrap.connect().addListener((ChannelFuture futureListener) -> {
final EventLoop eventLoop = futureListener.channel().eventLoop();
if (!futureListener.isSuccess()) {
System.out.println("與服務端斷開連線!在10s之後準備嘗試重連!");
eventLoop.schedule(() -> doConnect(new Bootstrap(), eventLoop), 10, TimeUnit.SECONDS);
}
});
if(initFalg){
System.out.println("Netty客戶端啟動成功!");
initFalg=false;
}
// 阻塞
f.channel().closeFuture().sync();
}
} catch (Exception e) {
System.out.println("客戶端連線失敗!"+e.getMessage());
}
}
注:監聽器這塊的實現用的是JDK1.8的寫法。
客戶端過濾其這塊基本和服務端一直。不過需要注意的是,傳輸協議、編碼和解碼應該一致,還有心跳的讀寫時間應該小於服務端所設定的時間。
改動的程式碼如下:
ChannelPipeline ph = ch.pipeline();
/*
* 解碼和編碼,應和服務端一致
* */
//入參說明: 讀超時時間、寫超時時間、所有型別的超時時間、時間格式
ph.addLast(new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS));
客戶端的業務程式碼邏輯。
主要實現的幾點邏輯是心跳按時傳送以及解析服務傳送的protobuf格式的資料。
這裡比服務端多個個註解, 該註解Sharable主要是為了多個handler可以被多個channel安全地共享,也就是保證執行緒安全。
廢話就不多說了,程式碼如下:
@Service("nettyClientHandler")
@ChannelHandler.Sharable
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
@Autowired
private NettyClient nettyClient;
/** 迴圈次數 */
private int fcount = 1;
/**
* 建立連線時
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("建立連線時:" + new Date());
ctx.fireChannelActive();
}
/**
* 關閉連線時
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("關閉連線時:" + new Date());
final EventLoop eventLoop = ctx.channel().eventLoop();
nettyClient.doConnect(new Bootstrap(), eventLoop);
super.channelInactive(ctx);
}
/**
* 心跳請求處理 每4秒傳送一次心跳請求;
*
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
System.out.println("迴圈請求的時間:" + new Date() + ",次數" + fcount);
if (obj instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) obj;
if (IdleState.WRITER_IDLE.equals(event.state())) { // 如果寫通道處於空閒狀態,就傳送心跳命令
UserMsg.Builder userState = UserMsg.newBuilder().setState(2);
ctx.channel().writeAndFlush(userState);
fcount++;
}
}
}
/**
* 業務邏輯處理
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 如果不是protobuf型別的資料
if (!(msg instanceof UserMsg)) {
System.out.println("未知資料!" + msg);
return;
}
try {
// 得到protobuf的資料
UserInfo.UserMsg userMsg = (UserInfo.UserMsg) msg;
// 進行相應的業務處理。。。
// 這裡就從簡了,只是列印而已
System.out.println(
"客戶端接受到的使用者資訊。編號:" + userMsg.getId() + ",姓名:" + userMsg.getName() + ",年齡:" + userMsg.getAge());
// 這裡返回一個已經接受到資料的狀態
UserMsg.Builder userState = UserMsg.newBuilder().setState(1);
ctx.writeAndFlush(userState);
System.out.println("成功傳送給服務端!");
} catch (Exception e) {
e.printStackTrace();
} finally {
ReferenceCountUtil.release(msg);
}
}
}
那麼到這裡客戶端的程式碼也編寫完畢了。
功能測試
首先啟動服務端,然後再啟動客戶端。
我們來看看結果是否如上述所說。
服務端輸出結果:
服務端啟動成功,埠是:9876
連線的客戶端地址:/127.0.0.1:53319
第1次,服務端接受的訊息:state: 1
客戶端業務處理成功!
第2次,服務端接受的訊息:state: 2
接受到客戶端傳送的心跳!
第3次,服務端接受的訊息:state: 2
接受到客戶端傳送的心跳!
第4次,服務端接受的訊息:state: 2
接受到客戶端傳送的心跳!
客戶端輸入結果:
Netty客戶端啟動成功!
建立連線時:Mon Jul 16 23:31:58 CST 2018
客戶端接受到的使用者資訊。編號:1,姓名:xuwujing,年齡:18
成功傳送給服務端!
迴圈請求的時間:Mon Jul 16 23:32:02 CST 2018,次數1
迴圈請求的時間:Mon Jul 16 23:32:06 CST 2018,次數2
迴圈請求的時間:Mon Jul 16 23:32:10 CST 2018,次數3
迴圈請求的時間:Mon Jul 16 23:32:14 CST 2018,次數4
通過列印資訊可以看出如上述所說。
接下來我們再來看看客戶端是否能夠實現重連。
先啟動客戶端,再啟動服務端。
客戶端輸入結果:
Netty客戶端啟動成功!
與服務端斷開連線!在10s之後準備嘗試重連!
客戶端連線失敗[email protected](incomplete)
建立連線時:Mon Jul 16 23:41:33 CST 2018
客戶端接受到的使用者資訊。編號:1,姓名:xuwujing,年齡:18
成功傳送給服務端!
迴圈請求的時間:Mon Jul 16 23:41:38 CST 2018,次數1
迴圈請求的時間:Mon Jul 16 23:41:42 CST 2018,次數2
迴圈請求的時間:Mon Jul 16 23:41:46 CST 2018,次數3
服務端輸出結果:
服務端啟動成功,埠是:9876
連線的客戶端地址:/127.0.0.1:53492
第1次,服務端接受的訊息:state: 1
客戶端業務處理成功!
第2次,服務端接受的訊息:state: 2
接受到客戶端傳送的心跳!
第3次,服務端接受的訊息:state: 2
接受到客戶端傳送的心跳!
第4次,服務端接受的訊息:state: 2
結果也如上述所說!
其它
關於SpringBoot整合Netty使用Protobuf進行資料傳輸到這裡就結束了。
SpringBoot整合Netty使用Protobuf進行資料傳輸的專案工程地址:
https://github.com/xuwujing/springBoot-study/tree/master/springboot-netty-protobuf
對了,也有不使用springBoot整合的Netty專案工程地址:
https://github.com/xuwujing/Netty-study/tree/master/Netty-protobuf
原創不易,如果感覺不錯,希望給個推薦!您的支援是我寫作的最大動力!
版權宣告:
作者:虛無境
部落格園出處:http://www.cnblogs.com/xuwujing
CSDN出處:http://blog.csdn.net/qazwsxpcm
個人部落格出處:http://www.panchengming.com
相關推薦
SpringBoot整合Netty並使用Protobuf進行資料傳輸(附工程)
前言 本篇文章主要介紹的是SpringBoot整合Netty以及使用Protobuf進行資料傳輸的相關內容。Protobuf會簡單的介紹下用法,至於Netty在之前的文章中已經簡單的介紹過了,這裡就不再過多細說了。 Protobuf 介紹 protocolbuffer(以下簡稱PB)是google 的一種資
Netty整合SpringBoot並使用Protobuf進行資料傳輸
<build> <extensions> <extension> <groupId>kr.motd.maven</groupId>
SSM下整合netty使用佇列進行檔案傳輸demo
原創文章 自己在閒暇無事的時候做的一些小demo,在這裡分享出來給大家 @Service @Scope("prototype") public class PictureServiceImpl implements PictureService {
高效能NIO框架Netty-整合Protobuf高效能資料傳輸
前言 上篇文章我們整合了kryo來進行資料的傳輸編解碼,今天將繼續學習使用Protobuf來編解碼。Netty對Protobuf的支援比較好,還提供了Protobuf的編解碼器,非常方便。 Protobuf介紹 Protobuf是google開
Android手機通過wifi進行資料傳輸(二)
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
SpringBoot整合Netty之Websocket
前後端通過websocket通訊進行聊天~ 核心程式碼整理如下: netty元件 @Component public class NettyBooter implements ApplicationListener<ContextRefreshedEvent> {
第6章 使用springboot整合netty搭建後臺
我們不會去使用自增長的id,在現階段的網際網路開發過程中,自增長的id是已經不適用了。在未來隨著系統版本的迭代,使用者數量的遞增,肯定會做分庫分表,去做一些相應的切分。在這個時候我們就需要有一個唯一的id。專案裡面會有一個唯一id的外掛去使用。所有的主鍵id都會使用一個字串varchar。小頭像是預覽過程
SpringBoot整合websocket並區分不同頁面來源
首先web.xml新增支援 <!-- 新增websocket支援 --> <dependency> <groupId>org.springframework.boot</groupId>
SpringBoot整合MybatisPlus並實現分頁查詢
首先https://start.spring.io/下載一個springBoot的demo。 然後增加pomyila依賴,引入以下pom,除了MybatisPlus其他自己分配 <?xml version="1.0" encoding="UTF-8"?> <
三分鐘構建高效能WebSocket服務 | 超優雅的Springboot整合Netty方案
前言 每當使用SpringBoot進行Weboscket開發時,最容易想到的就是spring-boot-starter-websocket(或spring-websocket)。它可以讓我們使用註解,很簡單的進行Websocket開發,讓我們更多的關注業務邏輯。它底層使用的是Tomcat,且不說把整個Tom
springboot 整合mongodb並操作簡單增刪改查
宣告: 執行環境:jdk 1.8、maven3.5.4、spingboot 2.0、mongodb、等 操作步驟: 第一步:pom檔案中新增jar包依賴(正常情況下) <!--mongodb --> <dependency>
用SpringBoot整合Netty開發一個基於WebSocket的聊天室
前言 基於SpringBoot,藉助Netty控制長連結,使用WebSocket協議做一個實時的聊天室。 專案效果 專案統一登入路徑: http://localhost:8080/chat/netty 使用者名稱隨機生成,離線呼叫非同步方法,資料寫操作,登入顯示歷史聊天
Netty(二) springboot 整合netty編寫時間伺服器
這個例子與上個例子( springboot 整合netty做心跳檢測)最大的不同就是,服務端傳送包含32位整數的訊息,而不接收任何請求,並在傳送訊息後關閉連線。 因為我們將忽略任何接收到的資料,一旦建立
SpringBoot整合Netty,Handler中@Autowired註解為空
最近建了個技術交流群,然後好多小夥伴都問關於Netty的問題,尤其今天的問題最特殊,功能大概是要在Netty接收訊息時把資料寫入資料庫,那個小夥伴用的是 Spring Boot + MyBatis + Netty,所以就碰到了Handler中@Autowired註解為空的問題 參考了
[springBoot] Springboot 整合redis並實現自定義序列化遇到的問題
當我們使用@Cacheable註解的時候會將返回的物件快取起來,我們會發現預設快取的值是二進位制的,不方便檢視,為此我們自定義序列化配置,改成JSON格式的 配置如下: pom.xml <?xml version="1.0" encoding="UTF-8"?&
extjs 使用Ext.Ajax.request進行資料傳輸
java程式碼 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// TODO Aut
SpringBoot整合Shiro、JWT 進行請求認證和鑑權
什麼是JWT? JSON Web Token(JWT)是一個開放標準(RFC 7519),它定義了一種緊湊且獨立的方式,可以在各方之間作為JSON物件安全地傳輸資訊。此資訊可以通過數字簽名進行驗證和信任。JWT可以使用祕密(使用HMAC演算法)或使用RSA或ECDSA的公鑰/私鑰對進
SpringBoot整合Elasticsearch並實現CRUD操作
配置準備 在build.gradle檔案中新增如下依賴: compile "org.elasticsearch.client:transport:5.5.2" compile "org.elasticsearch:elasticsearch:
SpringBoot整合netty實現客戶端服務端互動
看了好幾天的netty實戰,慢慢摸索,雖然還沒有摸著很多門道,但今天還是把之前想加入到專案裡的 一些想法實現了,算是有點信心了吧(講真netty對初學者還真的不是很友好......) 首先,當然是在SpringBoot專案裡新增netty的依賴了,注意不要用netty5的依賴,因為已經廢棄
Flume Avro 兩臺機器間進行資料傳輸的方式
flume 通過avro方式在兩臺機器之間進行資料傳輸 比如要在192.168.17.18 上把資料傳到 192.168.17.17 1 首先要再兩臺機器上都部署 flume 2 在 17 flume下這樣配置 avro-flume.conf agent3.channel