SpringBoot+Guacamole实现远程桌面教程

 更新时间:2025年10月13日 09:36:38   作者:肥仔哥哥1930  
文章讨论了坐席远程帮办的技术解决方案,比较了VNC和RDP两种协议的优缺点,最终选择了基于RDP的Guacamole框架,文中详细介绍了Guacamole的部署方法和如何通过Springboot集成,同时也提供了一些关于远程桌面技术的基础知识和实际应用的建议

前言

最近不是在想方案,就是在方案的预研上,头发越来越少啊。

今天要跟大家分享的是坐席远程帮办,名字定义很高大,技术落地实际上就是远程桌面+语音指导。

技术选型

我们团队很健全,各语种的研发都有,但是就是兄弟们现在都项目缠身。

我作为技术负责人,肯定是要自己先有方向,至少要能够在各种需求场景抛砖引玉吧。所以在远程桌面这块先行预研,先给C语种方向的兄弟整个可行性高点的方案:

1、https://github.com/xunki/RemoteDesktopManage

2、java方向我自己来

远程桌面协议分析

其实在选型时也是各方考量,首先是要不能用人民币,用人民币要考虑投入与回报是否对等。然后就是要考量我们现在的人力储备、技术底蕴等等。

在这过程中,首先是考量资源、带宽,然后就是针对VNC与RDP协议的抉择了。

按说VNC协议旧,那肯定就是资源多、可参考的资料就相对多,但是对比优缺点,实在是不想到时候因为效果、延时等影响形象,免得到时候吃亏了还不讨好(按说不应该太计较个人得失,可是现实很残酷啊)。

废话不说了,先看对比协议:

原理与协议

特性VNC(Virtual Network Computing)RDP(Remote Desktop Protocol)
协议类型基于 RFB(Remote Frame Buffer)协议,传输的是屏幕像素信息微软专有协议,传输 图形对象、指令、音视频、剪贴板 等
工作方式服务器端抓取屏幕像素并发送给客户端客户端发送操作命令,服务器端渲染界面并发送指令给客户端,客户端再绘制界面
平台支持跨平台,Windows / Linux / macOS / 嵌入式主要是 Windows,但有 Linux/macOS 客户端支持

性能与体验

特性VNCRDP
带宽占用较高,因为传输的是像素较低,因为只传输界面指令而非像素
响应速度较慢,高分辨率时延迟明显快,延迟低,尤其在低带宽下表现更好
图像质量像素传输,容易有模糊或延迟高质量,支持压缩和多种图形加速
音频/多媒体一般不传输音频,需要额外设置原生支持音频重定向、多媒体优化

功能与安全

特性VNCRDP
文件传输一般需要额外工具原生支持文件共享
剪贴板共享支持,但实现依赖客户端原生支持
多会话通常一个显示器对应一个会话(Linux 可以多个会话)Windows 支持多用户多会话
安全性默认明文传输,需要加密(SSH/VPN)支持 TLS 加密、网络级认证(NLA)

使用场景

场景适合VNC适合RDP
跨平台远程访问非 Windows 客户端有限
高性能远程办公
服务器管理Linux 常用Windows Server
低带宽环境RDP 优化带宽

小结

VNC

  • 优点:跨平台、轻量、简单
  • 缺点:性能低、延迟大、默认不安全
  • 适合远程监控、嵌入式系统、跨平台访问

RDP

  • 优点:低延迟、高性能、功能丰富(音频、剪贴板、文件)
  • 缺点:跨平台受限,Windows 外的体验不如原生
  • 适合 Windows 远程办公、远程服务器管理

架构选型

经过多方了解,既然VNC放弃,那java基于VNC的UltraVNC就不看了。

RDP了解到的就是Guacamole,而且活力还很大哦,最近才升级。

https://guacamole.apache.org/releases/1.6.0/

具体部署细节,看官网就行,建议用docker,部署guacamole-server/guacamole-client。

如果不用docker,用tomcat部署client,那就有点折腾,其实,也就是tomcat放war包的地方要放扩展包,也就是处理授权的,官网提供了对应jar,放在extensions目录下。

要理解的是

  • guacamole-server(guacd)提供服务
  • guacamole-client(RestAPI客户端)对外暴露接口

整体逻辑

浏览器 (HTML5/JS)

 │ WebSocket

 ▼

Java Web 应用 ── REST API ──► Guacamole (guacd)

                            │

                            ▼

                       Windows RDP Server

我们java能做的就是在Java Web应用层做认证、连接管理等等。

再来看看springboot的集成吧。

就是一个普通的Springboot服务,关于Guacamole不需要额外的依赖,要说用到的,那就是Hutool的HttpUtil请求工具类。其实还有一种集成方案,那个就需要相关依赖,但是那个要自己造的轮子也多,不适合快速落地。

RdpController

/**
 * RDP管理
 *
 * @author zwmac
 */
@Slf4j
@RestController
@RequestMapping("/rdp")
public class RdpController {

    @Resource
    private GuacamoleRestService guacamoleRestService;

    /**
     * guacamole登录
     *
     * @param rdpInfoVo 登录信息
     * @return 登录结果
     */
    @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 添加结果
     */
    @PostMapping("/addConnection")
    public RestResponse<?> addConnection(@RequestBody RdpConnectionInfoVo rdpConnectionInfoVo) {
        return guacamoleRestService.addConnection(rdpConnectionInfoVo);
    }


}

GuacamoleRestService

/**
 * @author zwmac
 */
public interface GuacamoleRestService {
    /**
     * guacamole登录
     *
     * @param username 用户名
     * @param password 密码
     * @return 登录结果
     */
    RestResponse<?> login(String username, String password);

    /**
     * 列出所有连接
     *
     * @param token
     * @return
     */
    RestResponse<?> listConnections(String token);

    /**
     * 添加连接
     *
     * @param rdpConnectionInfoVo 连接信息
     * @return 添加结果
     */
    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) {
        //参数校验
        Assert.notNull(rdpConnectionInfoVo, "参数不能为空");

        return null;
    }
}

配置项

guacamole:
  base-url: http://你的guacamole部署ip:端口/guacamole/api
  datasource: mysql   # 对应 guacamole.properties 里的配置
  admin-user: guacadmin
  admin-password: guacadmin

最后,看看效果:

Apifox接口:

guacamole服务端管理界面:

远程效果:

总结

好了,就写到这里,希望能帮到大家。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

其实还是那句话,关键的关键是要有思路,思路很重要!!!

相关文章

  • JDK自带监控工具jstat、jmap、jstack的使用指南(附命令示例)

    JDK自带监控工具jstat、jmap、jstack的使用指南(附命令示例)

    jstat是JDK中提供的一个命令行工具,主要用来打印JVM 性能数据相关的统计数据,这篇文章主要介绍了JDK自带监控工具jstat、jmap、jstack的使用指南,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-01-01
  • IntelliJ IDEA 2021.1 首个 Beta 版本发布

    IntelliJ IDEA 2021.1 首个 Beta 版本发布

    这篇文章主要介绍了IntelliJ IDEA 2021.1 首个 Beta 版本发布,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • SpringMVC+Spring+Mybatis实现支付宝支付功能的示例代码

    SpringMVC+Spring+Mybatis实现支付宝支付功能的示例代码

    这篇文章主要介绍了SpringMVC+Spring+Mybatis实现支付宝支付功能的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • Java中的Random和ThreadLocalRandom详细解析

    Java中的Random和ThreadLocalRandom详细解析

    这篇文章主要介绍了Java中的Random和ThreadLocalRandom详细解析,Random 类用于生成伪随机数的流, 该类使用48位种子,其使用线性同余公式进行修改,需要的朋友可以参考下
    2024-01-01
  • Java处理日期时间的方法汇总

    Java处理日期时间的方法汇总

    这篇文章主要给大家介绍了利用Java中的Calendar 类处理日期时间的方法汇总,其中包括取日期的每部分、取当月的第一天或最后一天、求两个日期之间相隔的天数以及一年前的日期等等的示例代码,有需要的朋友们可以直接参考借鉴,下面来一起看看吧。
    2016-12-12
  • springboot的controller中如何获取applicatim.yml的配置值

    springboot的controller中如何获取applicatim.yml的配置值

    本文介绍了在SpringBoot的Controller中获取application.yml配置值的四种方式,并举例说明了每种方式的使用场景和优缺点,结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • 使用maven创建普通项目命令行程序详解

    使用maven创建普通项目命令行程序详解

    大部分使用maven创建的是web项目,这里使用maven创建一个命令行程序,目的是让大家了解maven特点和使用方式,有需要的朋友可以借鉴参考下
    2021-10-10
  • Windows中使用Java生成Excel文件并插入图片的方法

    Windows中使用Java生成Excel文件并插入图片的方法

    这篇文章主要介绍了Windows中使用Java生成Excel文件并插入图片的方法,其中向Excel中插入图片文中通过使用Apache POI来实现,需要的朋友可以参考下
    2016-02-02
  • Java调用JavaScript实现字符串计算器代码示例

    Java调用JavaScript实现字符串计算器代码示例

    这篇文章主要介绍了Java调用JavaScript实现字符串计算器代码示例,具有一定参考价值,需要的朋友可以了解下。
    2017-12-12
  • Maven仓库的具体使用(本地仓库+远程仓库)

    Maven仓库的具体使用(本地仓库+远程仓库)

    Maven 在某个统一的位置存储所有项目的构件,这个统一的位置,我们就称之为仓库,本文主要介绍了Maven仓库的具体使用(本地仓库+远程仓库),感兴趣的可以了解一下
    2023-11-11

最新评论