找回密码
立即注册
搜索
发回帖 发新帖

5257

积分

0

好友

671

主题
发表于 3 小时前 | 查看: 9| 回复: 0

前几天有人问我,Java 做桌面应用是不是已经过时了。这个问题我不太想直接回答,因为很多人一提到 Java 桌面开发,脑子里就自动跳出十几年前的 Swing 界面。

最近我在做一些内部工具时,反而试出一个挺有意思的组合:Java 管业务逻辑,Shadcn UI 管界面体验。

以前 Java 桌面程序最大的问题不是功能不够,而是界面太像工具软件。按钮、表格、弹窗,一眼看去就是企业内部系统的味道。现在前端生态已经成熟,没必要再用 Java 硬造一套 UI。

Shadcn UI 本身不是一个完整组件库,它更像是一套基于 React 和 Tailwind CSS 的可复制组件方案。所以我这里的思路不是让 Java 去渲染 Shadcn,而是让 Java 做后端能力,通过 WebView 嵌入现代 UI。

这个架构我更喜欢:

Java 程序 → Spring Boot / 本地服务 → 提供 REST API → React + Shadcn UI → WebView 显示桌面界面

这样做最大的好处是,Java 负责它擅长的数据库、文件处理、线程任务,UI 层交给前端。

很多人一听“桌面应用”,第一反应就是 Swing。比如以前写个文件导入工具,大概是这种:

public class ImportWindow extends JFrame {
    private JButton button;

    public ImportWindow() {
        button = new JButton("开始导入");
        button.addActionListener(e -> {
            importData();
        });
        add(button);
        setSize(400, 200);
    }

    private void importData() {
        System.out.println("开始处理文件");
    }
}

功能没问题。但需求一变,比如按钮换个样式、增加进度条、表格支持筛选,Swing 代码很快开始膨胀。

所以现在我更倾向把 UI 独立出来,Java 这边只提供能力。比如一个本地文件处理工具,Java 可以只暴露一个接口:

@RestController
@RequestMapping("/task")
public class TaskController {

    private final TaskService taskService;

    public TaskController(TaskService taskService) {
        this.taskService = taskService;
    }

    @PostMapping("/start")
    public Map<String, Object> start(@RequestParam String file) {
        String taskId = taskService.createTask(file);
        return Map.of(
            "taskId", taskId,
            "status", "running"
        );
    }
}

前端点击按钮以后,只需要调用这个接口。Shadcn UI 的优势就在这里体现出来了。比如一个简单按钮:

<Button onClick={startTask}>
    开始处理
</Button>

然后配合 Card、Table、Dialog 这些组件,很快可以拼出一个接近现在 Web 产品体验的桌面工具。

我自己做这类工具时有个习惯:Java 层尽量不要知道页面长什么样。不要出现这种代码:

if(buttonName.equals("导出")) {
    exportExcel();
}

这种写法短期很爽,后面改需求特别痛苦。Java 应该只关心业务状态。例如:

@Service
public class ExportService {
    public ExportResult export(Long jobId) {
        Job job = jobRepository.findById(jobId)
                .orElseThrow();
        if(job.isFinished()){
            return ExportResult.done();
        }
        generateFile(job);
        return ExportResult.success();
    }
}

页面怎么展示,是 React 的事。

另一个比较容易踩坑的地方是桌面应用的数据通信。很多人直接让前端调用 Java 方法,这个耦合会越来越重。我一般会加一层事件状态。比如任务执行:

@Component
public class TaskRunner {
    private final ConcurrentHashMap<String, String> status =
            new ConcurrentHashMap<>();

    public void run(String id) {
        status.put(id, "processing");
        try {
            Thread.sleep(2000);
            status.put(id, "success");
        } catch (Exception e) {
            status.put(id, "failed");
        }
    }

    public String getStatus(String id) {
        return status.get(id);
    }
}

前端轮询:

const timer = setInterval(async () => {
    const res = await fetch("/task/status?id=" + taskId);
    const data = await res.json();
    setStatus(data.status);
}, 1000);

这种模式虽然简单,但对内部工具非常实用。比如:

  • Excel 批量处理工具
  • 日志分析工具
  • 数据同步工具
  • 自动化运维客户端

这些场景不需要上云,也不需要复杂部署。一个 jar 包,加一个前端资源,就能运行。

当然,Shadcn UI 不是万能的。它解决的是界面问题,不解决桌面应用打包问题。Java 桌面应用最后还是需要考虑:

  • 怎么启动?
  • 怎么升级?
  • 怎么访问本地文件?
  • 怎么调用系统能力?

比如读取用户目录:

public Path getWorkspace() {
    String home = System.getProperty("user.home");
    return Paths.get(home, "my-tool", "workspace");
}

或者监听本地文件变化:

WatchService watcher = FileSystems.getDefault().newWatchService();
Path path = Paths.get("./data");
path.register(
    watcher,
    StandardWatchEventKinds.ENTRY_CREATE,
    StandardWatchEventKinds.ENTRY_MODIFY
);

这些才是桌面程序真正麻烦的地方。UI 漂亮只是第一步。

我现在看 Java 桌面应用,已经不是以前那个思路了。不是 Swing 和 JavaFX 二选一,而是重新拆分职责。Java 管稳定的东西:数据库连接、文件处理、线程任务、系统调用,这些 Java 很成熟。UI 交给 Shadcn UI,前端生态发展这么多年,没必要重复造轮子。

对于企业内部工具、小型客户端、开发辅助工具,这套组合其实挺舒服。代码还是 Java,部署还是一个客户端,但界面已经不是十年前那个味道了。




上一篇:TeamViewer修复CVE-2026-111585高危漏洞:被控端可反向控制主控端
下一篇:从 Claude Code 到 Grok Bot:我搭了一套 24 小时 AI 编程 Agent
您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-11-4 03:48 , Processed in 0.075868 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表