org.springframework.boot
spring-boot-devtools
diff --git a/src/main/java/top/zzmark/echo/EchoApplication.java b/src/main/java/top/zzmark/echo/EchoApplication.java
index 3b32ec2..4e63cc8 100644
--- a/src/main/java/top/zzmark/echo/EchoApplication.java
+++ b/src/main/java/top/zzmark/echo/EchoApplication.java
@@ -1,11 +1,28 @@
package top.zzmark.echo;
+import org.apache.catalina.filters.RemoteIpFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class EchoApplication {
+ /**
+ * 识别反向代理的 X-Forwarded-* 标记,获取客户端的实际 ip
+ * 需要上层转发层的支持。
+ *
+ * 该 filter 不遵循 RFC 7239, spring-mvc 提供了一个名为 ForwardedFilter 的拦截器,但并不知道该怎么用
+ *
+ * webflux 有更好的解决方案,不需要这个
+ */
+ @Bean
+ @ConditionalOnClass(RemoteIpFilter.class)
+ public RemoteIpFilter remoteIpFilter() {
+ return new RemoteIpFilter();
+ }
+
public static void main(String[] args) {
SpringApplication.run(EchoApplication.class, args);
}
diff --git a/src/main/java/top/zzmark/echo/controller/Controller.java b/src/main/java/top/zzmark/echo/controller/Controller.java
index f11eaa0..59e2d3a 100644
--- a/src/main/java/top/zzmark/echo/controller/Controller.java
+++ b/src/main/java/top/zzmark/echo/controller/Controller.java
@@ -1,5 +1,8 @@
package top.zzmark.echo.controller;
+import cn.hutool.system.SystemUtil;
+import cn.hutool.system.oshi.CpuInfo;
+import cn.hutool.system.oshi.OshiUtil;
import org.springframework.web.bind.annotation.*;
import top.zzmark.echo.entity.EchoEntity;
import top.zzmark.echo.util.CommandUtil;
@@ -9,6 +12,7 @@
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.HashMap;
import java.util.Map;
/**
@@ -21,25 +25,50 @@
public class Controller {
@RequestMapping("echo")
- public EchoEntity echo(HttpServletRequest request, @RequestHeader(required = false) Map header,
- @RequestParam(required = false) Map param, @RequestBody(required = false) Map body)
+ public EchoEntity echo(HttpServletRequest request,
+ @RequestHeader(required = false) Map header,
+ @RequestParam(required = false) Map param,
+ @RequestBody(required = false) Map body)
throws IOException {
+
return EchoEntity.builder()
.clientIp(IpUtil.getIpAddr(request))
.serverIp(InetAddress.getLocalHost().getHostAddress())
- .serverInfo(CommandUtil.run("cat /etc/os-release", 0))
.requestHeader(header)
.requestBody(body)
.requestParam(param)
.build();
}
+ @GetMapping("env")
+ public Map env() throws IOException {
+ return System.getenv();
+ }
+
+ @GetMapping("systemInfo")
+ public Map systemInfo() throws IOException {
+ Map map = new HashMap<>();
+ map.put("JvmSpecInfo", SystemUtil.getJvmSpecInfo());
+ map.put("JvmInfo", SystemUtil.getJvmInfo());
+ map.put("JavaSpecInfo", SystemUtil.getJvmSpecInfo());
+ map.put("JavaInfo", SystemUtil.getJavaInfo());
+ map.put("JavaRuntimeInfo", SystemUtil.getJavaRuntimeInfo());
+ map.put("OsInfo", SystemUtil.getOsInfo());
+ map.put("UserInfo", SystemUtil.getUserInfo());
+ map.put("HostInfo", SystemUtil.getHostInfo());
+ map.put("RuntimeInfo", SystemUtil.getRuntimeInfo().toString());
+ CpuInfo cpuInfo = OshiUtil.getCpuInfo();
+ map.put("cpuInfo", cpuInfo);
+ return map;
+ }
+
@GetMapping("ping")
public String ping(@RequestParam("ip") String ip, @RequestParam(value = "s", required = false) Integer s)
throws IOException {
return CommandUtil.run("ping " + ip);
}
+ @Deprecated
@GetMapping("shell")
public String shell(@RequestParam("shell") String shell, @RequestParam(value = "s", required = false) Integer s)
throws IOException {
diff --git a/src/main/java/top/zzmark/echo/controller/ExecController.java b/src/main/java/top/zzmark/echo/controller/ExecController.java
new file mode 100644
index 0000000..86dc8ab
--- /dev/null
+++ b/src/main/java/top/zzmark/echo/controller/ExecController.java
@@ -0,0 +1,120 @@
+package top.zzmark.echo.controller;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.*;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static cn.hutool.core.io.FileUtil.isWindows;
+
+/**
+ * @author mark_zhou[zz.mark06@gmail.com]
+ * @date 2021-08-19 11:56
+ **/
+@RestController
+public class ExecController {
+
+ private static final Logger logger = LoggerFactory.getLogger(ExecController.class);
+
+ @GetMapping("exec")
+ public String shell(
+ @RequestParam("shell") String shell,
+ @RequestParam(value = "s", required = false) Long s
+ ) throws IOException {
+ String preCmd = "";
+ String encoding;
+ if (isWindows()) {
+ // 对 windows 需要点特别处理
+ encoding = "gb2312";
+ preCmd = "cmd /C ";
+ } else {
+ // linux 是否需要,得测试一下
+ encoding = "utf-8";
+ }
+ String[] exec = (preCmd + shell).split(" ");
+ return execToString(exec, encoding, s, TimeUnit.SECONDS);
+ }
+
+ public static boolean exec(String[] cmdArray, String[] envp, File dir,
+ OutputStream stdout, OutputStream stderr, long timeout, TimeUnit timeUnit) throws IOException {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("execute : ");
+ for (String s : cmdArray) {
+ sb.append(s).append(" ");
+ }
+ sb.append("\n in ").append(dir.getAbsolutePath());
+ logger.info(sb.toString());
+ Process p = Runtime.getRuntime().exec(cmdArray, envp, dir);
+
+ Thread _stdout = new Thread(new StreamReader(p.getInputStream(), stdout));
+ Thread _stderr = new Thread(new StreamReader(p.getErrorStream(), stderr));
+ _stdout.setDaemon(true);
+ _stderr.setDaemon(true);
+
+ _stdout.start();
+ _stderr.start();
+
+ boolean ret = false;
+ try {
+ ret = p.waitFor(timeout, timeUnit);
+ _stdout.join(timeUnit.toMillis(timeout));
+ _stderr.join(timeUnit.toMillis(timeout));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+
+ public static String execToString(String[] cmdArray, String encoding, long timeout, TimeUnit timeUnit) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try {
+ boolean ret = exec(cmdArray, getEnvs(), new File(".").getAbsoluteFile(), out, out, timeout, timeUnit);
+ out.close();
+ if (ret) {
+ return out.toString(encoding);
+ }
+ return out.toString(encoding);
+ } catch (Exception e) {
+ logger.error("执行失败", e);
+ return e.getMessage();
+ }
+ }
+
+ public static String[] getEnvs() {
+ String[] envs = new String[System.getenv().size()];
+ int c = 0;
+ for (Map.Entry entry : System.getenv().entrySet()) {
+ envs[c++] = entry.getKey() + "=" + entry.getValue();
+ }
+ return envs;
+ }
+
+ public static class StreamReader implements Runnable {
+ InputStream input;
+ OutputStream output;
+
+ private StreamReader(InputStream input, OutputStream output) {
+ this.input = input;
+ this.output = output;
+ }
+
+ @Override
+ public void run() {
+ try {
+ int c;
+ byte[] buff = new byte[1024];
+ while ((c = input.read(buff)) > 0) {
+ output.write(buff, 0, c);
+ }
+ } catch (IOException e) {
+ logger.error("", e);
+ }
+ }
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
deleted file mode 100644
index 08c8822..0000000
--- a/src/main/resources/application.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-spring.application.name=echo
-server.port=60001
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..e9c5a8b
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,33 @@
+spring.application.name: echo
+
+server:
+ port: 60001
+
+management:
+ server:
+ port: 60002 # ActuatorWeb访问端口
+ endpoint:
+ health:
+ show-details: always
+ probes:
+ enabled: true
+ prometheus:
+ enabled: true
+ endpoints:
+ jmx:
+ exposure:
+ include: '*'
+ web:
+ exposure:
+ include: '*'
+ metrics:
+ tags:
+ application: ${spring.application.name}
+ info:
+ git: # https://github.com/git-commit-id/git-commit-id-maven-plugin 显示 git 提交信息
+ mode: full
+logging:
+ pattern:
+ dateformat: 'yyyy-MM-dd HH:mm:ss.SSS,Asia/Shanghai'
+ file:
+ name: ./logs/${spring.application.name}.log
diff --git a/src/main/resources/public/index.html b/src/main/resources/public/index.html
new file mode 100644
index 0000000..35c7bab
--- /dev/null
+++ b/src/main/resources/public/index.html
@@ -0,0 +1,137 @@
+
+
+
+
+
+ Echo
+
+
+
+
+
+
+
+
+
+ {{ item.val }}
+
+
+
+
+
+ {{ item.val
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 执行
+
+
+
+ {{ cmdRes }}
+
+
+
+
+
+
+
+
+
+
+
+