SpringBoot+Guacamole實(shí)現(xiàn)遠(yuǎn)程桌面教程
前言
最近不是在想方案,就是在方案的預(yù)研上,頭發(fā)越來越少啊。
今天要跟大家分享的是坐席遠(yuǎn)程幫辦,名字定義很高大,技術(shù)落地實(shí)際上就是遠(yuǎn)程桌面+語音指導(dǎo)。
技術(shù)選型
我們團(tuán)隊(duì)很健全,各語種的研發(fā)都有,但是就是兄弟們現(xiàn)在都項(xiàng)目纏身。
我作為技術(shù)負(fù)責(zé)人,肯定是要自己先有方向,至少要能夠在各種需求場景拋磚引玉吧。所以在遠(yuǎn)程桌面這塊先行預(yù)研,先給C語種方向的兄弟整個(gè)可行性高點(diǎn)的方案:
1、https://github.com/xunki/RemoteDesktopManage
2、java方向我自己來
遠(yuǎn)程桌面協(xié)議分析
其實(shí)在選型時(shí)也是各方考量,首先是要不能用人民幣,用人民幣要考慮投入與回報(bào)是否對等。然后就是要考量我們現(xiàn)在的人力儲備、技術(shù)底蘊(yùn)等等。
在這過程中,首先是考量資源、帶寬,然后就是針對VNC與RDP協(xié)議的抉擇了。
按說VNC協(xié)議舊,那肯定就是資源多、可參考的資料就相對多,但是對比優(yōu)缺點(diǎn),實(shí)在是不想到時(shí)候因?yàn)樾Ч?、延時(shí)等影響形象,免得到時(shí)候吃虧了還不討好(按說不應(yīng)該太計(jì)較個(gè)人得失,可是現(xiàn)實(shí)很殘酷啊)。
廢話不說了,先看對比協(xié)議:
原理與協(xié)議
| 特性 | VNC(Virtual Network Computing) | RDP(Remote Desktop Protocol) |
|---|---|---|
| 協(xié)議類型 | 基于 RFB(Remote Frame Buffer)協(xié)議,傳輸?shù)氖瞧聊幌袼匦畔?/td> | 微軟專有協(xié)議,傳輸 圖形對象、指令、音視頻、剪貼板 等 |
| 工作方式 | 服務(wù)器端抓取屏幕像素并發(fā)送給客戶端 | 客戶端發(fā)送操作命令,服務(wù)器端渲染界面并發(fā)送指令給客戶端,客戶端再繪制界面 |
| 平臺支持 | 跨平臺,Windows / Linux / macOS / 嵌入式 | 主要是 Windows,但有 Linux/macOS 客戶端支持 |
性能與體驗(yàn)
| 特性 | VNC | RDP |
|---|---|---|
| 帶寬占用 | 較高,因?yàn)閭鬏數(shù)氖窍袼?/td> | 較低,因?yàn)橹粋鬏斀缑嬷噶疃窍袼?/td> |
| 響應(yīng)速度 | 較慢,高分辨率時(shí)延遲明顯 | 快,延遲低,尤其在低帶寬下表現(xiàn)更好 |
| 圖像質(zhì)量 | 像素傳輸,容易有模糊或延遲 | 高質(zhì)量,支持壓縮和多種圖形加速 |
| 音頻/多媒體 | 一般不傳輸音頻,需要額外設(shè)置 | 原生支持音頻重定向、多媒體優(yōu)化 |
功能與安全
| 特性 | VNC | RDP |
|---|---|---|
| 文件傳輸 | 一般需要額外工具 | 原生支持文件共享 |
| 剪貼板共享 | 支持,但實(shí)現(xiàn)依賴客戶端 | 原生支持 |
| 多會話 | 通常一個(gè)顯示器對應(yīng)一個(gè)會話(Linux 可以多個(gè)會話) | Windows 支持多用戶多會話 |
| 安全性 | 默認(rèn)明文傳輸,需要加密(SSH/VPN) | 支持 TLS 加密、網(wǎng)絡(luò)級認(rèn)證(NLA) |
使用場景
| 場景 | 適合VNC | 適合RDP |
|---|---|---|
| 跨平臺遠(yuǎn)程訪問 | 是 | 非 Windows 客戶端有限 |
| 高性能遠(yuǎn)程辦公 | 否 | 是 |
| 服務(wù)器管理 | Linux 常用 | Windows Server |
| 低帶寬環(huán)境 | 否 | RDP 優(yōu)化帶寬 |
小結(jié)
VNC
- 優(yōu)點(diǎn):跨平臺、輕量、簡單
- 缺點(diǎn):性能低、延遲大、默認(rèn)不安全
- 適合遠(yuǎn)程監(jiān)控、嵌入式系統(tǒng)、跨平臺訪問
RDP
- 優(yōu)點(diǎn):低延遲、高性能、功能豐富(音頻、剪貼板、文件)
- 缺點(diǎn):跨平臺受限,Windows 外的體驗(yàn)不如原生
- 適合 Windows 遠(yuǎn)程辦公、遠(yuǎn)程服務(wù)器管理
架構(gòu)選型
經(jīng)過多方了解,既然VNC放棄,那java基于VNC的UltraVNC就不看了。
RDP了解到的就是Guacamole,而且活力還很大哦,最近才升級。
https://guacamole.apache.org/releases/1.6.0/

具體部署細(xì)節(jié),看官網(wǎng)就行,建議用docker,部署guacamole-server/guacamole-client。
如果不用docker,用tomcat部署client,那就有點(diǎn)折騰,其實(shí),也就是tomcat放war包的地方要放擴(kuò)展包,也就是處理授權(quán)的,官網(wǎng)提供了對應(yīng)jar,放在extensions目錄下。
要理解的是
- guacamole-server(guacd)提供服務(wù)
- guacamole-client(RestAPI客戶端)對外暴露接口
整體邏輯
瀏覽器 (HTML5/JS)
│ WebSocket ▼
Java Web 應(yīng)用 ── REST API ──? Guacamole (guacd)
│
▼
Windows RDP Server
我們java能做的就是在Java Web應(yīng)用層做認(rèn)證、連接管理等等。
再來看看springboot的集成吧。
就是一個(gè)普通的Springboot服務(wù),關(guān)于Guacamole不需要額外的依賴,要說用到的,那就是Hutool的HttpUtil請求工具類。其實(shí)還有一種集成方案,那個(gè)就需要相關(guān)依賴,但是那個(gè)要自己造的輪子也多,不適合快速落地。
RdpController
/**
* RDP管理
*
* @author zwmac
*/
@Slf4j
@RestController
@RequestMapping("/rdp")
public class RdpController {
@Resource
private GuacamoleRestService guacamoleRestService;
/**
* guacamole登錄
*
* @param rdpInfoVo 登錄信息
* @return 登錄結(jié)果
*/
@GetMapping("/login")
public RestResponse<?> login(@RequestBody RdpInfoVo rdpInfoVo) {
return guacamoleRestService.login(rdpInfoVo.getUsername(), rdpInfoVo.getPassword());
}
/**
* 列出所有連接
*
* @param token 登錄token
* @return 連接列表
*/
@GetMapping("/listConnections")
public RestResponse<?> listConnections(@RequestParam String token) {
return guacamoleRestService.listConnections(token);
}
/**
* 添加連接
*
* @param rdpConnectionInfoVo 連接信息
* @return 添加結(jié)果
*/
@PostMapping("/addConnection")
public RestResponse<?> addConnection(@RequestBody RdpConnectionInfoVo rdpConnectionInfoVo) {
return guacamoleRestService.addConnection(rdpConnectionInfoVo);
}
}
GuacamoleRestService
/**
* @author zwmac
*/
public interface GuacamoleRestService {
/**
* guacamole登錄
*
* @param username 用戶名
* @param password 密碼
* @return 登錄結(jié)果
*/
RestResponse<?> login(String username, String password);
/**
* 列出所有連接
*
* @param token
* @return
*/
RestResponse<?> listConnections(String token);
/**
* 添加連接
*
* @param rdpConnectionInfoVo 連接信息
* @return 添加結(jié)果
*/
RestResponse<?> addConnection(RdpConnectionInfoVo rdpConnectionInfoVo);
}
GuacamoleRestServiceImpl
/**
* @author zwmac
*/
@Service
public class GuacamoleRestServiceImpl implements GuacamoleRestService {
@Value("${guacamole.base-url}")
private String guacamoleBaseUrl;
@Value("${guacamole.datasource}")
private String datasource;
@Value("${guacamole.admin-user}")
private String adminUserName;
@Value("${guacamole.admin-password}")
private String adminPassword;
@Autowired
private RestTemplate restTemplate;
@Override
public RestResponse<?> login(String username, String password) {
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
username = adminUserName;
password = adminPassword;
}
Assert.isTrue(!StringUtils.isAnyBlank(username, password), "用戶名或密碼不能為空");
Map<String, Object> formMap = new HashMap<>();
formMap.put("username", username);
formMap.put("password", password);
HttpRequest post = HttpUtil.createPost(guacamoleBaseUrl + "/tokens");
post.form(formMap);
post.header("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
HttpResponse execute = post.execute();
if (execute.isOk()) {
String executeBody = execute.body();
return RestResponse.success(executeBody);
}
return RestResponse.fail("登錄失?。? + execute.body());
}
@Override
public RestResponse<?> listConnections(String token) {
Assert.hasText(token, "token不能為空");
String getUrl = guacamoleBaseUrl + "/session/data/" + datasource + "/connections?token=" + token;
HttpRequest get = HttpUtil.createGet(getUrl);
HttpResponse execute = get.execute();
if (execute.isOk()) {
String executeBody = execute.body();
return RestResponse.success(executeBody);
}
return RestResponse.fail("獲取連接列表失敗:" + execute.body());
}
@Override
public RestResponse<?> addConnection(RdpConnectionInfoVo rdpConnectionInfoVo) {
//參數(shù)校驗(yàn)
Assert.notNull(rdpConnectionInfoVo, "參數(shù)不能為空");
return null;
}
}
配置項(xiàng)
guacamole: base-url: http://你的guacamole部署ip:端口/guacamole/api datasource: mysql # 對應(yīng) guacamole.properties 里的配置 admin-user: guacadmin admin-password: guacadmin
最后,看看效果:
Apifox接口:

guacamole服務(wù)端管理界面:


遠(yuǎn)程效果:

總結(jié)
好了,就寫到這里,希望能幫到大家。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
其實(shí)還是那句話,關(guān)鍵的關(guān)鍵是要有思路,思路很重要?。?!
- SpringBoot下使用RestTemplate實(shí)現(xiàn)遠(yuǎn)程服務(wù)調(diào)用的詳細(xì)過程
- SpringBoot基于AOP的本地/遠(yuǎn)程調(diào)用動態(tài)路由實(shí)踐指南
- SpringBoot實(shí)現(xiàn)本地與遠(yuǎn)程方法調(diào)用的無縫切換
- springboot整合retrofit實(shí)現(xiàn)本地接口調(diào)用遠(yuǎn)程服務(wù)方式
- SpringBoot項(xiàng)目中使用Netty實(shí)現(xiàn)遠(yuǎn)程調(diào)用的示例代碼
- 使用IDEA對SpringBoot應(yīng)用進(jìn)行遠(yuǎn)程調(diào)試方式
- springboot項(xiàng)目中使用docker進(jìn)行遠(yuǎn)程部署的實(shí)現(xiàn)
相關(guān)文章
Java equals 方法與hashcode 方法的深入解析
面試時(shí)經(jīng)常會問起字符串比較相關(guān)的問題,比如:字符串比較時(shí)用的什么方法,內(nèi)部實(shí)現(xiàn)如何?hashcode的作用,以及重寫equal方法,為什么要重寫hashcode方法?以下就為大家解答,需要的朋友可以參考下2013-07-07
java實(shí)現(xiàn)的n*n矩陣求值及求逆矩陣算法示例
這篇文章主要介紹了java實(shí)現(xiàn)的n*n矩陣求值及求逆矩陣算法,結(jié)合具體實(shí)例形式分析了java基于數(shù)組的矩陣定義、遍歷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2017-09-09
Java實(shí)現(xiàn)統(tǒng)計(jì)文檔中關(guān)鍵字出現(xiàn)的次數(shù)
這篇文章主要為大家分享了利用Java語言實(shí)現(xiàn)統(tǒng)計(jì)關(guān)鍵字在文檔中出現(xiàn)的次數(shù)的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-05-05
關(guān)于MyBatis的foreach標(biāo)簽常用方法
這篇文章主要介紹了關(guān)于MyBatis的foreach標(biāo)簽常用方法,foreach 標(biāo)簽可以用來遍歷數(shù)組、列表和 Map 等集合參數(shù),實(shí)現(xiàn)批量操作或一些簡單 SQL 操作,需要的朋友可以參考下2023-05-05
SpringBoot實(shí)現(xiàn)Tomcat集群的會話管理功能
在使用 Tomcat 集群時(shí),由于每個(gè) Tomcat 實(shí)例的 Session 存儲是獨(dú)立的,導(dǎo)致無法實(shí)現(xiàn) Session 的共享,這可能影響到用戶跨節(jié)點(diǎn)的訪問,為了實(shí)現(xiàn)跨 Tomcat 實(shí)例共享 Session,可以使用 Spring Session 配合 Redis 進(jìn)行集中式會話管理,需要的朋友可以參考下2024-12-12
dubbo環(huán)境搭建ZooKeeper注冊中心全過程
文章介紹Dubbo環(huán)境搭建,包含ZooKeeper注冊中心的安裝配置(修改數(shù)據(jù)存儲路徑、啟動服務(wù)并驗(yàn)證節(jié)點(diǎn))和dubbo-admin監(jiān)控中心的部署流程(解壓、打包、運(yùn)行jar包,需注意Maven版本及zkServer狀態(tài))2025-07-07
SpringBoot結(jié)合mybatis-plus實(shí)現(xiàn)分頁的項(xiàng)目實(shí)踐
本文主要介紹了SpringBoot結(jié)合mybatis-plus實(shí)現(xiàn)分頁的項(xiàng)目實(shí)踐,主要基于MyBatis-Plus 自帶的分頁插件 PaginationInterceptor,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Java 數(shù)據(jù)庫連接池詳解及簡單實(shí)例
這篇文章主要介紹了Java 數(shù)據(jù)庫連接池詳解及簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下2016-12-12

