-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
92bec16
commit c7a0a3e
Showing
17 changed files
with
400 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 4 additions & 1 deletion
5
yyets-history/src/main/java/com/zhangjiashuai/yyetshistory/YyetsHistoryApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
yyets-history/src/main/java/com/zhangjiashuai/yyetshistory/config/AppRunner.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
yyets-history/src/main/java/com/zhangjiashuai/yyetshistory/util/NativeOperationUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
} |
116 changes: 116 additions & 0 deletions
116
yyets-history/src/main/java/com/zhangjiashuai/yyetshistory/util/NativeYamlUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} |
Oops, something went wrong.