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

甲、环境Tauri跨端程序
前端
- 
✅\] 得升级`@tauri-apps/cli`到`>=2.0.0-beta.0`
 
rust
- 
✅\] 得升级`tauri-build`到`2.0.0-beta.10`
 
乙、下载最新的Geoserver二进制文件
一定🏳️
一定🏳️
一定🏳️
下载二进制文件
Platform Independent Binary
Geoserver Platform Independent Binary
丙、 下载最低17版本的java
一定🏳️
一定🏳️
一定🏳️
下载免安装解压即用的
丁、 设置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
    },