Skip to content

Commit

Permalink
桌面运行逻辑
Browse files Browse the repository at this point in the history
  • Loading branch information
jiashuaizhang committed Dec 16, 2021
1 parent 92bec16 commit c7a0a3e
Show file tree
Hide file tree
Showing 17 changed files with 400 additions and 4 deletions.
2 changes: 1 addition & 1 deletion yyets-history/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</parent>
<groupId>com.zhangjiashuai</groupId>
<artifactId>yyets-history</artifactId>
<version>2.0</version>
<version>2.1</version>
<name>yyets-history</name>
<description>a yyets history snapshot</description>
<properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.zhangjiashuai.yyetshistory;

import com.zhangjiashuai.yyetshistory.util.NativeOperationUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class YyetsHistoryApplication {

public static void main(String[] args) {
SpringApplication.run(YyetsHistoryApplication.class, args);
if(NativeOperationUtils.onStartPrepare(args)) {
SpringApplication.run(YyetsHistoryApplication.class, args);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.extra.compress.extractor.SevenZExtractor;
import cn.hutool.extra.spring.EnableSpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
Expand All @@ -17,8 +18,10 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.StandardCopyOption;


@Slf4j
@Configuration
@EnableSpringUtil
public class AppConfig {

@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.zhangjiashuai.yyetshistory.config;

import com.zhangjiashuai.yyetshistory.util.NativeOperationUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppRunner implements ApplicationRunner {

@Override
public void run(ApplicationArguments args) {
NativeOperationUtils.onStartFinish();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class YyetsHistoryProperties {

public static final int DEFAULT_PAGE_SIZE = 10;
public static final int MAX_PAGE_SIZE = 100;
public static final String APPLICATION_INFO = "yyets-history";

/**
* 保留的链接类型
Expand All @@ -18,6 +19,10 @@ public class YyetsHistoryProperties {
* 默认每页大小
*/
private int defaultPageSize;
/**
* 域名
*/
private String host;

public int getDefaultPageSize() {
return defaultPageSize < 1 ? DEFAULT_PAGE_SIZE : defaultPageSize;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import static com.zhangjiashuai.yyetshistory.config.YyetsHistoryProperties.APPLICATION_INFO;

@Controller
public class IndexController {
Expand All @@ -10,4 +13,10 @@ public class IndexController {
public String index() {
return "index";
}

@GetMapping("/info")
@ResponseBody
public String info() {
return APPLICATION_INFO;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package com.zhangjiashuai.yyetshistory.util;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.swing.DesktopUtil;
import cn.hutool.core.swing.clipboard.ClipboardUtil;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;

import javax.swing.*;
import java.net.URL;

import static com.zhangjiashuai.yyetshistory.config.YyetsHistoryProperties.APPLICATION_INFO;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.INFORMATION_MESSAGE;

/**
* 本地指令操作工具
*/
@Slf4j
public class NativeOperationUtils {

static {
System.setProperty("java.awt.headless", "false");
NativeYamlUtil.loadYamlConfig();
}

/**
* 项目范文路径
*/
private static volatile String uri;

private NativeOperationUtils() {}

private static String buildUri(String host, int port) {
uri = String.format("http://%s:%d/", host, port);
log.info("项目访问路径初始化完成: {}", uri);
return uri;
}

/**
* 准备启动时触发事件
* @param args 命令行参数
* @return true 执行启动
*/
public static boolean onStartPrepare(String[] args) {
NativeYamlUtil.loadCommandLineArgs(args);
String host = getHost();
int port = getPort();
String uri = buildUri(host, port);
log.info("检查项目是否已经启动");
if(telnet(host, port)) {
log.info("探测到项目访问路径上有服务运行");
if (startAlready()) {
log.info("服务已在另一进程运行");
onStartFinish();
} else {
openErrorDialog ("端口冲突","当前地址: " + uri + " 已被占用");
}
System.exit(0);
}
return true;
}

/**
* 启动成功触发事件
* @param uri 项目访问地址
*/
public static void onStartFinish() {
log.info("程序启动完成,访问地址: {}", uri);
try {
webBrowse(uri);
} catch (Exception e1) {
log.debug("打开桌面浏览器失败", e1);
try {
copy2Clipboard(uri);
} catch (Exception e2) {
log.debug("复制链接至剪贴板失败", e2);
}
try {
openSuccessDialog(uri);
} catch (Exception e3) {
log.debug("弹出对话框失败", e3);
}
}
}

private static boolean startAlready() {
String url = uri + "info";
try {
HttpResponse response = HttpUtil.createGet(url).timeout(100).execute();
return response.getStatus() == HttpStatus.HTTP_OK && APPLICATION_INFO.equals(response.body());
} catch (HttpException e) {
return false;
}
}
/**
* 浏览器访问
* @param url
*/
public static void webBrowse(String url) {
DesktopUtil.browse(url);
}

/**
* 复制到剪贴板
* @param str
*/
public static void copy2Clipboard(String str) {
ClipboardUtil.setStr(str);
}

public static String openSuccessDialog(String url) {
URL icon = NativeOperationUtils.class.getResource("/static/icon_msg.png");
return openInputDialog("启动完成", "打开浏览器访问以下地址:", url, new ImageIcon(icon));
}
/**
* 弹出对话框
* @param title 标题
* @param label 文本框名称
* @param text 文本内容
* @param icon 图标
* @return
*/
public static String openInputDialog(String title, String label, String text, Icon icon) {
return (String) JOptionPane.showInputDialog(null, label,
title, INFORMATION_MESSAGE, icon, null, text);
}

/**
* 弹出错误提示框
* @param title 标题
* @param text 内容
*/
public static void openErrorDialog(String title, String text) {
JOptionPane.showMessageDialog(null, text, title, ERROR_MESSAGE);
}

/**
* 检查端口是否开启
* @param host
* @param port
* @return
*/
public static boolean telnet(String host, int port) {
return NetUtil.isOpen(NetUtil.buildInetSocketAddress(host, port), 100);
}


private static String getHost() {
return NativeYamlUtil.getPropertyOrDefault("yyets-history.host", "localhost").toString();
}

private static int getPort() {
Object value = NativeYamlUtil.getProperty("server.port");
final int defaultPort = 8080;
if(value == null) {
return defaultPort;
}
if(value instanceof Number) {
return ((Number) value).intValue();
}
try {
return Integer.parseInt(value.toString());
} catch (NumberFormatException e) {
return defaultPort;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.zhangjiashuai.yyetshistory.util;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.setting.yaml.YamlUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

import static cn.hutool.core.text.StrPool.COMMA;
import static cn.hutool.core.text.StrPool.DOT;

@Slf4j
class NativeYamlUtil {

private static final Map<String, Object> PROPERTIES = new HashMap<>();

static Object getProperty(String key) {
if(SpringUtil.getApplicationContext() != null) {
return SpringUtil.getProperty(key);
}
return PROPERTIES.get(key);
}

static Object getPropertyOrDefault(String key, Object defaultValue) {
Object v;
return (((v = getProperty(key)) != null) || PROPERTIES.containsKey(key))
? v : defaultValue;
}

static void loadYamlConfig() {
PROPERTIES.clear();
loadConfigYaml(null);
Object configValue = PROPERTIES.get("spring.profiles.active");
if(configValue == null) {
return;
}
Collection<String> activeProfiles;
if (configValue instanceof Collection) {
activeProfiles = (Collection<String>) configValue;
} else {
activeProfiles = Arrays.stream(configValue.toString().split(COMMA)).collect(Collectors.toList());
}
for (String profile : activeProfiles) {
if(StrUtil.isBlank(profile)) {
continue;
}
try {
loadConfigYaml(profile);
} catch (Exception e) {
log.debug("yaml加载异常, profile: {}", profile, e);
}
}
// 尝试获取环境变量与jvm参数
loadSystemProperties();
}

static void loadCommandLineArgs(String[] args) {
if(ArrayUtil.isEmpty(args)) {
return;
}
String prefix = "--";
String separator = "=";
for (String arg : args) {
if(StrUtil.isBlank(arg) || !arg.startsWith(prefix)) {
continue;
}
String subs = arg.substring(prefix.length());
String[] array = subs.split(separator);
if(array.length != 2 || StrUtil.isBlank(array[0])) {
continue;
}
PROPERTIES.put(array[0], array[1]);
}
}
private static void loadSystemProperties() {
for (Map.Entry<String, Object> entry : PROPERTIES.entrySet()) {
String key = entry.getKey();
String newValue;
if(StrUtil.isBlank(newValue = System.getenv(key))) {
newValue = System.getProperty(key);
}
if(StrUtil.isNotBlank(newValue)) {
entry.setValue(newValue);
}
}
}

private static void loadConfigYaml(String profile) {
String filename;
if(StrUtil.isBlank(profile)) {
filename = "application.yml";
} else {
filename = String.format("application-%s.yml", profile.trim());
}
Dict dict = YamlUtil.loadByPath(filename);
readYaml(PROPERTIES, null, dict);
}

private static void readYaml(Map<String, Object> properties, String key, Object value) {
if(value instanceof LinkedHashMap) {
LinkedHashMap<String, Object> map = (LinkedHashMap<String, Object>) value;
for (Map.Entry<String, Object> entry : map.entrySet()) {
String childKey = entry.getKey();
Object childValue = entry.getValue();
String keyPart = Optional.ofNullable(key).map(s -> (s + DOT + childKey)).orElse(childKey);
readYaml(properties, keyPart, childValue);
}
} else {
properties.put(key, value);
}
}
}
Loading

0 comments on commit c7a0a3e

Please sign in to comment.