OssSettings.java 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package com.fujica.parkingtool.oss;
  2. import java.util.Objects;
  3. import java.util.prefs.Preferences;
  4. /**
  5. * 阿里云 OSS 配置。
  6. *
  7. * <p>4 项核心字段:address / accessKey / secretKey / bucket。
  8. * 全部不为空且 address 是合法主机时被视作"有效配置",否则 {@link #isUsable()} 返回 false,
  9. * 用于让上层选择"不传图片"。</p>
  10. *
  11. * <p>address 不需要带协议前缀;不含 bucket 子域名(即只是 OSS endpoint,
  12. * 例如 <code>oss-cn-hangzhou.aliyuncs.com</code>)。
  13. * 上传时会自动拼成 <code>https://{bucket}.{address}/{key}</code>。</p>
  14. *
  15. * <p>配置持久化在用户 Preferences 节点 <code>/com/fujica/parkingtool/oss</code> 下。</p>
  16. */
  17. public final class OssSettings {
  18. private static final String PREF_ROOT = "/com/fujica/parkingtool/oss";
  19. private static final String KEY_ADDRESS = "address";
  20. private static final String KEY_ACCESS_KEY = "accessKey";
  21. private static final String KEY_SECRET_KEY = "secretKey";
  22. private static final String KEY_BUCKET = "bucket";
  23. private static final String KEY_PATH_PREFIX= "pathPrefix";
  24. /** OSS endpoint,不带 https://,不带 bucket 子域名 */
  25. private String address = "";
  26. private String accessKey = "";
  27. private String secretKey = "";
  28. private String bucket = "";
  29. /** 上传路径前缀,默认 parking-simulator */
  30. private String pathPrefix = "parking-simulator";
  31. public OssSettings() { }
  32. public String getAddress() { return address; }
  33. public void setAddress(String address) { this.address = address == null ? "" : address.trim(); }
  34. public String getAccessKey() { return accessKey; }
  35. public void setAccessKey(String accessKey) { this.accessKey = accessKey == null ? "" : accessKey.trim(); }
  36. public String getSecretKey() { return secretKey; }
  37. public void setSecretKey(String secretKey) { this.secretKey = secretKey == null ? "" : secretKey; }
  38. public String getBucket() { return bucket; }
  39. public void setBucket(String bucket) { this.bucket = bucket == null ? "" : bucket.trim(); }
  40. public String getPathPrefix() { return pathPrefix; }
  41. public void setPathPrefix(String pathPrefix) {
  42. if (pathPrefix == null) { this.pathPrefix = ""; return; }
  43. String p = pathPrefix.trim();
  44. // 去除首尾的多余斜杠
  45. while (p.startsWith("/")) p = p.substring(1);
  46. while (p.endsWith("/")) p = p.substring(0, p.length() - 1);
  47. this.pathPrefix = p;
  48. }
  49. /** 4 项核心字段全部非空,且 address 形如 host[:port] 才算有效。 */
  50. public boolean isUsable() {
  51. if (isBlank(address) || isBlank(accessKey) || isBlank(secretKey) || isBlank(bucket)) {
  52. return false;
  53. }
  54. String cleaned = cleanAddress(address);
  55. // 简单校验:不能是带协议的 URL;必须包含一个点
  56. return !cleaned.contains("://") && cleaned.contains(".");
  57. }
  58. /** 去除可能错误粘进来的协议前缀和尾部斜杠,返回纯 host[:port] */
  59. public static String cleanAddress(String raw) {
  60. if (raw == null) return "";
  61. String s = raw.trim();
  62. if (s.startsWith("https://")) s = s.substring(8);
  63. if (s.startsWith("http://")) s = s.substring(7);
  64. while (s.endsWith("/")) s = s.substring(0, s.length() - 1);
  65. return s;
  66. }
  67. /** 拼装最终公网 URL(https):{bucket}.{address}/{key} */
  68. public String publicUrl(String key) {
  69. String addr = cleanAddress(address);
  70. String k = key == null ? "" : (key.startsWith("/") ? key.substring(1) : key);
  71. return "https://" + bucket + "." + addr + "/" + k;
  72. }
  73. private static boolean isBlank(String s) {
  74. return s == null || s.trim().isEmpty();
  75. }
  76. public static OssSettings load() {
  77. OssSettings s = new OssSettings();
  78. Preferences p = node();
  79. s.address = p.get(KEY_ADDRESS, s.address);
  80. s.accessKey = p.get(KEY_ACCESS_KEY, s.accessKey);
  81. s.secretKey = p.get(KEY_SECRET_KEY, s.secretKey);
  82. s.bucket = p.get(KEY_BUCKET, s.bucket);
  83. s.pathPrefix = p.get(KEY_PATH_PREFIX,s.pathPrefix);
  84. return s;
  85. }
  86. public void save() {
  87. Preferences p = node();
  88. p.put(KEY_ADDRESS, address);
  89. p.put(KEY_ACCESS_KEY, accessKey);
  90. p.put(KEY_SECRET_KEY, secretKey);
  91. p.put(KEY_BUCKET, bucket);
  92. p.put(KEY_PATH_PREFIX,pathPrefix);
  93. }
  94. public OssSettings copy() {
  95. OssSettings s = new OssSettings();
  96. s.address = address;
  97. s.accessKey = accessKey;
  98. s.secretKey = secretKey;
  99. s.bucket = bucket;
  100. s.pathPrefix = pathPrefix;
  101. return s;
  102. }
  103. private static Preferences node() {
  104. return Preferences.userRoot().node(PREF_ROOT);
  105. }
  106. @Override
  107. public boolean equals(Object o) {
  108. if (this == o) return true;
  109. if (!(o instanceof OssSettings that)) return false;
  110. return Objects.equals(address, that.address)
  111. && Objects.equals(accessKey, that.accessKey)
  112. && Objects.equals(secretKey, that.secretKey)
  113. && Objects.equals(bucket, that.bucket)
  114. && Objects.equals(pathPrefix, that.pathPrefix);
  115. }
  116. @Override
  117. public int hashCode() {
  118. return Objects.hash(address, accessKey, secretKey, bucket, pathPrefix);
  119. }
  120. }