杰瑞科技汇

JavaScript如何调用Java方法?

  1. 浏览器端 (Client-Side):在用户的浏览器中,通过某种技术让 JavaScript 执行 Java 代码,这种场景在现代 Web 开发中非常罕见,因为浏览器本身不直接支持 Java,我们通常使用 WebAssembly (Wasm) 来执行其他语言编译的代码,而 Java 到 Wasm 的生态还不成熟。
  2. 服务器端或后端通信 (Server-Side / Backend Communication):这是最常见、最主流的场景,JavaScript 代码(在浏览器中运行的网页前端,或者使用 Node.js 构建的后端服务)通过网络请求与一个独立的 Java 应用程序(通常是后端服务器)进行通信,让 Java 应用程序执行任务并返回结果。

下面我将详细讲解这两种情况,并重点介绍主流的实现方式。


浏览器端 JavaScript 调用 Java (不推荐,已过时)

在 Java Applet 被淘汰之前,这是唯一的方式,现在几乎不再使用。

Java Applet (已过时,被浏览器弃用)

这是最早的方式,开发者将 Java 代码编译成 .class 文件,然后嵌入到 HTML 的 <applet> 标签中,浏览器需要安装 Java 插件来运行这些 Applet。

HTML 示例:

<applet code="MyApplet.class" width="300" height="300">
  Your browser does not support the applet tag.
</applet>

为什么被淘汰?

  • 安全性问题:Applet 拥有很高的系统权限,容易成为病毒和恶意软件的温床。
  • 插件依赖:用户必须手动安装并启用 Java 插件,体验差。
  • 性能问题:启动慢,资源消耗大。
  • 跨平台兼容性差:不同浏览器、不同版本的 Java 运行环境表现不一。

不要在任何新项目中使用 Applet,它已经是历史产物。

GWT (Google Web Toolkit)

GWT 是一个前端框架,它允许开发者用 Java 语言编写前端代码,GWT 编译器会将其转换成优化的 JavaScript 代码,最终在浏览器中运行。

工作原理:

  1. 你用 Java 编写 UI 组件和业务逻辑。
  2. GWT 编译器将你的 Java 代码翻译成 JavaScript。
  3. 部署生成的 HTML 和 JavaScript 文件到服务器。
  4. 用户访问网页,浏览器直接执行生成的 JavaScript,实现了“用 Java 开发前端”的目标。

注意:这里不是 JS "调用" Java,而是 Java "变成" 了 JS,两者之间没有实时的交互调用。

GWT 是一个特定的开发框架,而不是一个通用的 JS 调用 Java 的工具,它的流行度也已大幅下降。


JavaScript 与 Java 后端通信 (主流方式)

这是现代 Web 应用的标准架构,JavaScript 运行在浏览器或 Node.js 环境中,它通过网络协议(如 HTTP)向一个 Java 后端服务发送请求,Java 服务处理请求后,将结果以某种格式(如 JSON)返回给 JavaScript。

核心思想:API 通信

JavaScript 和 Java 是两个独立的应用程序,它们通过预先定义好的“接口”(API, Application Programming Interface)来通信,最常见的 API 风格是 RESTful API

工作流程:

  1. Java 后端:创建一个 Web 服务器(例如使用 Spring Boot),并暴露一些 API 端点(Endpoint),如 /api/users, /api/data
  2. JavaScript 前端:当需要调用 Java 逻辑时(用户点击“获取数据”按钮),前端代码会使用 fetch (现代浏览器) 或 axios (流行的库) 发送一个 HTTP 请求(如 GET, POST)到 Java 后端的 API 端点。
  3. Java 后端处理:Java 后端接收到请求,执行相应的业务逻辑(比如查询数据库、进行复杂计算等)。
  4. 返回结果:Java 后端将处理结果序列化成 JSON 格式,然后通过 HTTP 响应返回给 JavaScript。
  5. JavaScript 处理结果:前端接收到 JSON 数据,解析后更新页面内容,展示给用户。

主流实现技术栈

下面我们来看几种具体的技术组合,来实现这种通信。

Java Spring Boot + JavaScript (Fetch/Axios)

这是目前最流行、最强大的组合,Spring Boot 简化了 Java Web 服务的开发,而现代前端框架(React, Vue, Angular)或原生 JS 都能轻松地通过 HTTP 请求与之通信。

Java 后端 (Spring Boot 示例)

你需要一个 Spring Boot 项目,它会自动为你配置好 Web 服务器。

// 一个简单的 Controller,用来处理 HTTP 请求
import org.springframework.web.bind.annotation.*;
@RestController // 告诉 Spring 这是一个控制器,所有方法的返回值会直接写入 HTTP 响应体
@RequestMapping("/api") // 为这个控制器下的所有端点设置一个基础路径
public class MyJavaController {
    // 定义一个 GET 请求的端点,路径是 /hello
    @GetMapping("/hello")
    public String sayHello() {
        // 这里是你要执行的 Java 逻辑
        return "Hello from Java Spring Boot!";
    }
    // 定义一个 POST 请求的端点,接收一个 JSON 对象并返回处理结果
    @PostMapping("/process")
    public MyResponse processData(@RequestBody MyRequest request) {
        // 执行一些复杂的业务逻辑
        String processedData = "Processed: " + request.getData();
        // 返回一个自定义的响应对象,Spring Boot 会自动将其转换为 JSON
        return new MyResponse(processedData, "success");
    }
}
// 请求和响应的简单数据模型 (POJO)
class MyRequest {
    private String data;
    // getters and setters
}
class MyResponse {
    private String result;
    private String status;
    // constructor, getters and setters
}

JavaScript 前端 (Fetch API 示例)

在 HTML 文件中,你可以这样调用上面的 Java 接口。

<button id="callJavaBtn">调用 Java 后端</button>
<div id="result"></div>
<script>
    document.getElementById('callJavaBtn').addEventListener('click', async () => {
        const resultDiv = document.getElementById('result');
        try {
            // --- 调用 GET 请求 ---
            const getResponse = await fetch('/api/hello');
            const getText = await getResponse.text();
            console.log(getText); // "Hello from Java Spring Boot!"
            // --- 调用 POST 请求 ---
            const postData = {
                data: "This is data from JS"
            };
            const postResponse = await fetch('/api/process', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(postData),
            });
            const postResult = await postResponse.json(); // 解析 JSON 响应
            console.log(postResult); // {result: "Processed: This is data from JS", status: "success"}
            // 在页面上显示结果
            resultDiv.innerHTML = `<p>GET Result: ${getText}</p><p>POST Result: ${postResult.result}</p>`;
        } catch (error) {
            console.error('Error calling Java backend:', error);
            resultDiv.innerHTML = 'An error occurred.';
        }
    });
</script>

优点

  • 解耦:前端和后端可以独立开发、部署和扩展。
  • 技术灵活:前端可以用任何技术栈(React, Vue, Angular, Svelte 等),后端也可以用任何语言(Java, Python, Go, C# 等),只要它们能提供 HTTP API。
  • 标准化:基于 HTTP 和 JSON,是业界公认的标准。

Java 后端提供 WebSocket 服务

如果你的应用需要实时、双向的通信(聊天应用、实时股票行情、在线协作工具),HTTP REST API 就不太合适了,这时可以使用 WebSocket

工作原理

  1. JavaScript 客户端和 Java 服务器建立一个持久的 WebSocket 连接。
  2. 连接建立后,任何一方都可以主动向另一方发送消息,而无需等待对方的请求。
  3. 服务器可以主动向客户端推送数据,客户端也可以随时向服务器发送数据。

Java 后端 (Spring WebSocket 示例)

// 启用 WebSocket 支持
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MyWebSocketHandler(), "/ws") // 注册处理器和路径
                .setAllowedOrigins("*"); // 允许所有来源(生产环境需配置具体域名)
    }
}
// 处理 WebSocket 消息的处理器
public class MyWebSocketHandler extends TextWebSocketHandler {
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("WebSocket connection established!");
        // 连接建立后,服务器可以主动发送消息
        session.sendMessage(new TextMessage("Welcome to the Java WebSocket server!"));
    }
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        System.out.println("Received message: " + payload);
        // 执行 Java 逻辑
        String response = "Server received your message: " + payload;
        // 将处理结果返回给客户端
        session.sendMessage(new TextMessage(response));
    }
}

JavaScript 前端 (WebSocket API 示例)

const socket = new WebSocket('ws://your-java-server/ws');
// 连接打开时
socket.onopen = function(event) {
    console.log('WebSocket connection opened!');
    // 发送一条消息到服务器
    socket.send('Hello from JavaScript client!');
};
// 接收到服务器消息时
socket.onmessage = function(event) {
    const message = event.data;
    console.log('Message from server: ' + message);
    // 在页面上显示消息
    document.getElementById('result').innerHTML += `<p>${message}</p>`;
};
// 连接关闭时
socket.onclose = function(event) {
    console.log('WebSocket connection closed.');
};
// 发生错误时
socket.onerror = function(error) {
    console.error('WebSocket error: ' + error);
};

优点

  • 实时性:真正的双向通信,延迟极低。
  • 高效:避免了 HTTP 的握手和头部开销,适合频繁的小数据量通信。

在 Node.js 中直接调用 Java 代码 (较少见)

在某些特定场景下,你可能希望在一个 Node.js 应用中直接调用本地的 Java 类文件(.jar.class),这可以通过子进程或专门的桥接库实现。

使用 child_process 模块

这是最直接的方式,Node.js 可以启动一个新的进程来执行 Java 命令。

const { exec } = require('child_process');
// 假设你有一个 Java 程序,可以接收命令行参数并输出结果
//  java -jar myapp.jar "input data"
exec('java -jar my-java-app.jar "some data from node.js"', (error, stdout, stderr) => {
    if (error) {
        console.error(`exec error: ${error}`);
        return;
    }
    if (stderr) {
        console.error(`stderr: ${stderr}`);
        return;
    }
    // stdout Java 程序打印到控制台的结果
    console.log(`Java app output: ${stdout}`);
});

缺点

  • 性能差:每次调用都需要启动一个新的 JVM(Java 虚拟机),开销巨大。
  • 通信复杂:数据交换依赖于标准输入/输出,不适合复杂的数据结构。
  • 平台依赖:需要目标机器上安装 Java 环境。

使用桥接库 (如 java-node)

有一些第三方库试图在 Node.js 和 JVM 之间建立一个更直接的桥接,但它们通常不够成熟,社区支持有限,且可能引入新的复杂性。

除非有非常特殊的需求(复用某个没有提供 API 的 Java 库),否则应尽量避免这种方式,更好的选择是启动一个微服务 Java 应用,然后通过 HTTP API 调用它。


总结与对比

方案 场景 优点 缺点 推荐度
Java Applet 浏览器端执行 Java 早期方案,集成度高 已被淘汰,安全、兼容性差 ⭐ (不推荐)
GWT 用 Java 编写前端代码 用 Java 开发前端 限制大,非通用方案,生态萎缩 ⭐⭐ (特定场景)
Spring Boot + HTTP API 前后端分离 解耦、灵活、标准化、生态强大 需要网络通信,非实时 ⭐⭐⭐⭐⭐ (强烈推荐)
WebSocket 实时双向通信 低延迟,真正的双向通信 协议复杂,需要服务器支持 ⭐⭐⭐⭐ (实时场景首选)
Node.js 子进程调用 Node.js 直接调用本地 Java 无需网络,直接复用 性能差,通信复杂,平台依赖 ⭐ (仅限特殊需求)

最终建议

对于 99% 的现代 Web 应用开发场景,首选方案是“方案一:Java Spring Boot + JavaScript (Fetch/Axios)”

  1. 使用 Spring Boot (或类似的 Java Web 框架如 Micronaut, Quarkus) 构建你的后端服务。
  2. 设计 RESTful API 来暴露你的 Java 业务逻辑。
  3. 在前端 (无论是浏览器还是 Node.js) 使用 fetchaxios 等库来调用这些 API。
  4. 如果你的应用需要实时功能,再考虑引入 WebSocket

这种架构是行业标准,因为它带来了最大的灵活性、可维护性和可扩展性。

分享:
扫描分享到社交APP
上一篇
下一篇