xyc
15 小时以前 8ad75d5872872b79abada58589adad0df4614db6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package com.trafficaudit.system.controller;
 
import com.trafficaudit.common.Result;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
 
/**
 * Exposes the product version so the UI (and operators) can confirm which build
 * is actually running on a server. Kept public on purpose: the login page shows
 * the version before any token exists.
 */
@RestController
@RequestMapping("/api")
public class VersionController {
 
    private static final String VERSION_FILE = "app-version.properties";
 
    @GetMapping("/version")
    public Result<Map<String, Object>> version() {
        Map<String, Object> info = new LinkedHashMap<>();
        info.put("version", readVersion());
        info.put("buildTime", resolveBuildTime());
        return Result.ok(info);
    }
 
    private String readVersion() {
        try (InputStream in = new ClassPathResource(VERSION_FILE).getInputStream()) {
            Properties props = new Properties();
            props.load(in);
            String value = props.getProperty("version");
            return value == null || value.trim().isEmpty() ? "unknown" : value.trim();
        } catch (Exception e) {
            return "unknown";
        }
    }
 
    /**
     * Build time of the running artifact. In a packaged run this is the jar file's
     * last-modified time; when running from exploded classes (mvn spring-boot:run)
     * there is no jar, so the value is null.
     */
    private String resolveBuildTime() {
        try {
            URI location = VersionController.class.getProtectionDomain()
                    .getCodeSource().getLocation().toURI();
            Path path = resolveArtifactPath(location);
            if (path != null && Files.isRegularFile(path)) {
                return Files.getLastModifiedTime(path).toInstant().toString();
            }
        } catch (Exception ignored) {
            // Fall through: build time is optional information.
        }
        return null;
    }
 
    /**
     * Spring Boot executable jars expose a nested classpath such as
     * "jar:file:/app.jar!/BOOT-INF/classes!/". Strip the nested part before
     * asking the filesystem for the jar timestamp.
     */
    private Path resolveArtifactPath(URI location) {
        String value = location.toString();
        int nested = value.indexOf("!/");
        if (nested >= 0) {
            value = value.substring(0, nested);
        }
        if (value.startsWith("jar:")) {
            value = value.substring(4);
        }
        return Paths.get(URI.create(value));
    }
}