将Geoserver服务打包到Tauri程序中使用

GeoServer在Tauri中无感启动与使用

吃力不讨好的事情 PC端加载至少1G的tif文件到地图中展示
离谱
切片都不帮个忙
这不难为老实人么


甲、环境Tauri跨端程序

前端

  • [✅] 得升级@tauri-apps/cli>=2.0.0-beta.0
  • [✅] - @tauri-apps/api >=2.0.0-beta.0

rust

  • [✅] 得升级tauri-build2.0.0-beta.10
  • [✅] - tauri 2.0.0-beta.13

乙、下载最新的Geoserver二进制文件

一定🏳️

一定🏳️

一定🏳️

下载二进制文件Platform Independent Binary

Geoserver Platform Independent Binary


丙、 下载最低17版本的java

一定🏳️

一定🏳️

一定🏳️

下载免安装解压即用的

java_17 zip


丁、 设置Tauri 打包文件

tauri.conf.json

json 复制代码
 "resources": [
      "./resources/geoserver-main-latest-bin"
 ]

文件geoserver-main-latest-bin中需要包含下载解压的java_17 最终项目结构是

-src-tauri/resources/geoserver-main-latest-bin

--bin

--data_dir

--etc

--jdk_17

--lib

--license

--licenses

--log

--modules

--resources

--webapps

--start.ini

--start.jar

--VERSION.txt


戍、rust执行终端命令唤起geoserver

1) 使用std::env::current_dir判断文件是否存在
rust 复制代码
    let binding = env::current_dir().unwrap().join("resources/geoserver-main-latest-bin");
    let flag = is_path_exists(binding.to_str().unwrap());
2) 使用std::process::Command执行终端命令
rust 复制代码
    //CREATE_NO_WINDOW 叮嘱此变量是设置终端命令执行时不创建终端窗口(仅限window)
    let binding = env::current_dir().unwrap().join("resources/geoserver-main-latest-bin");
    let java_path = binding.join(r"jdk_17/bin/java.exe");
    let jar_path = binding.join(r".\start.jar");
    const CREATE_NO_WINDOW: u32 = 0x08000000;
    let  command  = Command::new(java_path)
        .arg("-jar")
        .arg(jar_path)
        .current_dir(binding)
        .creation_flags(CREATE_NO_WINDOW)
        .spawn();
3) 使用std::net::UdpSocket::bind获取当前设备IP
rust 复制代码
fn get_local_ip() -> Option<IpAddr> {
    let socket = match std::net::UdpSocket::bind("0.0.0.0:0") {
        Ok(socket) => socket,
        Err(_) => return None,
    };

    match socket.connect("8.8.8.8:80") {
        Ok(()) => (),
        Err(_) => return None,
    }

    socket.local_addr().ok().map(|addr| addr.ip())
}

fn is_port_available(ip: IpAddr, port: u16) -> bool {
    let addr = SocketAddr::new(ip, port);
    TcpStream::connect(addr).is_ok()
}

#[tauri::command]
pub async fn get_localhost_ip() -> Result<CustomResult> {
    if let Some(ip) = get_local_ip() {
        println!("Local IP address: {}", ip);

        let port = 28080;
        if is_port_available(ip, port) {
            return Ok(CustomResult::new(true, 200, "Success", Some(json!({
                "ip": ip,
                "port": port
            }))));
        } else {
            return Err(CustomResult::new(false, 500, &format!("Port {} is not available", port), None));
        }
    } else {
        return Err(CustomResult::new(false, 500, "Failed to get local IP address", None));
    }
}

CustomResult是我自定义的内容返回格式,请自行处理


己、唤起服务

不在项目启动时唤起,单独开启子进程会阻塞主进程

在前端初始化时在进行IPC通信唤起

设置打开Geoserver时单独唤起一个webview

ts 复制代码
import { invokeGeoServerExist, invokeGeoServerStart, invokeGetLocalhostIp } from "@/ipc-apps/invoke.geoserver";
import { ResultMeta } from "@/types/result";
import { useEffect, useState } from "react";
import { WebviewWindow  } from '@tauri-apps/api/webviewWindow';

export const useGeoServerClient = () => {
    const [isExist, setExist] = useState<boolean>(false);

    const [isStart, setStart] = useState<boolean>(false);

    const [ipAddress, setIpAddress] = useState<{
        address: string,
        msg: string
    }>({
        address: '',
        msg: 'GeoServer服务未启动'
    })

    const queryGeoServer = async () => {
        invokeGeoServerExist().then((res: ResultMeta) => {
            console.log('是否存在 = ',res.success);
            if(res.success){
                setExist(true);
                invokeGeoServerStart().then((res: ResultMeta) => {
                    console.info('geoserver启动成功');
                    // res.success && setStart(true);
                })
            }
        })
    }
    const geoserverUrl = (_isStart: boolean, uri: string) => {
        if(!_isStart)return;
        const webview = new WebviewWindow("geoserver-window", {
            url: `${uri}/geoserver/index.html`,
            x: 0,
            y: 0,
            width: 1440,
            height: 1080,
            title: "GeoServer自启服务",
          });
        webview.once('tauri://created', function () {
        // webview 窗口成功创建
        console.log('成功');
        
        });

        webview.once('tauri://error', function (e) {
        // 创建窗口时出现错误
        console.log('错误, ', e);
        
        });
    }

    useEffect(() => {
        console.log("是否启动 = ", isExist);
        
        if(isExist){
            const _timer = setInterval(() => {
                invokeGetLocalhostIp().then(res => {
                    console.log('res =', res);
                    
                    if(res.success){
                        setStart(true)
                        const { 
                            ip, port
                        } = res.payload;
                        setIpAddress({
                            address: `http://${ip}:${port}`,
                            msg: 'GeoServer服务已启动'
                        })
                        clearInterval(_timer)
                    }else{
                        setIpAddress({
                            address: "",
                            msg: res.msg
                        })
                    }
                })
            }, 1000)
        }
    }, [isExist])



    return {
        isStart,
        ipAddress,
        isExist,
        queryGeoServer,
        geoserverUrl
    }
}

庚、得设置允许http使用

tauri.conf.json

json 复制代码
"security": {
      "csp": null
    },
相关推荐
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
林太白8 小时前
❤React-React 组件通讯
前端·javascript·react.js
豆华8 小时前
React 中 为什么多个 JSX 标签需要被一个父元素包裹?
前端·react.js·前端框架
前端熊猫9 小时前
React第一个项目
前端·javascript·react.js
练习两年半的工程师9 小时前
使用React和Vite构建一个AirBnb Experiences克隆网站
前端·react.js·前端框架
林太白9 小时前
❤React-JSX语法认识和使用
前端·react.js·前端框架
女生也可以敲代码9 小时前
react中如何在一张图片上加一个灰色蒙层,并添加事件?
前端·react.js·前端框架
布兰妮甜9 小时前
前端框架大比拼:React.js, Vue.js 及 Angular 的优势与适用场景探讨
前端·vue.js·react.js·前端框架·angular.js
老码沉思录10 小时前
React Native 全栈开发实战班 - 核心组件与导航
javascript·react native·react.js