Browse Source

优化系统初始化,增加跨域支持

zhou-hao 5 years ago
parent
commit
c47e509aab

+ 114 - 0
hsweb-starter/src/main/java/org/hswebframework/web/starter/CorsAutoConfiguration.java

@@ -0,0 +1,114 @@
+package org.hswebframework.web.starter;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.cors.reactive.CorsWebFilter;
+import org.springframework.web.reactive.config.CorsRegistration;
+import org.springframework.web.reactive.config.CorsRegistry;
+import org.springframework.web.reactive.config.WebFluxConfigurer;
+
+import java.util.Collections;
+import java.util.Optional;
+
+/**
+ * 跨域设置,支持不同的请求路径,配置不同的跨域信息配置
+ *
+ * <p>
+ * Example:
+ * <pre class="code">
+ *   {@code
+ *      hsweb:
+ *        cors:
+ *          enable: true
+ *          configs:
+ *            - /**:
+ *                allowed-headers: "*"
+ *                allowed-methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
+ *                allowed-origins: ["http://xxx.example.com"]
+ *                allow-credentials: true
+ *                maxAge: 1800
+ *   }
+ * </pre>
+ * <p>
+ * enable设为true,但是configs未配置,将使用已下的默认配置:
+ * <pre class="code">
+ *   {@code
+ *      hsweb:
+ *        cors:
+ *          enable: true
+ *          configs:
+ *            - /**:
+ *                allowed-headers: "*"
+ *                allowed-methods: ["GET", "POST", "HEAD"]
+ *                allowed-origins: "*"
+ *                allow-credentials: true
+ *                maxAge: 1800
+ *   }
+ * </pre>
+ *
+ * <p>
+ * <b>注意:</b>
+ * 配置文件中对象的属性名在 SpringBoot 2.x 版本开始不在支持特殊字符,会将特殊字符过滤掉,
+ * 仅支持{@code [A-Za-z0-9\-\_]},具体细节请查看{@code ConfigurationPropertyName}类的{@code adapt}方法
+ *
+ * @author zhouhao
+ * @author Jia
+ * @since 1.0
+ */
+@Configuration
+@ConditionalOnProperty(prefix = "hsweb.cors", name = "enable", havingValue = "true")
+@EnableConfigurationProperties(CorsProperties.class)
+public class CorsAutoConfiguration {
+
+    @ConditionalOnClass(name = "javax.servlet.Filter")
+    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
+    @Configuration
+    static class WebMvcCorsConfiguration {
+        @Bean
+        public org.springframework.web.filter.CorsFilter corsFilter(CorsProperties corsProperties) {
+            UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
+
+            Optional.ofNullable(corsProperties.getConfigs())
+                    .orElseGet(()->Collections.singletonList(new CorsProperties.CorsConfiguration().applyPermitDefaultValues()))
+                    .forEach((config) ->
+                            corsConfigurationSource.registerCorsConfiguration(config.getPath(), buildConfiguration(config))
+                    );
+
+            return new org.springframework.web.filter.CorsFilter(corsConfigurationSource);
+        }
+    }
+    @Configuration
+    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
+    static class WebFluxCorsConfiguration{
+        @Bean
+        public CorsWebFilter webFluxCorsRegistration(CorsProperties corsProperties) {
+            org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource corsConfigurationSource = new org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource();
+
+            Optional.ofNullable(corsProperties.getConfigs())
+                    .orElseGet(()->Collections.singletonList(new CorsProperties.CorsConfiguration().applyPermitDefaultValues()))
+                    .forEach((config) ->
+                            corsConfigurationSource.registerCorsConfiguration(config.getPath(), buildConfiguration(config))
+                    );
+            return new CorsWebFilter(corsConfigurationSource);
+        }
+    }
+
+
+    private static CorsConfiguration buildConfiguration(CorsProperties.CorsConfiguration config) {
+        CorsConfiguration corsConfiguration = new CorsConfiguration();
+        corsConfiguration.setAllowedHeaders(config.getAllowedHeaders());
+        corsConfiguration.setAllowedMethods(config.getAllowedMethods());
+        corsConfiguration.setAllowedOrigins(config.getAllowedOrigins());
+        corsConfiguration.setAllowCredentials(config.getAllowCredentials());
+        corsConfiguration.setExposedHeaders(config.getExposedHeaders());
+        corsConfiguration.setMaxAge(config.getMaxAge());
+
+        return corsConfiguration;
+    }
+}

+ 107 - 0
hsweb-starter/src/main/java/org/hswebframework/web/starter/CorsProperties.java

@@ -0,0 +1,107 @@
+package org.hswebframework.web.starter;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.http.HttpMethod;
+import org.springframework.web.reactive.config.CorsRegistration;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+@ConfigurationProperties(prefix = "hsweb.cors"/*, ignoreInvalidFields = true*/)
+public class CorsProperties {
+
+    @Getter
+    @Setter
+    private List<CorsConfiguration> configs;
+
+    @Getter
+    @Setter
+    @ToString
+    public static class CorsConfiguration {
+
+        /**
+         * Wildcard representing <em>all</em> origins, methods, or headers.
+         */
+        public static final String ALL = "*";
+
+        private String path = "/**";
+
+        private List<String> allowedOrigins;
+
+        private List<String> allowedMethods;
+
+        private List<String> allowedHeaders;
+
+        private List<String> exposedHeaders;
+
+        private Boolean allowCredentials;
+
+        private Long maxAge = 1800L;
+
+        public void apply(CorsRegistration registry) {
+            if (CollectionUtils.isNotEmpty(this.allowedHeaders)) {
+                registry.allowedHeaders(this.getAllowedHeaders().toArray(new String[0]));
+            }
+            if (CollectionUtils.isNotEmpty(this.allowedMethods)) {
+                registry.allowedMethods(this.getAllowedMethods().toArray(new String[0]));
+            }
+            if (CollectionUtils.isNotEmpty(this.allowedOrigins)) {
+                registry.allowedOrigins(this.getAllowedOrigins().toArray(new String[0]));
+            }
+            if (CollectionUtils.isNotEmpty(this.exposedHeaders)) {
+                registry.exposedHeaders(this.getExposedHeaders().toArray(new String[0]));
+            }
+            if (this.maxAge == null) {
+                registry.maxAge(this.getMaxAge());
+            }
+            registry.allowCredentials(this.getAllowCredentials() == null || Boolean.TRUE.equals(this.getAllowCredentials()));
+        }
+
+        CorsConfiguration applyPermitDefaultValues() {
+            if (this.allowedOrigins == null) {
+                this.addAllowedOrigin();
+            }
+            if (this.allowedMethods == null) {
+                this.setAllowedMethods(Arrays.asList(
+                        HttpMethod.GET.name(), HttpMethod.HEAD.name(), HttpMethod.POST.name()));
+            }
+            if (this.allowedHeaders == null) {
+                this.addAllowedHeader();
+            }
+            if (this.allowCredentials == null) {
+                this.setAllowCredentials(true);
+            }
+            if (this.maxAge == null) {
+                this.setMaxAge(1800L);
+            }
+            return this;
+        }
+
+        /**
+         * Add an origin to allow.
+         */
+        void addAllowedOrigin() {
+            if (this.allowedOrigins == null) {
+                this.allowedOrigins = new ArrayList<>(4);
+            }
+            this.allowedOrigins.add(CorsConfiguration.ALL);
+        }
+
+        /**
+         * Add an actual request header to allow.
+         */
+        void addAllowedHeader() {
+            if (this.allowedHeaders == null) {
+                this.allowedHeaders = new ArrayList<>(4);
+            }
+            this.allowedHeaders.add(CorsConfiguration.ALL);
+        }
+    }
+
+}

+ 1 - 1
hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/AppProperties.java

@@ -13,7 +13,7 @@ public class AppProperties {
     private boolean      autoInit = true;
     private List<String> initTableExcludes;
 
-    private String name;
+    private String name = "default";
     private String comment;
     private String website;
     private String version;

+ 3 - 3
hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/DefaultDependencyUpgrader.java

@@ -13,13 +13,13 @@ import java.util.stream.Collectors;
  */
 public class DefaultDependencyUpgrader implements DependencyUpgrader {
     private Logger logger = LoggerFactory.getLogger(this.getClass());
-    SystemVersion.Dependency  installed;
-    SystemVersion.Dependency  dependency;
+    Dependency installed;
+    Dependency  dependency;
     List<Map<String, Object>> shouldUpdateVersionList;
     private Map<String, Object> context;
     private boolean             firstInstall;
 
-    public DefaultDependencyUpgrader(SystemVersion.Dependency installed, SystemVersion.Dependency dependency, Map<String, Object> context) {
+    public DefaultDependencyUpgrader(Dependency installed, Dependency dependency, Map<String, Object> context) {
         this.firstInstall = installed == null;
         if (firstInstall) {
             this.installed = dependency;

+ 60 - 0
hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/Dependency.java

@@ -0,0 +1,60 @@
+package org.hswebframework.web.starter.initialize;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+
+import java.util.Map;
+
+public  class Dependency extends Version {
+        protected String groupId;
+        protected String artifactId;
+        protected String author;
+
+        public String getGroupId() {
+            return groupId;
+        }
+
+        public void setGroupId(String groupId) {
+            this.groupId = groupId;
+        }
+
+        public String getArtifactId() {
+            return artifactId;
+        }
+
+        public void setArtifactId(String artifactId) {
+            this.artifactId = artifactId;
+        }
+
+        public String getAuthor() {
+            return author;
+        }
+
+        public void setAuthor(String author) {
+            this.author = author;
+        }
+
+        public static Dependency fromMap(Map<String, Object> map) {
+            Dependency dependency = new Dependency();
+            dependency.setGroupId((String) map.get("groupId"));
+            dependency.setArtifactId((String) map.get("artifactId"));
+            dependency.setName((String) map.getOrDefault(SystemVersion.Property.name, dependency.getArtifactId()));
+            dependency.setVersion((String) map.get("version"));
+            dependency.setWebsite((String) map.get(SystemVersion.Property.website));
+            dependency.setAuthor((String) map.get("author"));
+            return dependency;
+        }
+
+        public boolean isSameDependency(Dependency dependency) {
+            return isSameDependency(dependency.getGroupId(), dependency.getArtifactId());
+        }
+
+        public boolean isSameDependency(String groupId, String artifactId) {
+            return groupId.equals(this.getGroupId()) && artifactId.equals(this.getArtifactId());
+        }
+
+        @Override
+        public String toString() {
+            return JSON.toJSONString(this, SerializerFeature.PrettyFormat);
+        }
+    }

+ 2 - 2
hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/DependencyInstaller.java

@@ -25,10 +25,10 @@ import java.util.Map;
  * @author zhouhao
  */
 public interface DependencyInstaller {
-    DependencyInstaller setup(SystemVersion.Dependency dependency);
+    DependencyInstaller setup(Dependency dependency);
 
     default DependencyInstaller setup(Map<String, Object> mapDependency) {
-        return setup(SystemVersion.Dependency.fromMap(mapDependency));
+        return setup(Dependency.fromMap(mapDependency));
     }
 
     DependencyInstaller onInstall(CallBack callBack);

+ 4 - 4
hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/SimpleDependencyInstaller.java

@@ -9,7 +9,7 @@ import java.util.Map;
  * @author zhouhao
  */
 public class SimpleDependencyInstaller implements DependencyInstaller {
-    SystemVersion.Dependency dependency;
+    Dependency dependency;
     CallBack installer;
     CallBack upgrader;
     CallBack unInstaller;
@@ -19,7 +19,7 @@ public class SimpleDependencyInstaller implements DependencyInstaller {
     public SimpleDependencyInstaller() {
     }
 
-    public SystemVersion.Dependency getDependency() {
+    public Dependency getDependency() {
         return dependency;
     }
 
@@ -47,7 +47,7 @@ public class SimpleDependencyInstaller implements DependencyInstaller {
         }
     }
 
-    public void doUpgrade(Map<String, Object> context, SystemVersion.Dependency installed) {
+    public void doUpgrade(Map<String, Object> context, Dependency installed) {
         DefaultDependencyUpgrader defaultDependencyUpgrader =
                 new DefaultDependencyUpgrader(installed, dependency, context);
         context.put("upgrader", defaultDependencyUpgrader);
@@ -57,7 +57,7 @@ public class SimpleDependencyInstaller implements DependencyInstaller {
     }
 
     @Override
-    public DependencyInstaller setup(SystemVersion.Dependency dependency) {
+    public DependencyInstaller setup(Dependency dependency) {
         this.dependency = dependency;
         return this;
     }

+ 0 - 4
hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/SystemInitialize.java

@@ -7,14 +7,10 @@ import org.hswebframework.expands.script.engine.DynamicScriptEngineFactory;
 import org.hswebframework.ezorm.rdb.codec.ClobValueCodec;
 import org.hswebframework.ezorm.rdb.codec.CompositeValueCodec;
 import org.hswebframework.ezorm.rdb.codec.JsonValueCodec;
-import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor;
-import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor;
-import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSyncSqlExecutor;
 import org.hswebframework.ezorm.rdb.mapping.SyncRepository;
 import org.hswebframework.ezorm.rdb.mapping.defaults.record.Record;
 import org.hswebframework.ezorm.rdb.operator.DatabaseOperator;
 import org.hswebframework.web.bean.FastBeanCopier;
-import org.hswebframework.web.starter.initialize.SystemVersion.Dependency;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.core.io.Resource;

+ 46 - 184
hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/SystemVersion.java

@@ -18,10 +18,6 @@
 
 package org.hswebframework.web.starter.initialize;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
-import lombok.extern.slf4j.Slf4j;
-import org.hswebframework.utils.ListUtils;
 import org.hswebframework.utils.StringUtils;
 
 import java.util.ArrayList;
@@ -29,7 +25,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class SystemVersion extends Version {
+public class SystemVersion extends Version  {
 
     public SystemVersion() {
     }
@@ -81,187 +77,53 @@ public class SystemVersion extends Version {
         public FrameworkVersion() {
             setName("hsweb framework");
             setComment("企业后台管理系统基础框架");
-            setWebsite("http://www.hsweb.me");
+            setWebsite("http://www.hsweb.io");
             setComment("");
-            setVersion(4, 0, 0);
-        }
-    }
-
-
-    public static class Dependency extends Version {
-        protected String groupId;
-        protected String artifactId;
-        protected String author;
-
-        public String getGroupId() {
-            return groupId;
-        }
-
-        public void setGroupId(String groupId) {
-            this.groupId = groupId;
-        }
-
-        public String getArtifactId() {
-            return artifactId;
-        }
-
-        public void setArtifactId(String artifactId) {
-            this.artifactId = artifactId;
-        }
-
-        public String getAuthor() {
-            return author;
-        }
-
-        public void setAuthor(String author) {
-            this.author = author;
-        }
-
-        public static Dependency fromMap(Map<String, Object> map) {
-            Dependency dependency = new Dependency();
-            dependency.setGroupId((String) map.get("groupId"));
-            dependency.setArtifactId((String) map.get("artifactId"));
-            dependency.setName((String) map.getOrDefault("name", dependency.getArtifactId()));
-            dependency.setVersion((String) map.get("version"));
-            dependency.setWebsite((String) map.get("website"));
-            dependency.setAuthor((String) map.get("author"));
-            return dependency;
-        }
-
-        public boolean isSameDependency(Dependency dependency) {
-            return isSameDependency(dependency.getGroupId(), dependency.getArtifactId());
-        }
-
-        public boolean isSameDependency(String groupId, String artifactId) {
-            return groupId.equals(this.getGroupId()) && artifactId.equals(this.getArtifactId());
-        }
-
-        @Override
-        public String toString() {
-            return JSON.toJSONString(this, SerializerFeature.PrettyFormat);
-        }
-    }
-}
-
-@Slf4j
-class Version implements Comparable<Version> {
-    protected String  name;
-    protected String  comment;
-    protected String  website;
-    protected int     majorVersion    = 1;
-    protected int     minorVersion    = 0;
-    protected int     revisionVersion = 0;
-
-    public void setVersion(int major, int minor, int revision) {
-        this.majorVersion = major;
-        this.minorVersion = minor;
-        this.revisionVersion = revision;
-    }
-
-    public void setVersion(String version) {
-        if (null == version) {
-            return;
-        }
-        version = version.toLowerCase();
-
-        boolean snapshot = version.toLowerCase().contains("snapshot");
-
-        String[] ver = version.split("[-]")[0].split("[.]");
-        Integer[] numberVer = ListUtils.stringArr2intArr(ver);
-        if (numberVer.length == 0) {
-            numberVer = new Integer[]{1, 0, 0};
-            log.warn("解析版本号失败:{},将使用默认版本号:1.0.0,请检查hsweb-starter.js配置内容!", version);
-        }
-
-        for (int i = 0; i < numberVer.length; i++) {
-            if (numberVer[i] == null) {
-                numberVer[i] = 0;
-            }
-        }
-        setVersion(numberVer[0],
-                numberVer.length <= 1 ? 0 : numberVer[1],
-                numberVer.length <= 2 ? 0 : numberVer[2]);
-    }
-
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getComment() {
-        return comment;
-    }
-
-    public void setComment(String comment) {
-        this.comment = comment;
-    }
-
-    public String getWebsite() {
-        if (website == null) {
-            website = "";
-        }
-        return website;
-    }
-
-    public void setWebsite(String website) {
-        this.website = website;
-    }
-
-    public int getMajorVersion() {
-        return majorVersion;
-    }
-
-    public void setMajorVersion(int majorVersion) {
-        this.majorVersion = majorVersion;
-    }
-
-    public int getMinorVersion() {
-        return minorVersion;
-    }
-
-    public void setMinorVersion(int minorVersion) {
-        this.minorVersion = minorVersion;
-    }
-
-    public int getRevisionVersion() {
-        return revisionVersion;
+            setVersion(4, 0, 0, true);
+        }
+    }
+
+
+    public interface Property {
+        /**
+         * @see SystemVersion#name
+         */
+        String name            = "name";
+        /**
+         * @see SystemVersion#comment
+         */
+        String comment         = "comment";
+        /**
+         * @see SystemVersion#website
+         */
+        String website         = "website";
+        /**
+         * @see SystemVersion#majorVersion
+         */
+        String majorVersion    = "majorVersion";
+        /**
+         * @see SystemVersion#minorVersion
+         */
+        String minorVersion    = "minorVersion";
+        /**
+         * @see SystemVersion#revisionVersion
+         */
+        String revisionVersion = "revisionVersion";
+        /**
+         * @see SystemVersion#snapshot
+         */
+        String snapshot        = "snapshot";
+
+        /**
+         * @see SystemVersion#frameworkVersion
+         */
+        String frameworkVersion = "frameworkVersion";
+
+        /**
+         * @see SystemVersion#dependencies
+         */
+        String dependencies = "dependencies";
     }
 
-    public void setRevisionVersion(int revisionVersion) {
-        this.revisionVersion = revisionVersion;
-    }
-
-    @Override
-    public int compareTo(Version o) {
-        if (null == o) {
-            return -1;
-        }
-        if (o.getMajorVersion() > this.getMajorVersion()) {
-            return -1;
-        }
-        if (o.getMajorVersion() == this.getMajorVersion()) {
-            if (o.getMinorVersion() > this.getMinorVersion()) {
-                return -1;
-            }
-            if (o.getMinorVersion() == this.getMinorVersion()) {
-                return Integer.compare(this.getRevisionVersion(), o.getRevisionVersion());
-            } else {
-                return 1;
-            }
-        } else {
-            return 1;
-        }
-    }
-
-    @Override
-    public String toString() {
-        return name + " version " +
-                majorVersion + "." +
-                minorVersion;
-    }
 
 }

+ 147 - 0
hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/Version.java

@@ -0,0 +1,147 @@
+package org.hswebframework.web.starter.initialize;
+
+import lombok.extern.slf4j.Slf4j;
+import org.hswebframework.utils.ListUtils;
+
+import java.io.Serializable;
+
+@Slf4j
+public class Version implements Comparable<Version>, Serializable {
+    protected String name;
+    protected String comment;
+    protected String website;
+    protected int majorVersion = 1;
+    protected int minorVersion = 0;
+    protected int revisionVersion = 0;
+    protected boolean snapshot = false;
+
+    public void setVersion(int major, int minor, int revision, boolean snapshot) {
+        this.majorVersion = major;
+        this.minorVersion = minor;
+        this.revisionVersion = revision;
+        this.snapshot = snapshot;
+    }
+
+    public void setVersion(String version) {
+        if (null == version) {
+            return;
+        }
+        version = version.toLowerCase();
+
+        boolean snapshot = version.toLowerCase().contains("snapshot");
+
+        String[] ver = version.split("[-]")[0].split("[.]");
+        Integer[] numberVer = ListUtils.stringArr2intArr(ver);
+        if (numberVer.length == 0) {
+            numberVer = new Integer[]{1, 0, 0};
+            log.warn("解析版本号失败:{},将使用默认版本号:1.0.0,请检查hsweb-starter.js配置内容!", version);
+        }
+
+        for (int i = 0; i < numberVer.length; i++) {
+            if (numberVer[i] == null) {
+                numberVer[i] = 0;
+            }
+        }
+        setVersion(numberVer[0],
+                numberVer.length <= 1 ? 0 : numberVer[1],
+                numberVer.length <= 2 ? 0 : numberVer[2],
+                snapshot);
+    }
+
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getComment() {
+        return comment;
+    }
+
+    public void setComment(String comment) {
+        this.comment = comment;
+    }
+
+    public String getWebsite() {
+        if (website == null) {
+            website = "";
+        }
+        return website;
+    }
+
+    public void setWebsite(String website) {
+        this.website = website;
+    }
+
+    public int getMajorVersion() {
+        return majorVersion;
+    }
+
+    public void setMajorVersion(int majorVersion) {
+        this.majorVersion = majorVersion;
+    }
+
+    public int getMinorVersion() {
+        return minorVersion;
+    }
+
+    public void setMinorVersion(int minorVersion) {
+        this.minorVersion = minorVersion;
+    }
+
+    public int getRevisionVersion() {
+        return revisionVersion;
+    }
+
+    public void setRevisionVersion(int revisionVersion) {
+        this.revisionVersion = revisionVersion;
+    }
+
+    public boolean isSnapshot() {
+        return snapshot;
+    }
+
+    public void setSnapshot(boolean snapshot) {
+        this.snapshot = snapshot;
+    }
+
+    @Override
+    public int compareTo(Version o) {
+        if (null == o) {
+            return -1;
+        }
+        if (o.getMajorVersion() > this.getMajorVersion()) {
+            return -1;
+        }
+        if (o.getMajorVersion() == this.getMajorVersion()) {
+            if (o.getMinorVersion() > this.getMinorVersion()) {
+                return -1;
+            }
+            if (o.getMinorVersion() == this.getMinorVersion()) {
+                return Integer.compare(this.getRevisionVersion(), o.getRevisionVersion());
+            } else {
+                return 1;
+            }
+        } else {
+            return 1;
+        }
+    }
+
+    public String versionToString() {
+        return String.valueOf(majorVersion) + "." +
+                minorVersion + "." +
+                revisionVersion + (snapshot ? "-SNAPSHOT" : "");
+    }
+
+    @Override
+    public String toString() {
+        return name + " version " +
+                majorVersion + "." +
+                minorVersion + "." +
+                revisionVersion + (snapshot ? "-SNAPSHOT" : "");
+    }
+
+}

+ 2 - 1
hsweb-starter/src/main/resources/META-INF/spring.factories

@@ -1,4 +1,5 @@
 # Auto Configure
 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
 org.hswebframework.web.starter.jackson.CustomCodecsAutoConfiguration,\
-org.hswebframework.web.starter.HswebAutoConfiguration
+org.hswebframework.web.starter.HswebAutoConfiguration,\
+org.hswebframework.web.starter.CorsAutoConfiguration