feat: 应用开发后端基础框架,初始提交
diff --git a/bff/admin/Dockerfile b/bff/admin/Dockerfile
new file mode 100644
index 0000000..4810f6b
--- /dev/null
+++ b/bff/admin/Dockerfile
@@ -0,0 +1,21 @@
+FROM harbor.supwisdom.com/institute/openjdk:8-jre
+
+ENV ENABLE_JMX_SSL=false
+ENV JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=docker
+ENV SPRING_PROFILES_ACTIVE=docker
+
+ARG NAME
+ARG VERSION
+ARG JAR_FILE
+
+LABEL name=$NAME \
+      version=$VERSION
+
+EXPOSE 8080
+
+EXPOSE 8443
+
+COPY --chown=java-app:java-app target/${JAR_FILE} /home/java-app/lib/app.jar
+
+COPY --chown=java-app:java-app target/doc /home/java-app/doc
+COPY --chown=java-app:java-app target/api-docs /home/java-app/api-docs
diff --git a/bff/admin/pom.xml b/bff/admin/pom.xml
new file mode 100644
index 0000000..5bc267a
--- /dev/null
+++ b/bff/admin/pom.xml
@@ -0,0 +1,247 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-admin-bff</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework Admin Backend for Frontend</name>
+  <description>Supwisdom Backend Framework Admin Backend for Frontend project</description>
+
+  <properties>
+    <start-class>com.supwisdom.institute.admin.bff.Application</start-class>
+  </properties>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+
+    <!-- 微服务 健康监控 -->
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-actuator</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-webflux</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.springframework.cloud</groupId>
+      <artifactId>spring-cloud-starter-gateway</artifactId>
+    </dependency>
+
+
+    <!-- <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-online-doc</artifactId>
+    </dependency> -->
+
+
+    <!-- <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-mvc</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-object-mapper</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-i18n</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-lang</artifactId>
+    </dependency> -->
+
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-security</artifactId>
+      <exclusions>
+        <exclusion>
+          <groupId>org.springframework.boot</groupId>
+          <artifactId>spring-boot-starter-web</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>io.jsonwebtoken</groupId>
+      <artifactId>jjwt</artifactId>
+      <version>0.9.1</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-cas</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-framework</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.alibaba</groupId>
+      <artifactId>fastjson</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+    </dependency>
+    <!-- <dependency>
+      <groupId>com.netflix.feign</groupId>
+      <artifactId>feign-httpclient</artifactId>
+    </dependency> -->
+
+
+    <dependency>
+      <groupId>io.springfox</groupId>
+      <artifactId>springfox-swagger2</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.springfox</groupId>
+      <artifactId>springfox-swagger-ui</artifactId>
+    </dependency>
+
+
+    <!-- 热部署,无需重启项目 -->
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-devtools</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <finalName>${project.artifactId}</finalName>
+
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+
+
+      <!-- <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <configuration>
+          <encoding>${project.build.sourceEncoding}</encoding>
+        </configuration>
+        <executions>
+          <execution>
+            <id>copy-doc-resources</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <encoding>utf-8</encoding>
+              <outputDirectory>${basedir}/target/doc</outputDirectory>
+              <overwrite>true</overwrite>
+              <resources>
+                <resource>
+                  <directory>${basedir}/../../doc</directory>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+          <execution>
+            <id>copy-certs-jwt-resources</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <encoding>utf-8</encoding>
+              <outputDirectory>${basedir}/target/certs/jwt</outputDirectory>
+              <overwrite>true</overwrite>
+              <resources>
+                <resource>
+                  <directory>${basedir}/../../certs/jwt</directory>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin> -->
+
+
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
+      </plugin>
+
+      <plugin>
+        <groupId>com.spotify</groupId>
+        <artifactId>dockerfile-maven-plugin</artifactId>
+        <configuration>
+          <skip>false</skip>
+        </configuration>
+      </plugin>
+
+    </plugins>
+
+  </build>
+
+</project>
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/Application.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/Application.java
new file mode 100644
index 0000000..364ed0b
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/Application.java
@@ -0,0 +1,49 @@
+package com.supwisdom.institute.backend.admin.bff;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+//import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+//import com.supwisdom.infras.online.doc.configuration.EnableInfrasOnlineDoc;
+import com.supwisdom.infras.security.configure.basic.EnableInfrasBasicApi;
+import com.supwisdom.infras.security.configure.cas.EnableInfrasCasSecurity;
+import com.supwisdom.infras.security.configure.jwt.EnableInfrasJWTApi;
+import com.supwisdom.institute.backend.common.core.transmit.annotation.EnableSimpleUserTransmit;
+
+@SpringBootApplication
+//@EnableFeignClients
+
+@EnableSimpleUserTransmit
+
+//@EnableInfrasOnlineDoc
+
+@EnableInfrasCasSecurity
+
+@EnableInfrasBasicApi
+@EnableInfrasJWTApi
+public class Application {
+
+  public static void main(String[] args) {
+    SpringApplication.run(Application.class, args);
+  }
+  
+  @Bean
+  public CorsFilter corsFilter() {
+    final CorsConfiguration config = new CorsConfiguration();
+    //config.setAllowCredentials(true);
+    config.addAllowedOrigin("*");
+    config.addAllowedHeader("*");
+    config.addAllowedMethod("*");
+
+    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+    source.registerCorsConfiguration("/v2/api-docs", config);
+    source.registerCorsConfiguration("/api/**", config);  // 对 /api/** 下的请求,支持 cors 跨域请求,如不需要可以注释
+
+    return new CorsFilter(source);
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/controller/.gitkeep b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/controller/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/controller/.gitkeep
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/controller/biz/AdminBizController.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/controller/biz/AdminBizController.java
new file mode 100644
index 0000000..68bd37a
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/controller/biz/AdminBizController.java
@@ -0,0 +1,17 @@
+package com.supwisdom.institute.backend.admin.bff.apis.controller.biz;
+
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(value = "/api/bff/v1/admin/biz")
+public class AdminBizController {
+
+  @RequestMapping(method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  public String biz() {
+    return "biz";
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/controller/system/AdminSystemController.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/controller/system/AdminSystemController.java
new file mode 100644
index 0000000..84d0f3a
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/controller/system/AdminSystemController.java
@@ -0,0 +1,17 @@
+package com.supwisdom.institute.backend.admin.bff.apis.controller.system;
+
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(value = "/api/bff/v1/admin/system")
+public class AdminSystemController {
+  
+  @RequestMapping(method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  public String hello() {
+    return "hello";
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/remote/.gitkeep b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/remote/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/remote/.gitkeep
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/service/.gitkeep b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/service/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/service/.gitkeep
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/vo/.gitkeep b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/vo/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/vo/.gitkeep
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/FeignBasicAuthRequestInterceptor.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/FeignBasicAuthRequestInterceptor.java
new file mode 100644
index 0000000..2a22b46
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/FeignBasicAuthRequestInterceptor.java
@@ -0,0 +1,77 @@
+package com.supwisdom.institute.backend.admin.bff.configuration;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * feign请求参数转化
+ * @author fengpy
+ */
+@Configuration
+public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    public FeignBasicAuthRequestInterceptor() {}
+
+    @Override
+    public void apply(RequestTemplate template) {
+        ///**get-pojo贯穿*/
+        if (template.method().equals("GET") && template.request().body() != null) {
+            try {
+                JsonNode jsonNode = objectMapper.readTree(template.request().body());
+                //template.body(null);
+                Map<String, Collection<String>> queries = new HashMap<>();
+                //feign 不支持 GET 方法传 POJO, json body转query
+                buildQuery(jsonNode, "", queries);
+                template.queries(queries);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    //处理 get-pojo贯穿
+    private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) {
+        if (!jsonNode.isContainerNode()) { //叶子节点
+            if (jsonNode.isNull()) {
+                return;
+            }
+            Collection<String> values = queries.get(path);
+            if (null == values) {
+                values = new ArrayList<>();
+                queries.put(path, values);
+            }
+            values.add(jsonNode.asText());
+            return;
+        }
+        if (jsonNode.isArray()) { //数组节点
+            Iterator<JsonNode> it = jsonNode.elements();
+            while (it.hasNext()) {
+                buildQuery(it.next(), path, queries);
+            }
+        } else {
+            Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
+            while (it.hasNext()) {
+                Map.Entry<String, JsonNode> entry = it.next();
+                if (StringUtils.hasText(path)) {
+                    if ("mapBean".equals(path)||"orderBy".equals(path)||"sequence".equals(path)) {
+                        buildQuery(entry.getValue(), path + "[" + entry.getKey() + "]", queries);
+                    } else {
+                        buildQuery(entry.getValue(), path + "." + entry.getKey(), queries);
+                    }
+                } else { //根节点
+                    buildQuery(entry.getValue(), entry.getKey(), queries);
+                }
+            }
+        }
+    }
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/GatewayFilterConfig.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/GatewayFilterConfig.java
new file mode 100644
index 0000000..f475158
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/GatewayFilterConfig.java
@@ -0,0 +1,16 @@
+package com.supwisdom.institute.backend.admin.bff.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.supwisdom.institute.backend.admin.bff.gateway.filter.factory.SimpleUserTransmitGatewayFilterFactory;
+
+@Configuration
+public class GatewayFilterConfig {
+
+  @Bean
+  public SimpleUserTransmitGatewayFilterFactory simpleUserTransmitGatewayFilterFactory() {
+    return new SimpleUserTransmitGatewayFilterFactory();
+  }
+  
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/GlobalFilterConfig.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/GlobalFilterConfig.java
new file mode 100644
index 0000000..e9e6282
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/GlobalFilterConfig.java
@@ -0,0 +1,16 @@
+package com.supwisdom.institute.backend.admin.bff.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.supwisdom.institute.backend.admin.bff.gateway.filter.SimpleUserTransmitGlobalFilter;
+
+@Configuration
+public class GlobalFilterConfig {
+
+  @Bean
+  public SimpleUserTransmitGlobalFilter simpleUserTransmitGlobalFilter() {
+    return new SimpleUserTransmitGlobalFilter();
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/InfrasFilterSecurityInterceptorConfig.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/InfrasFilterSecurityInterceptorConfig.java
new file mode 100644
index 0000000..6c77526
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/InfrasFilterSecurityInterceptorConfig.java
@@ -0,0 +1,53 @@
+package com.supwisdom.institute.backend.admin.bff.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.access.AccessDecisionManager;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+
+import com.supwisdom.infras.security.web.access.intercept.InfrasFilterSecurityInterceptor;
+import com.supwisdom.institute.backend.admin.bff.security.web.access.MyAccessDecisionManager;
+import com.supwisdom.institute.backend.admin.bff.security.web.access.intercept.InMemeryFilterInvocationSecurityMetadataSource;
+import com.supwisdom.institute.backend.admin.bff.security.web.access.intercept.MyFilterSecurityInterceptor;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Configuration
+public class InfrasFilterSecurityInterceptorConfig {
+
+//  @Bean
+//  public FilterInvocationSecurityMetadataSource securityMetadataSource() {
+//    MyFilterInvocationSecurityMetadataSource securityMetadataSource = new MyFilterInvocationSecurityMetadataSource();
+//    log.debug("InfrasFilterSecurityInterceptorConfig securityMetadataSource is {}", securityMetadataSource);
+//
+//    return securityMetadataSource;
+//  }
+  
+  @Bean
+  public FilterInvocationSecurityMetadataSource securityMetadataSource() {
+    InMemeryFilterInvocationSecurityMetadataSource securityMetadataSource = new InMemeryFilterInvocationSecurityMetadataSource();
+    log.debug("InfrasFilterSecurityInterceptorConfig securityMetadataSource is {}", securityMetadataSource);
+
+    return securityMetadataSource;
+  }
+  
+  
+  @Bean
+  public AccessDecisionManager accessDecisionManager() {
+    MyAccessDecisionManager accessDecisionManager = new MyAccessDecisionManager();
+    log.debug("InfrasFilterSecurityInterceptorConfig accessDecisionManager is {}", accessDecisionManager);
+
+    return accessDecisionManager;
+  }
+  
+  @Bean
+  public InfrasFilterSecurityInterceptor infrasFilterSecurityInterceptor() throws Exception {
+    MyFilterSecurityInterceptor myFilterSecurityInterceptor = new MyFilterSecurityInterceptor();
+    myFilterSecurityInterceptor.setRejectPublicInvocations(true);
+    log.debug("InfrasFilterSecurityInterceptorConfig infrasFilterSecurityInterceptor is {}", myFilterSecurityInterceptor);
+
+    return myFilterSecurityInterceptor;
+  }
+  
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/ListenerConfig.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/ListenerConfig.java
new file mode 100644
index 0000000..3f94d53
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/ListenerConfig.java
@@ -0,0 +1,27 @@
+package com.supwisdom.institute.backend.admin.bff.configuration;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+
+import com.supwisdom.institute.backend.admin.bff.listener.MyFilterInvocationSecurityMetadataSourceRefreshListener;
+
+@Configuration
+public class ListenerConfig {
+  
+  @Autowired
+  private FilterInvocationSecurityMetadataSource securityMetadataSource;
+  
+  @Bean
+  public ServletListenerRegistrationBean<MyFilterInvocationSecurityMetadataSourceRefreshListener> serssionListenerBean(){
+    MyFilterInvocationSecurityMetadataSourceRefreshListener listener = new MyFilterInvocationSecurityMetadataSourceRefreshListener();
+    listener.setSecurityMetadataSource(securityMetadataSource);
+    
+    ServletListenerRegistrationBean<MyFilterInvocationSecurityMetadataSourceRefreshListener> refreshListener = 
+        new ServletListenerRegistrationBean<MyFilterInvocationSecurityMetadataSourceRefreshListener>(listener);
+    return refreshListener;
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/PasswordEncoderConfig.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/PasswordEncoderConfig.java
new file mode 100644
index 0000000..b44d152
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/PasswordEncoderConfig.java
@@ -0,0 +1,29 @@
+package com.supwisdom.institute.backend.admin.bff.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.factory.PasswordEncoderFactories;
+import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Configuration
+public class PasswordEncoderConfig {
+
+  @Bean
+  public PasswordEncoder passwordEncoder() {
+    
+    PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
+
+    if (passwordEncoder instanceof DelegatingPasswordEncoder) {
+      ((DelegatingPasswordEncoder)passwordEncoder).setDefaultPasswordEncoderForMatches(NoOpPasswordEncoder.getInstance());
+    }
+
+    log.debug("PasswordEncoderConfig passwordEncoder is {}", passwordEncoder);
+    return passwordEncoder;
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/UserDetailsServiceConfig.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/UserDetailsServiceConfig.java
new file mode 100644
index 0000000..63945f4
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/UserDetailsServiceConfig.java
@@ -0,0 +1,31 @@
+package com.supwisdom.institute.backend.admin.bff.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.supwisdom.institute.backend.admin.bff.security.core.userdetails.InMemeryUserDetailsService;
+import com.supwisdom.institute.backend.admin.bff.security.core.userdetails.MyUserDetailsService;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Configuration
+public class UserDetailsServiceConfig {
+
+//  @Bean
+//  public MyUserDetailsService userDetailsService() throws Exception {
+//    MyUserDetailsService myUserDetailsService = new MyUserDetailsService();
+//    log.debug("UserDetailsServiceConfig myUserDetailsService is {}", myUserDetailsService);
+//
+//    return myUserDetailsService;
+//  }
+
+  @Bean
+  public InMemeryUserDetailsService userDetailsService() throws Exception {
+    InMemeryUserDetailsService inMemeryUserDetailsService = new InMemeryUserDetailsService();
+    log.debug("UserDetailsServiceConfig inMemeryUserDetailsService is {}", inMemeryUserDetailsService);
+
+    return inMemeryUserDetailsService;
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/gateway/filter/SimpleUserTransmitGlobalFilter.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/gateway/filter/SimpleUserTransmitGlobalFilter.java
new file mode 100644
index 0000000..a9bf2ae
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/gateway/filter/SimpleUserTransmitGlobalFilter.java
@@ -0,0 +1,60 @@
+package com.supwisdom.institute.backend.admin.bff.gateway.filter;
+
+import java.net.URLDecoder;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.core.Ordered;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.ReactiveSecurityContextHolder;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.web.server.ServerWebExchange;
+
+import com.alibaba.fastjson.JSONObject;
+import com.supwisdom.institute.backend.admin.bff.security.core.userdetails.MyUser;
+import com.supwisdom.institute.backend.common.core.transmit.user.User;
+import com.supwisdom.institute.backend.common.core.transmit.user.UserContext;
+
+import reactor.core.publisher.Mono;
+
+@Slf4j
+public class SimpleUserTransmitGlobalFilter implements GlobalFilter, Ordered {
+
+  @Override
+  public int getOrder() {
+    return 0;
+  }
+
+  @Override
+  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+    
+    return ReactiveSecurityContextHolder.getContext()
+      .filter(c -> c.getAuthentication() != null && c.getAuthentication().isAuthenticated() && c.getAuthentication().getPrincipal() instanceof MyUser)
+      .map(SecurityContext::getAuthentication)
+      .map(Authentication::getPrincipal)
+      .cast(MyUser.class)
+      .map(myUser -> {
+        try {
+          User user = new User(myUser.getUsername(), myUser.getRoles(), myUser.getAttributes());
+          
+          String jsonUser = JSONObject.toJSONString(user);
+          log.info(jsonUser);
+          String headerValue = new String(URLDecoder.decode(jsonUser,"UTF-8"));
+          ServerHttpRequest request = exchange.getRequest().mutate()
+              .header(UserContext.KEY_USER_IN_HTTP_HEADER, headerValue)
+              .build();
+          log.debug("User set ok");
+          return exchange.mutate().request(request).build();
+        } catch (Exception e) {
+          log.warn("User set error", e);
+        }
+        return exchange;
+      })
+      .flatMap(ex -> chain.filter(ex))
+    ;
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/gateway/filter/factory/SimpleUserTransmitGatewayFilterFactory.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/gateway/filter/factory/SimpleUserTransmitGatewayFilterFactory.java
new file mode 100644
index 0000000..6d0d981
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/gateway/filter/factory/SimpleUserTransmitGatewayFilterFactory.java
@@ -0,0 +1,93 @@
+package com.supwisdom.institute.backend.admin.bff.gateway.filter.factory;
+
+import java.net.URLDecoder;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.ReactiveSecurityContextHolder;
+import org.springframework.security.core.context.SecurityContext;
+
+import com.alibaba.fastjson.JSONObject;
+import com.supwisdom.institute.backend.admin.bff.security.core.userdetails.MyUser;
+import com.supwisdom.institute.backend.common.core.transmit.user.User;
+import com.supwisdom.institute.backend.common.core.transmit.user.UserContext;
+
+@Slf4j
+public class SimpleUserTransmitGatewayFilterFactory extends AbstractGatewayFilterFactory<SimpleUserTransmitGatewayFilterFactory.Config> {
+  
+  public SimpleUserTransmitGatewayFilterFactory() {
+    super(Config.class);
+  }
+
+  @Override
+  public GatewayFilter apply(Config config) {
+    return (exchange, chain) -> {
+      
+      
+//      Mono<ServerWebExchange> m = Mono.fromCallable(() ->{
+//        MyUser myUser = ReactiveSecurityContextHolder.getContext()
+//            .filter(c -> c.getAuthentication() != null)
+//            .map(SecurityContext::getAuthentication)
+//            .map(Authentication::getPrincipal)
+//            .cast(MyUser.class)
+//            .block()
+//          ;
+//          try {
+//            String jsonUser = JSONObject.toJSONString(myUser);
+//            log.info(jsonUser);
+//            String headerValue = new String(URLDecoder.decode(jsonUser,"UTF-8"));
+//            ServerHttpRequest request = exchange.getRequest().mutate()
+//                .header(UserContext.KEY_USER_IN_HTTP_HEADER, headerValue)
+//                .build();
+//            log.debug("User set ok");
+//            return exchange.mutate().request(request).build();
+//          } catch (Exception e) {
+//            log.warn("User set error", e);
+//          }
+//          return exchange;
+//      })
+//      .publishOn(Schedulers.elastic())
+//      ;
+//      return m.flatMap(ex -> chain.filter(ex));
+
+      
+      return ReactiveSecurityContextHolder.getContext()
+          .filter(c -> c.getAuthentication() != null && c.getAuthentication().isAuthenticated() && c.getAuthentication().getPrincipal() instanceof MyUser)
+          .map(SecurityContext::getAuthentication)
+          .map(Authentication::getPrincipal)
+          .cast(MyUser.class)
+          .map(myUser -> {
+            try {
+              User user = new User(myUser.getUsername(), myUser.getRoles(), myUser.getAttributes());
+              
+              String jsonUser = JSONObject.toJSONString(user);
+              log.info(jsonUser);
+              String headerValue = new String(URLDecoder.decode(jsonUser,"UTF-8"));
+              ServerHttpRequest request = exchange.getRequest().mutate()
+                  .header(UserContext.KEY_USER_IN_HTTP_HEADER, headerValue)
+                  .build();
+              log.debug("User set ok");
+              return exchange.mutate().request(request).build();
+            } catch (Exception e) {
+              log.warn("User set error", e);
+            }
+            return exchange;
+          })
+          .flatMap(ex -> chain.filter(ex))
+        ;
+    };
+  }
+
+  public static class Config {
+    @Getter
+    @Setter
+    private String a;
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/gateway/route/CustomRouteLocator.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/gateway/route/CustomRouteLocator.java
new file mode 100644
index 0000000..fc90c15
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/gateway/route/CustomRouteLocator.java
@@ -0,0 +1,17 @@
+package com.supwisdom.institute.backend.admin.bff.gateway.route;
+
+import org.springframework.cloud.gateway.route.Route;
+import org.springframework.cloud.gateway.route.RouteLocator;
+
+import reactor.core.publisher.Flux;
+
+public class CustomRouteLocator implements RouteLocator {
+
+  @Override
+  public Flux<Route> getRoutes() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/listener/MyFilterInvocationSecurityMetadataSourceRefreshListener.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/listener/MyFilterInvocationSecurityMetadataSourceRefreshListener.java
new file mode 100644
index 0000000..2c6d2bd
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/listener/MyFilterInvocationSecurityMetadataSourceRefreshListener.java
@@ -0,0 +1,59 @@
+package com.supwisdom.institute.backend.admin.bff.listener;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import javax.servlet.ServletContextEvent;
+
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+import org.springframework.web.context.ContextLoaderListener;
+
+import com.supwisdom.institute.backend.admin.bff.security.web.access.intercept.MyFilterInvocationSecurityMetadataSource;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class MyFilterInvocationSecurityMetadataSourceRefreshListener extends ContextLoaderListener {
+
+  private FilterInvocationSecurityMetadataSource securityMetadataSource;
+  public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
+    this.securityMetadataSource = securityMetadataSource;
+  }
+
+  private Timer timer = null;
+
+  private int delay = 1; // 启动后,延迟1分钟
+  private int period = 2; // 定时,每隔2分钟
+
+  @Override
+  public void contextInitialized(ServletContextEvent event) {
+    // super.contextInitialized(event);
+    log.info("MyFilterInvocationSecurityMetadataSourceRefreshListener.contextInitialized");
+
+    if (securityMetadataSource instanceof MyFilterInvocationSecurityMetadataSource) {
+      timer = new Timer("定时刷新权限信息", true);
+
+      timer.scheduleAtFixedRate(new TimerTask() {
+
+        @Override
+        public void run() {
+          ((MyFilterInvocationSecurityMetadataSource) securityMetadataSource).refreshRequestMap();
+        }
+
+      }, 1000 * 60 * delay, 1000 * 60 * period);
+
+    }
+
+  }
+
+  @Override
+  public void contextDestroyed(ServletContextEvent event) {
+    // super.contextDestroyed(event);
+    log.info("MyFilterInvocationSecurityMetadataSourceRefreshListener.contextDestroyed");
+
+    if (timer != null) {
+      timer.cancel();
+    }
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/core/userdetails/InMemeryUserDetailsService.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/core/userdetails/InMemeryUserDetailsService.java
new file mode 100644
index 0000000..bfe9a21
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/core/userdetails/InMemeryUserDetailsService.java
@@ -0,0 +1,72 @@
+package com.supwisdom.institute.backend.admin.bff.security.core.userdetails;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import com.supwisdom.institute.backend.common.core.transmit.user.User;
+import com.supwisdom.institute.backend.common.core.transmit.user.UserContext;
+
+import reactor.core.publisher.Mono;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class InMemeryUserDetailsService implements UserDetailsService, ReactiveUserDetailsService {
+
+  @Autowired
+  PasswordEncoder passwordEncoder;
+  
+  @Override
+  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+    
+    log.debug("InMemeryUserDetailsService.loadUserByUsername({})", username);
+    
+    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
+    authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
+    authorities.add(new SimpleGrantedAuthority("administrator"));
+    authorities.add(new SimpleGrantedAuthority("user"));
+
+    Map<String, Object> attributes = new HashMap<String, Object>();
+    
+    MyUser myUser = new MyUser(username, passwordEncoder.encode(username), authorities, attributes);
+    log.debug("myUser is {}", myUser);
+    
+    return myUser;
+  }
+
+  @Override
+  public Mono<UserDetails> findByUsername(String username) {
+
+    log.debug("InMemeryUserDetailsService.findByUsername({})", username);
+    
+    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
+    authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
+    authorities.add(new SimpleGrantedAuthority("administrator"));
+    authorities.add(new SimpleGrantedAuthority("user"));
+
+    Map<String, Object> attributes = new HashMap<String, Object>();
+    
+    MyUser myUser = new MyUser(username, passwordEncoder.encode(username), authorities, attributes);
+    log.debug("myUser is {}", myUser);
+    
+    List<String> roles = new ArrayList<>();
+    roles.add("ROLE_ADMIN");
+    roles.add("administrator");
+    roles.add("user");
+    User user = new User(username, roles, attributes);
+    UserContext.setUser(user);
+    
+    return Mono.just(myUser);
+  }
+  
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/core/userdetails/MyUser.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/core/userdetails/MyUser.java
new file mode 100644
index 0000000..b662422
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/core/userdetails/MyUser.java
@@ -0,0 +1,60 @@
+package com.supwisdom.institute.backend.admin.bff.security.core.userdetails;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+
+public class MyUser extends User {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 3195151947212484499L;
+
+  public MyUser(String username, String password, 
+      Collection<? extends GrantedAuthority> authorities, 
+      Map<String, Object> attributes) {
+    this(username, password, true, true, true, true, authorities, attributes);
+  }
+
+  public MyUser(String username, String password, 
+      boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, 
+      Collection<? extends GrantedAuthority> authorities, 
+      Map<String, Object> attributes) {
+    super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
+    
+    this.attributes = attributes;
+  }
+
+  private final Map<String, Object> attributes;
+  public Map<String, Object> getAttributes() {
+    return this.attributes;
+  }
+  
+  public List<String> getRoles() {
+    List<String> roles = new ArrayList<>();
+    for (GrantedAuthority grantedAuthority : this.getAuthorities()) {
+      roles.add(grantedAuthority.getAuthority());
+    }
+    
+    return roles;
+  }
+  
+
+  public Object getAttribute(String key) {
+    if (attributes == null) {
+      return null;
+    }
+    
+    if (!attributes.containsKey(key)) {
+      return null;
+    }
+    
+    return attributes.get(key);
+  }
+  
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/core/userdetails/MyUserDetailsService.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/core/userdetails/MyUserDetailsService.java
new file mode 100644
index 0000000..110af6b
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/core/userdetails/MyUserDetailsService.java
@@ -0,0 +1,79 @@
+package com.supwisdom.institute.backend.admin.bff.security.core.userdetails;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import reactor.core.publisher.Mono;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class MyUserDetailsService implements UserDetailsService, ReactiveUserDetailsService {
+  
+  @Autowired
+  PasswordEncoder passwordEncoder;
+
+//  @Autowired
+//  AccountService accountService;
+  
+  @Override
+  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // TODO: 
+
+    log.debug("MyUserDetailsService.loadUserByUsername({})", username);
+    
+//    Account account = accountService.loadByUsername(username);
+//    if (account == null) {
+//      throw new UsernameNotFoundException(String.format("%s not found", username));
+//    }
+//    
+//    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
+////    for (Role role : securityUser.getRoles()) {
+////      authorities.add(new SimpleGrantedAuthority(role.getCode()));
+////    }
+//    // FIXME: 
+//    authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
+//    authorities.add(new SimpleGrantedAuthority("administrator"));
+//    authorities.add(new SimpleGrantedAuthority("user"));
+//    
+//    Map<String, Object> attributes = new HashMap<String, Object>();
+//    attributes.put("userId", account.getUser().getId());
+//    attributes.put("userUid", account.getUser().getUid());
+//    
+//    MyUser myUser = new MyUser(
+//        account.getAccountName(), 
+//        account.getUser().getPassWord(), 
+//        account.getActivation() && "Normal".equals(account.getState()) ? true : false, 
+//        account.getAccountExpiryDate() == null || Calendar.getInstance().getTime().before(account.getAccountExpiryDate()) ? true : false,
+//        true, 
+//        true, 
+//        authorities,
+//        attributes);
+//    
+//    log.debug("myUser is {}", myUser);
+    
+    MyUser myUser = null;
+    
+    return myUser;
+  }
+
+  @Override
+  public Mono<UserDetails> findByUsername(String username) {
+    log.debug("MyUserDetailsService.findByUsername({})", username);
+    
+    MyUser myUser = null;
+    
+    return Mono.just(myUser);
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/MyAccessDecisionManager.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/MyAccessDecisionManager.java
new file mode 100644
index 0000000..56fe469
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/MyAccessDecisionManager.java
@@ -0,0 +1,48 @@
+package com.supwisdom.institute.backend.admin.bff.security.web.access;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.springframework.security.access.AccessDecisionManager;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.authentication.InsufficientAuthenticationException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+
+public class MyAccessDecisionManager implements AccessDecisionManager {
+
+  @Override
+  public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
+      throws AccessDeniedException, InsufficientAuthenticationException {
+
+    if (null == configAttributes || configAttributes.size() <= 0) {
+      return;
+    }
+    
+    ConfigAttribute ca;
+    String needRole;
+    for (Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext();) {
+      ca = iter.next();
+      needRole = ca.getAttribute();
+      for (GrantedAuthority ga : authentication.getAuthorities()) { // authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合
+        if (needRole.trim().equals(ga.getAuthority())) {
+          return;
+        }
+      }
+    }
+    
+    throw new AccessDeniedException("no right");
+  }
+
+  @Override
+  public boolean supports(ConfigAttribute attribute) {
+    return true;
+  }
+
+  @Override
+  public boolean supports(Class<?> clazz) {
+    return true;
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/intercept/InMemeryFilterInvocationSecurityMetadataSource.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/intercept/InMemeryFilterInvocationSecurityMetadataSource.java
new file mode 100644
index 0000000..5666b1a
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/intercept/InMemeryFilterInvocationSecurityMetadataSource.java
@@ -0,0 +1,76 @@
+package com.supwisdom.institute.backend.admin.bff.security.web.access.intercept;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.access.SecurityConfig;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+
+public class InMemeryFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
+  
+  private Map<RequestMatcher, Collection<ConfigAttribute>> requestMap = null;
+  
+  private void loadRequestMap() {
+    if (requestMap == null) {
+      requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
+      
+      AntPathRequestMatcher requestMatcher0 = new AntPathRequestMatcher("/api/**");
+      Collection<ConfigAttribute> attributes0 = new ArrayList<ConfigAttribute>();  // FIXME: 返回当前请求的url 对应的 角色代码
+      attributes0.add(new SecurityConfig("user"));
+      requestMap.put(requestMatcher0, attributes0);
+
+      
+      AntPathRequestMatcher requestMatcher = new AntPathRequestMatcher("/web/**");
+      Collection<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();  // FIXME: 返回当前请求的url 对应的 角色代码
+      attributes.add(new SecurityConfig("user"));
+      requestMap.put(requestMatcher, attributes);
+    }
+  }
+
+  /**
+   * 获取当前请求关联的所有角色code {@link SecurityConfig} 
+   * 用于和用户拥有的角色code 进行比对
+   */
+  @Override
+  public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
+    
+    if (requestMap == null) {
+      loadRequestMap();
+    }
+
+    HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
+    
+    RequestMatcher requestMatcher;
+    for(Iterator<RequestMatcher> iter = requestMap.keySet().iterator(); iter.hasNext(); ) {
+      requestMatcher = iter.next();
+      
+      if(requestMatcher.matches(request)) {
+        return requestMap.get(requestMatcher);
+      }
+    }
+    
+    return null;
+  }
+
+  @Override
+  public Collection<ConfigAttribute> getAllConfigAttributes() {
+
+    return null;
+  }
+
+  @Override
+  public boolean supports(Class<?> clazz) {
+
+    return true;
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/intercept/MyFilterInvocationSecurityMetadataSource.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/intercept/MyFilterInvocationSecurityMetadataSource.java
new file mode 100644
index 0000000..90f4b53
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/intercept/MyFilterInvocationSecurityMetadataSource.java
@@ -0,0 +1,129 @@
+package com.supwisdom.institute.backend.admin.bff.security.web.access.intercept;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.access.SecurityConfig;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
+  
+//  @Autowired
+//  User1SecurityPermissionRemoteService user1SecurityPermissionRemoteService;
+
+  private Map<RequestMatcher, Collection<ConfigAttribute>> requestMap = null;
+
+  public void refreshRequestMap() {
+    
+    log.info("MyFilterInvocationSecurityMetadataSource.refreshRequestMap");
+    
+    requestMap = null;
+    loadRequestMap();
+  }
+  
+  private void loadRequestMap() {
+    synchronized (MyFilterInvocationSecurityMetadataSource.class) {
+
+      if (requestMap == null) {
+        requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
+        
+//        String applicationCode = Constants.APPLICATION_CODE;
+//        SecurityPermission securityPermission = user1SecurityPermissionRemoteService.loadPermissionsByAppcode(applicationCode, null);
+//        if (securityPermission == null) {
+//          return;
+//        }
+//  
+//        Map<String, String> mapRoles = new HashMap<String, String>();
+//        for (Role r : securityPermission.getRoles()) {
+//          mapRoles.put(r.getId(), r.getCode());
+//        }
+//  
+//        Map<String, Collection<ConfigAttribute>> permissionRoles = new HashMap<String, Collection<ConfigAttribute>>();
+//        for (RolePermission rp : securityPermission.getRolePermissions()) {
+//          if (mapRoles.containsKey(rp.getRoleId())) {
+//            if (!permissionRoles.containsKey(rp.getPermissionId())) {
+//              permissionRoles.put(rp.getPermissionId(), new ArrayList<ConfigAttribute>());
+//            }
+//            ConfigAttribute ca = new SecurityConfig(mapRoles.get(rp.getRoleId()));
+//            permissionRoles.get(rp.getPermissionId()).add(ca);
+//          }
+//        }
+//  
+//        for (Permission p : securityPermission.getPermissions()) {
+//          Collection<ConfigAttribute> attributes = permissionRoles.get(p.getId());
+//          if (attributes == null) {
+//            attributes = new ArrayList<ConfigAttribute>();
+//          }
+//          
+//          if (p.getUrl() == null || p.getUrl().isEmpty()) {
+//            continue;
+//          }
+//          
+//          String pattern = p.getUrl();
+//          String httpMethod = null;
+//          
+//          if (pattern.startsWith("GET ") || pattern.startsWith("POST ") || pattern.startsWith("PUT ") || pattern.startsWith("DELETE ")) {
+//            httpMethod = pattern.substring(0, pattern.indexOf(" "));
+//            pattern = pattern.substring(pattern.indexOf(" ")+1);
+//          }
+//          
+//          AntPathRequestMatcher requestMatcher = new AntPathRequestMatcher(pattern, httpMethod);
+//  
+//          requestMap.put(requestMatcher, attributes);
+//        }
+      }
+      
+    }
+  }
+
+  /**
+   * 获取当前请求关联的所有角色code {@link SecurityConfig} 用于和用户拥有的角色code 进行比对
+   */
+  @Override
+  public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
+
+    if (requestMap == null) {
+      loadRequestMap();
+    }
+
+    HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
+
+    RequestMatcher requestMatcher;
+    for (Iterator<RequestMatcher> iter = requestMap.keySet().iterator(); iter.hasNext();) {
+      requestMatcher = iter.next();
+
+      if (requestMatcher.matches(request)) {
+        return requestMap.get(requestMatcher);
+      }
+    }
+
+    return null;
+  }
+
+  @Override
+  public Collection<ConfigAttribute> getAllConfigAttributes() {
+
+    return null;
+  }
+
+  @Override
+  public boolean supports(Class<?> clazz) {
+
+    return true;
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/intercept/MyFilterSecurityInterceptor.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/intercept/MyFilterSecurityInterceptor.java
new file mode 100644
index 0000000..7cd74e2
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/security/web/access/intercept/MyFilterSecurityInterceptor.java
@@ -0,0 +1,78 @@
+package com.supwisdom.institute.backend.admin.bff.security.web.access.intercept;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.ServletException;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.AccessDecisionManager;
+import org.springframework.security.access.SecurityMetadataSource;
+import org.springframework.security.access.intercept.InterceptorStatusToken;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+
+import com.supwisdom.infras.security.web.access.intercept.InfrasFilterSecurityInterceptor;
+import com.supwisdom.institute.backend.admin.bff.utils.AuthenticationUtil;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class MyFilterSecurityInterceptor extends InfrasFilterSecurityInterceptor {
+  
+  @Autowired
+  private FilterInvocationSecurityMetadataSource securityMetadataSource;
+
+  @Autowired
+  public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) {
+
+    super.setAccessDecisionManager(accessDecisionManager);
+  }
+
+  @Override
+  public void invoke(FilterInvocation fi) throws IOException, ServletException {
+    
+    Set<String> noneSecurityUrl = new HashSet<String>();  // FIXME: 对无须访问控制的url,支持可配置
+    noneSecurityUrl.add("/web/login");
+    noneSecurityUrl.add("/web/logout");
+    noneSecurityUrl.add("/web/index");
+
+    if (fi.getRequest() != null) {
+      String requestUrl = fi.getRequestUrl(); log.debug("MyFilterSecurityInterceptor invoke requestUrl: {}", requestUrl);
+      if (noneSecurityUrl.contains(requestUrl)) {
+        fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
+        return;
+      }
+    }
+    
+    if(AuthenticationUtil.isAdministrator()){
+     fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
+       return;
+  }
+    
+    // fi里面有一个被拦截的url
+    // 里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
+    // 再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够
+    InterceptorStatusToken token = super.beforeInvocation(fi);
+    try {
+      // 执行下一个拦截器
+      fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
+    } finally {
+      super.afterInvocation(token, null);
+    }
+  }
+
+  @Override
+  public Class<?> getSecureObjectClass() {
+
+    return FilterInvocation.class;
+  }
+
+  @Override
+  public SecurityMetadataSource obtainSecurityMetadataSource() {
+
+    return this.securityMetadataSource;
+  }
+  
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/utils/AuthenticationUtil.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/utils/AuthenticationUtil.java
new file mode 100644
index 0000000..b2ab8e8
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/utils/AuthenticationUtil.java
@@ -0,0 +1,91 @@
+package com.supwisdom.institute.backend.admin.bff.utils;
+
+import java.util.Collection;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import com.supwisdom.institute.backend.admin.bff.security.core.userdetails.MyUser;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class AuthenticationUtil {
+
+  public static String currentUsername() {
+
+    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+
+    if (authentication == null) {
+      log.error("authentication is null");
+      return null;
+    }
+
+    log.debug("authentication is {}", authentication.getPrincipal());
+
+    if (!authentication.isAuthenticated()) {
+      log.error("authentication is not authenticated");
+      return null;
+    }
+
+    if (authentication.getPrincipal() == null) {
+      log.error("authentication's principal is null");
+      return null;
+    }
+
+    log.debug("authentication's principal is {}", authentication.getPrincipal());
+
+    if (authentication.getPrincipal() instanceof MyUser) {
+      return ((MyUser) authentication.getPrincipal()).getUsername();
+    }
+
+    return null;
+  }
+
+  public static MyUser currentUser() {
+
+    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+
+    if (authentication == null) {
+      log.error("authentication is null");
+      return null;
+    }
+
+    log.debug("authentication is {}", authentication.getPrincipal());
+
+    if (!authentication.isAuthenticated()) {
+      log.error("authentication is not authenticated");
+      return null;
+    }
+
+    if (authentication.getPrincipal() == null) {
+      log.error("authentication's principal is null");
+      return null;
+    }
+
+    log.debug("authentication's principal is {}", authentication.getPrincipal());
+
+    if (authentication.getPrincipal() instanceof MyUser) {
+      return (MyUser) authentication.getPrincipal();
+    }
+
+    return null;
+  }
+
+  public static boolean isAdministrator() {
+    MyUser myUser = AuthenticationUtil.currentUser();
+    if (myUser != null) {
+      Collection<GrantedAuthority> grantedAuthoritys = myUser.getAuthorities();
+      if (grantedAuthoritys != null && grantedAuthoritys.size() > 0) {
+        for (GrantedAuthority grantedAuthority : grantedAuthoritys) {
+          if ("administrator".equals(grantedAuthority.getAuthority())) {
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+}
diff --git a/bff/admin/src/main/resources/application-docker.yml b/bff/admin/src/main/resources/application-docker.yml
new file mode 100644
index 0000000..cc5555e
--- /dev/null
+++ b/bff/admin/src/main/resources/application-docker.yml
@@ -0,0 +1,81 @@
+server:
+  port: ${SERVER_PORT:8443}
+  ssl:
+    enabled: ${SSL_ENABLED:true}
+    clientAuth: NEED
+    key-store: ${SSL_KEYSTORE_FILE:file:/certs/server/server.keystore}
+    key-store-password: ${SSL_KEYSTORE_PASSWORD:}
+    trust-store: ${SSL_TRUSTSTORE_FILE:file:/certs/server/server.truststore}
+    trust-store-password: ${SSL_TRUSTSTORE_PASSWORD:}
+  tomcat: 
+    accesslog: 
+      enabled: ${TOMCAT_ACCESSLOG_ENABLED:false}
+      buffered: ${TOMCAT_ACCESSLOG_BUFFERED:true}
+      directory: ${TOMCAT_ACCESSLOG_DIR:log}
+      prefix: ${TOMCAT_ACCESSLOG_PREFIX:sa-api-accesslog}
+      suffix: ${TOMCAT_ACCESSLOG_SUFFIX:.log}
+      file-date-format: ${TOMCAT_ACCESSLOG_FILE_DATE_FORMAT:.yyyy-MM-dd}
+      rotate: ${TOMCAT_ACCESSLOG_ROTATE:true}
+
+
+##
+# logging
+#
+logging:
+  level:
+    root: INFO
+    com.supwisdom: INFO
+
+
+##
+# infras.online-doc
+#
+infras.online-doc.enabled: ${INFRAS_ONLINE_DOC_ENABLED:false}
+infras.online-doc.md-docs.staitc.path: ${INFRAS_ONLINE_DOC_MD_DOCS_STATIC_PATH:/doc/}
+infras.online-doc.api-docs.staitc.path: ${INFRAS_ONLINE_DOC_API_DOCS_STATIC_PATH:/api-docs/}
+
+
+##
+# infras.security basic
+#
+infras.security.basic.enabled: ${INFRAS_SECURITY_BASIC_ENABLED:true}
+
+
+##
+# infras.security jwt
+#
+infras.security.jwt.enabled: ${INFRAS_SECURITY_JWT_ENABLED:false}
+
+infras.security.jwt.public-key-pem: ${INFRAS_SECURITY_JWT_PUBLIC_KEY_PEM:}
+infras.security.jwt.private-key-pem-pkcs8: ${INFRAS_SECURITY_JWT_PRIVATE_KEY_PEM_PKCS8:}
+
+
+##
+# infras.security cas
+#
+infras.security.cas.enabled: ${INFRAS_SECURITY_CAS_ENABLED:false}
+
+#应用访问地址
+app.server.host.url: ${APP_SERVER_HOST_URL:https://localhost:8443}
+#应用登录地址
+app.login.url: ${APP_LOGIN_URL:/cas/login}
+#应用登出地址
+app.logout.url: ${APP_LOGOUT_URL:/cas/logout}
+
+#CAS服务地址
+cas.server.host.url: ${CAS_SERVER_HOST_URL:https://cas-server/cas}
+
+
+##
+# server url for feign
+#
+sw-backend-api-admin:
+  server:
+    url: ${CASSERVER_SA_API_SERVER_URL:https://sw-backend/sa-api}
+  client-auth:
+    enabled: ${CASSERVER_SA_API_CLIENT_AUTH_ENABLED:true}
+    key-password: ${CASSERVER_SA_API_CLIENT_AUTH_KEY_PASSWORD:}
+    key-store: ${CASSERVER_SA_API_CLIENT_AUTH_KEYSTORE_FILE:file:/certs/common/common.keystore}
+    key-store-password: ${CASSERVER_SA_API_CLIENT_AUTH_KEYSTORE_PASSWORD:}
+    trust-store: ${CASSERVER_SA_API_CLIENT_AUTH_TRUSTSTORE_FILE:file:/certs/common/common.truststore}
+    trust-store-password: ${CASSERVER_SA_API_CLIENT_AUTH_TRUSTSTORE_PASSWORD:}
diff --git a/bff/admin/src/main/resources/application.yml b/bff/admin/src/main/resources/application.yml
new file mode 100644
index 0000000..d93888b
--- /dev/null
+++ b/bff/admin/src/main/resources/application.yml
@@ -0,0 +1,114 @@
+server:
+  port: 8080
+
+
+##
+# logging
+#
+logging:
+  level:
+    root: INFO
+    com.supwisdom: DEBUG
+#    org.springframework.web: INFO
+#    org.springframework.cloud.openfeign: INFO
+
+
+spring:
+  jackson:
+    time-zone: Asia/Shanghai
+
+##
+# spring cloud gateway
+#
+  cloud:
+    gateway:
+      metrics:
+        enabled: true
+      routes:
+      - id: system-api
+        uri: http://localhost:8081
+        predicates:
+        - Path=/api/system/**
+        filters:
+        - RewritePath=/api/system/(?<suffix>.*), /$\{suffix}
+      - id: biz-api
+        uri: http://localhost:8081
+        predicates:
+        - Path=/api/biz/**
+        filters:
+        - RewritePath=/api/biz/(?<suffix>.*), /$\{suffix}
+
+
+feign:
+  client:
+    config:
+      default:
+        #errorDecoder: com.supwisdom.leaveschool.common.config.BaseExceptionErrorDecoder
+        connectTimeout: 12000
+        readTimeout: 12000
+        loggerLevel: full
+  hystrix:
+    enabled: true
+  httpclient:
+    enabled: true
+
+hystrix:
+  command:
+    default:
+      execution:
+        timeout:
+          enabled: true
+        isolation:
+          thread:
+            timeoutInMilliseconds: 12000
+
+
+##
+# infras.online-doc
+#
+infras.online-doc.enabled: false
+infras.online-doc.md-docs.staitc.path: /Users/loie/c/work/git/institute/sw-backend/doc/
+infras.online-doc.api-docs.staitc.path: /Users/loie/c/work/git/institute/sw-backend/api-docs/
+
+
+##
+# infras.security basic
+#
+infras.security.basic.enabled: true
+
+
+##
+# infras.security jwt
+#
+infras.security.jwt.enabled: false
+
+#infras.security.jwt.public-key-pem: |-
+#  -----BEGIN PUBLIC KEY-----
+#  MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBQw6TmvJ+nOuRaLoHsZJGIBzRg/wbskNv6UevL3/nQioYooptPfdIHVzPiKRVT5+DW5+nqzav3DOxY+HYKjO9nFjYdj0sgvRae6iVpa5Ji1wbDKOvwIDNukgnKbqvFXX2Isfl0RxeN3uEKdjeFGGFdr38I3ADCNKFNxtbmfqvjQIDAQAB
+#  -----END PUBLIC KEY-----
+#infras.security.jwt.private-key-pem-pkcs8: |-
+#  -----BEGIN PRIVATE KEY-----
+#  MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMFDDpOa8n6c65FougexkkYgHNGD/BuyQ2/pR68vf+dCKhiiim0990gdXM+IpFVPn4Nbn6erNq/cM7Fj4dgqM72cWNh2PSyC9Fp7qJWlrkmLXBsMo6/AgM26SCcpuq8VdfYix+XRHF43e4Qp2N4UYYV2vfwjcAMI0oU3G1uZ+q+NAgMBAAECgYA7jA7UuhxXmMAYmJ0hO7xnMQPQJouqeP3AYK9+sfMF7WQNHR/r0vj7Vli/dUm1I4hxr+x8fAuomf+ve6gds7sm+v2JHLzEIyPPiogoC7IcBmjJ3yVzW/26cXeOmTiPC/fW2g4BpYxSM8HLDaSkrtqzy8e9ijlzMpHBvvwLikufnQJBAOXaqIPuZ7Vm/JwQHAmX2HV+Qk6GMi/H7mL8X0AaW68w+Iccdbz1hzmMBfdn5NMmx2AOwoBAVivgjt0a1OfksHMCQQDXPtXxwFy4dQ4TbPu8L38P8s/bPo9ib1YkEMp57yBw+IvxB7jnpA9rUYTfZM/HpVP7r9rfVEUylVXXzhz1qx//AkEApWJOTBdW8bQ3YEdLFS/3pJqDNSLjq3OMuBZkpqgQfh6bRAQbRynW8XYpuNk9URye6iPUmRkxp4J86ORseqoWtwJAJb5a/b1hhObhxP5DVkht23oUgLmDoxsq28AmASOxaJ3szCMyhUv7eDIfPp0K4lNXWrcHhkncqHYPS3xVD68mOQJAV4SRDdWpgAbQOUODotohE48RxrabHo0l228CJ/pnm0q7gplPs4iSNJ2eijFuOMXfKkq3z/vxiNSA59FcdoCOHQ==
+#  -----END PRIVATE KEY-----
+
+
+##
+# infras.security cas
+#
+infras.security.cas.enabled: false
+
+#应用访问地址
+app.server.host.url: http://localhost:8080
+#应用登录地址
+app.login.url: /cas/login
+#应用登出地址
+app.logout.url: /cas/logout
+
+#CAS服务地址
+cas.server.host.url: https://cas.supwisdom.com/cas
+
+
+##
+# server url for feign
+#
+sw-backend-api-admin.server.url: http://localhost:8081
diff --git a/bff/admin/src/main/resources/bootstrap.yml b/bff/admin/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..2df1be7
--- /dev/null
+++ b/bff/admin/src/main/resources/bootstrap.yml
@@ -0,0 +1,3 @@
+spring:
+  application:
+    name: sw-backend-admin-bff
diff --git a/bff/pom.xml b/bff/pom.xml
new file mode 100644
index 0000000..8685014
--- /dev/null
+++ b/bff/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+  
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-bff-aggregator</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <name>Supwisdom Backend Framework Backend for Frontend Aggregator</name>
+  <description>Supwisdom Backend Framework Backend for Frontend Aggregator project</description>
+
+  <modules>
+    <module>admin</module>
+  </modules>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/biz/api/pom.xml b/biz/api/pom.xml
new file mode 100644
index 0000000..3832ac9
--- /dev/null
+++ b/biz/api/pom.xml
@@ -0,0 +1,111 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-biz-api</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework BIZ API</name>
+  <description>Supwisdom Backend Framework BIZ API project</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-utils</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-framework</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-biz-domain</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-mvc</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/v1/admin/AdminHelloController.java b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/v1/admin/AdminHelloController.java
new file mode 100644
index 0000000..a46c806
--- /dev/null
+++ b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/v1/admin/AdminHelloController.java
@@ -0,0 +1,26 @@
+package com.supwisdom.institute.backend.biz.api.v1.admin;
+
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.supwisdom.institute.backend.common.core.transmit.user.User;
+import com.supwisdom.institute.backend.common.core.transmit.user.UserContext;
+
+@Api(value = "BizAdminHello", tags = { "BizAdminHello" }, description = "示例接口")
+@Slf4j
+@RestController
+@RequestMapping("/v1/admin/hello")
+public class AdminHelloController {
+  
+  @RequestMapping(method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  public User biz() {
+    User user = UserContext.getUser(); log.debug("{}", user);
+    return user;
+  }
+
+}
diff --git a/biz/domain/pom.xml b/biz/domain/pom.xml
new file mode 100644
index 0000000..3f8f044
--- /dev/null
+++ b/biz/domain/pom.xml
@@ -0,0 +1,102 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-biz-domain</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework BIZ Domain</name>
+  <description>Supwisdom Backend Framework BIZ Domain project</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-framework</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-data-jpa</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/biz/pom.xml b/biz/pom.xml
new file mode 100644
index 0000000..52f8e2f
--- /dev/null
+++ b/biz/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+  
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-biz-aggregator</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <name>Supwisdom Backend Framework BIZ Aggregator</name>
+  <description>Supwisdom Backend Framework BIZ Aggregator project</description>
+
+  <modules>
+    <module>domain</module>
+    <module>api</module>
+  </modules>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/common/core/pom.xml b/common/core/pom.xml
new file mode 100644
index 0000000..d535132
--- /dev/null
+++ b/common/core/pom.xml
@@ -0,0 +1,74 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-common-core</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework Common Core</name>
+  <description>Supwisdom Backend Framework Common Core project</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.cloud</groupId>
+      <artifactId>spring-cloud-starter-openfeign</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.alibaba</groupId>
+      <artifactId>fastjson</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/annotation/EnableSimpleUserTransmit.java b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/annotation/EnableSimpleUserTransmit.java
new file mode 100644
index 0000000..5a094e9
--- /dev/null
+++ b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/annotation/EnableSimpleUserTransmit.java
@@ -0,0 +1,19 @@
+package com.supwisdom.institute.backend.common.core.transmit.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.context.annotation.Import;
+
+import com.supwisdom.institute.backend.common.core.transmit.config.SimpleUserTransmitAutoConfiguration;
+
+@Documented
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Import({SimpleUserTransmitAutoConfiguration.class})
+public @interface EnableSimpleUserTransmit {
+
+}
diff --git a/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/config/SimpleUserTransmitAutoConfiguration.java b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/config/SimpleUserTransmitAutoConfiguration.java
new file mode 100644
index 0000000..a3e11ce
--- /dev/null
+++ b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/config/SimpleUserTransmitAutoConfiguration.java
@@ -0,0 +1,27 @@
+package com.supwisdom.institute.backend.common.core.transmit.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.supwisdom.institute.backend.common.core.transmit.feign.SimpleUserTransmitRequestInterceptor;
+import com.supwisdom.institute.backend.common.core.transmit.filter.SimpleUserTransmitFilter;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Configuration
+public class SimpleUserTransmitAutoConfiguration {
+  
+  @Bean
+  public SimpleUserTransmitRequestInterceptor simpleUserTransmitRequestInterceptor() {
+    log.debug("-----SimpleUserTransmitRequestInterceptor");
+    return new SimpleUserTransmitRequestInterceptor();
+  }
+
+  @Bean
+  public SimpleUserTransmitFilter simpleUserTransmitFilter() {
+    log.debug("-----SimpleUserTransmitFilter");
+    return new SimpleUserTransmitFilter();
+  }
+  
+}
diff --git a/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/feign/SimpleUserTransmitRequestInterceptor.java b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/feign/SimpleUserTransmitRequestInterceptor.java
new file mode 100644
index 0000000..be002db
--- /dev/null
+++ b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/feign/SimpleUserTransmitRequestInterceptor.java
@@ -0,0 +1,31 @@
+package com.supwisdom.institute.backend.common.core.transmit.feign;
+
+import java.net.URLDecoder;
+
+import lombok.extern.slf4j.Slf4j;
+
+import com.alibaba.fastjson.JSONObject;
+import com.supwisdom.institute.backend.common.core.transmit.user.User;
+import com.supwisdom.institute.backend.common.core.transmit.user.UserContext;
+
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+
+@Slf4j
+public class SimpleUserTransmitRequestInterceptor implements RequestInterceptor {
+
+  @Override
+  public void apply(RequestTemplate template) {
+    User user = UserContext.getUser();
+    if (user != null) {
+      try {
+        String jsonUser = JSONObject.toJSONString(user);
+        String headerValue = new String(URLDecoder.decode(jsonUser,"UTF-8"));
+        template.header(UserContext.KEY_USER_IN_HTTP_HEADER, headerValue);
+      } catch (Exception e) {
+        log.warn("User set error", e);
+      }
+    }
+  }
+
+}
diff --git a/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/filter/SimpleUserTransmitFilter.java b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/filter/SimpleUserTransmitFilter.java
new file mode 100644
index 0000000..4d8a2dc
--- /dev/null
+++ b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/filter/SimpleUserTransmitFilter.java
@@ -0,0 +1,55 @@
+package com.supwisdom.institute.backend.common.core.transmit.filter;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.supwisdom.institute.backend.common.core.transmit.user.User;
+import com.supwisdom.institute.backend.common.core.transmit.user.UserContext;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class SimpleUserTransmitFilter implements Filter {
+
+  @Override
+  public void init(FilterConfig filterConfig) throws ServletException {
+    
+  }
+
+  @Override
+  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+    HttpServletRequest request = (HttpServletRequest) servletRequest;
+    
+    String headerValue = request.getHeader(UserContext.KEY_USER_IN_HTTP_HEADER);
+    if (StringUtils.isNotBlank(headerValue)) {
+      try {
+        String jsonUser = URLDecoder.decode(headerValue,"UTF-8");
+        
+        User user = JSONObject.parseObject(jsonUser, User.class);
+        
+        UserContext.setUser(user);
+      } catch (Exception e) {
+        log.warn("User get error", e);
+      }
+    }
+    
+    filterChain.doFilter(servletRequest, servletResponse);
+  }
+
+  @Override
+  public void destroy() {
+    
+  }
+
+}
diff --git a/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/user/User.java b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/user/User.java
new file mode 100644
index 0000000..3d34bc4
--- /dev/null
+++ b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/user/User.java
@@ -0,0 +1,17 @@
+package com.supwisdom.institute.backend.common.core.transmit.user;
+
+import java.util.List;
+import java.util.Map;
+
+import lombok.Value;
+
+@Value
+public class User {
+  
+  private String username;
+  
+  private List<String> roles;
+  
+  private Map<String, Object> attributes;
+
+}
diff --git a/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/user/UserContext.java b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/user/UserContext.java
new file mode 100644
index 0000000..00f2e43
--- /dev/null
+++ b/common/core/src/main/java/com/supwisdom/institute/backend/common/core/transmit/user/UserContext.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.common.core.transmit.user;
+
+public class UserContext {
+  
+  private static ThreadLocal<User> user = new ThreadLocal<User>();
+  
+  public static String KEY_USER_IN_HTTP_HEADER = "X-FORWARD-USER";
+  
+  private UserContext() {
+    
+  }
+  
+  public static User getUser() {
+    return user.get();
+  }
+  
+  public static void setUser(User value) {
+    user.set(value);
+  }
+
+}
diff --git a/common/framework/pom.xml b/common/framework/pom.xml
new file mode 100644
index 0000000..328b83c
--- /dev/null
+++ b/common/framework/pom.xml
@@ -0,0 +1,80 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-common-framework</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework Common Framework</name>
+  <description>Supwisdom Backend Framework Common Framework project</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-utils</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-data-jpa</artifactId>
+      <optional>true</optional>
+    </dependency>
+
+
+    <dependency>
+      <groupId>io.springfox</groupId>
+      <artifactId>springfox-swagger2</artifactId>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/entity/ABaseEntity.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/entity/ABaseEntity.java
new file mode 100644
index 0000000..3c14c25
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/entity/ABaseEntity.java
@@ -0,0 +1,79 @@
+package com.supwisdom.institute.backend.common.framework.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@MappedSuperclass
+public abstract class ABaseEntity implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 2613136930230449335L;
+
+  @Id
+  @Column(name = "ID")
+  private String id;
+
+  /**
+   * 获取主键
+   */
+  public String getId() {
+    return id;
+  }
+
+  /**
+   * 设置ID属性,主要用于人工指定键值
+   */
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  @Getter
+  @Setter
+  @Column(name = "COMPANY_ID", nullable = true)
+  private String companyId = null;
+
+  @Getter
+  @Setter
+  @Column(name = "DELETED")
+  private Boolean deleted = false;
+
+  @Getter
+  @Setter
+  @Column(name = "ADD_ACCOUNT", nullable = true)
+  private String addAccount = null;
+
+  @Getter
+  @Setter
+  @Column(name = "ADD_TIME", nullable = true)
+  private Date addTime = null;
+
+  @Getter
+  @Setter
+  @Column(name = "EDIT_ACCOUNT", nullable = true)
+  private String editAccount = null;
+
+  @Getter
+  @Setter
+  @Column(name = "EDIT_TIME", nullable = true)
+  private Date editTime = null;
+
+  @Getter
+  @Setter
+  @Column(name = "DELETE_ACCOUNT", nullable = true)
+  private String deleteAccount = null;
+
+  @Getter
+  @Setter
+  @Column(name = "DELETE_TIME", nullable = true)
+  private Date deleteTime = null;
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/entity/EntityUtils.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/entity/EntityUtils.java
new file mode 100644
index 0000000..662b24a
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/entity/EntityUtils.java
@@ -0,0 +1,199 @@
+package com.supwisdom.institute.backend.common.framework.entity;
+
+import java.lang.reflect.Field;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+
+import com.supwisdom.institute.backend.common.util.ReflectUtils;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 对 entity 的操作 如:复制、合并、转换等
+ * 
+ * @author loie
+ *
+ */
+public class EntityUtils {
+
+  /**
+   * 合并 domain 中带有{@link Column}注解的字段值, 将 newEntity 中值为null的字段,使用 oldEntity 中的值
+   * 进行覆盖
+   * 
+   * @param oldEntity
+   *          ,覆盖的实体
+   * @param newEntity
+   *          ,待覆盖的实体
+   * @return 合并后的newEntity
+   */
+  public static <T> T merge(T oldEntity, T newEntity) {
+
+    for (Class<?> clazz = oldEntity.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
+      for (Field field : clazz.getDeclaredFields()) {
+        Column[] annotations = field.getAnnotationsByType(Column.class);
+        if (annotations == null || annotations.length == 0) {
+          Id[] idAnnotations = field.getAnnotationsByType(Id.class);
+          if (idAnnotations == null || idAnnotations.length == 0) {
+            continue;
+          }
+        }
+
+        String fieldName = field.getName();
+        Object newFieldValue = ReflectUtils.getFieldValue(newEntity, fieldName);
+
+        if (newFieldValue == null) {
+          Object oldFieldValue = ReflectUtils.getFieldValue(oldEntity, fieldName);
+          ReflectUtils.setFieldValue(newEntity, fieldName, oldFieldValue,field.getType());
+        }
+      }
+    }
+
+    return newEntity;
+  }
+
+  public static <S, T> T copy(S sourceEntity, T targetEntity) {
+    
+    for (Class<?> clazz = targetEntity.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
+      for (Field field : clazz.getDeclaredFields()) {
+        Column[] annotations = field.getAnnotationsByType(Column.class);
+        if (annotations == null || annotations.length == 0) {
+          Id[] idAnnotations = field.getAnnotationsByType(Id.class);
+          if (idAnnotations == null || idAnnotations.length == 0) {
+            continue;
+          }
+        }
+
+        String fieldName = field.getName();
+        Object sFieldValue = ReflectUtils.getFieldValue(sourceEntity, fieldName);
+
+        if (sFieldValue != null) {
+          ReflectUtils.setFieldValue(targetEntity, fieldName, sFieldValue,field.getType());
+        }
+      }
+    }
+
+    return targetEntity;
+  }
+
+  public static <S, T> T fatherToChild (S father, T child){
+    for (Class<?> clazz = child.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
+      for (Field field : clazz.getDeclaredFields()) {
+        String fieldName = field.getName();
+        if(fieldName.equals("serialVersionUID")){continue;}
+        Object sFieldValue = ReflectUtils.getFieldValue(father, fieldName);
+
+        if (sFieldValue != null) {
+          ReflectUtils.setFieldValue(child, fieldName, sFieldValue,field.getType());
+        }
+      }
+    }
+
+    return child;
+  }
+
+    public static void main(String[] args) {
+
+    Test target0 = new Test();
+    target0.setId("id0");
+    target0.setCode("code");
+    target0.setName("name");
+    target0.setDate(new Date());
+    target0.setEnabled(false);
+    target0.setStatus(1);
+
+    System.out.println("target0 == " + target0.toString());
+    System.out.println();
+
+    Test source1 = new Test();
+    // source1.setId("id1");
+    source1.setCode("code1");
+    // source1.setName("name");
+    // source1.setDate(new Date());
+    source1.setEnabled(true);
+    // source1.setStatus(1);
+    System.out.println("source1 == " + source1.toString());
+
+    Test target1 = EntityUtils.merge(source1, target0);
+    System.out.println("target0 == " + target0.toString());
+    System.out.println("target1 == " + target1.toString());
+    System.out.println();
+
+    Test source2 = new Test();
+    // source2.setId("id2");
+    source2.setCode("code2");
+    source2.setName("name2");
+    // source2.setDate(new Date());
+    // source2.setEnabled(true);
+    source2.setStatus(2);
+    System.out.println("source2 == " + source2.toString());
+
+    Test target2 = EntityUtils.merge(source2, target0);
+    System.out.println("target0 == " + target0.toString());
+    System.out.println("target2 == " + target2.toString());
+    System.out.println();
+
+
+    Test test = new Test();
+    test.setId("id0");
+    test.setCode("code");
+    test.setName("name");
+    test.setDate(new Date());
+    test.setEnabled(false);
+    test.setStatus(1);
+
+    Test2 test2 = new Test2();
+    test2 = EntityUtils.copy(test, test2);
+    System.out.println("test    == " + test.toString());
+    System.out.println("test2   == " + test2.toString());
+    System.out.println();
+
+  }
+  
+  @Getter
+  @Setter
+  @ToString
+  public static class Test extends ABaseEntity {
+    
+    /**
+     * 
+     */
+    private static final long serialVersionUID = -8348781653151879484L;
+    
+    @Column
+    private String code = null;
+    @Column
+    private String name = null;
+    @Column
+    private Date date = null;
+    @Column
+    private Boolean enabled = null;
+    @Column
+    private Integer status = null;
+    
+  }
+  
+  public static class Test2 extends ABaseEntity {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = -5565959639168005384L;
+    
+    @Column
+    private String name = null;
+    @Column
+    private String memo = null;
+    @Column
+    private Date date = null;
+    @Column
+    private Boolean enabled = null;
+    @Column
+    private Integer status = null;
+
+  }
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/BaseException.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/BaseException.java
new file mode 100644
index 0000000..ee21f7a
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/BaseException.java
@@ -0,0 +1,66 @@
+package com.supwisdom.institute.backend.common.framework.exception;
+
+public class BaseException extends RuntimeException {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 2278568118369300446L;
+
+  /**
+   * 异常信息
+   */
+  protected String msg;
+
+  /**
+   * 具体异常码
+   */
+  protected int code = -1;
+
+  public BaseException(int code, String msgFormat, Object... args) {
+      super(String.format(msgFormat, args));
+      this.code = code;
+      this.msg = String.format(msgFormat, args);
+  }
+
+  public BaseException() {
+      super();
+  }
+
+  public BaseException(String message, Throwable cause) {
+      super(message, cause);
+  }
+
+  public BaseException(Throwable cause) {
+      super(cause);
+  }
+
+  public BaseException(String message) {
+      super(message);
+  }
+
+  public String getMsg() {
+      return msg;
+  }
+
+  public int getCode() {
+      return code;
+  }
+
+  /**
+   * 实例化异常
+   * 
+   * @param msgFormat
+   * @param args
+   * @return
+   */
+  @Deprecated
+  public BaseException newInstance(String msgFormat, Object... args) {
+      return new BaseException(this.code, msgFormat, args);
+  }
+  
+  public BaseException newInstance(int code, String msgFormat, Object... args) {
+    return new BaseException(code, msgFormat, args);
+  }
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/modal/ABaseModal.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/modal/ABaseModal.java
new file mode 100644
index 0000000..3b8d6d3
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/modal/ABaseModal.java
@@ -0,0 +1,10 @@
+package com.supwisdom.institute.backend.common.framework.modal;
+
+public abstract class ABaseModal implements IModal {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8717041105592152819L;
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/modal/IModal.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/modal/IModal.java
new file mode 100644
index 0000000..cb6f72b
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/modal/IModal.java
@@ -0,0 +1,7 @@
+package com.supwisdom.institute.backend.common.framework.modal;
+
+import java.io.Serializable;
+
+public interface IModal extends Serializable {
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/rabbitmq/constants/ExchangeNames.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/rabbitmq/constants/ExchangeNames.java
new file mode 100644
index 0000000..1266710
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/rabbitmq/constants/ExchangeNames.java
@@ -0,0 +1,13 @@
+package com.supwisdom.institute.backend.common.framework.rabbitmq.constants;
+
+public class ExchangeNames {
+
+  public static final String EXCHANGE_NAME_FANOUT = "fanout-exchange";
+
+  public static final String EXCHANGE_NAME_DIRECT = "direct-exchange";
+
+  public static final String EXCHANGE_NAME_TOPIC = "topic-exchange";
+
+  public static final String EXCHANGE_NAME_HEADERS = "headers-exchange";
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/rabbitmq/constants/QueueNames.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/rabbitmq/constants/QueueNames.java
new file mode 100644
index 0000000..e2ed900
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/rabbitmq/constants/QueueNames.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.common.framework.rabbitmq.constants;
+
+public class QueueNames {
+
+  /**
+   * 授权添加事件
+   */
+  public static final String QUEUE_NAME_GRANTED_ADDED = "granted-added";
+
+  /**
+   * 授权移除事件
+   */
+  public static final String QUEUE_NAME_GRANTED_REMOVED = "granted-removed";
+
+  
+  /**
+   * 授权操作日志记录事件
+   */
+  public static final String QUEUE_NAME_GRANT_OPERATE_LOGGING = "granted-operate-logging";
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/rabbitmq/constants/RoutingKeys.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/rabbitmq/constants/RoutingKeys.java
new file mode 100644
index 0000000..dad0e02
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/rabbitmq/constants/RoutingKeys.java
@@ -0,0 +1,20 @@
+package com.supwisdom.institute.backend.common.framework.rabbitmq.constants;
+
+public class RoutingKeys {
+
+  /**
+   * 授权添加事件
+   */
+  public static final String ROUTING_KEY_GRANTED_ADDED = "granted.added";
+
+  /**
+   * 授权移除事件
+   */
+  public static final String ROUTING_KEY_GRANTED_REMOVED = "granted.removed";
+
+  
+  /**
+   * 授权操作日志记录事件
+   */
+  public static final String ROUTING_KEY_GRANT_OPERATE_LOGGING = "grant.operate.logging";
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/ABaseJpaRepositoryImpl.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/ABaseJpaRepositoryImpl.java
new file mode 100644
index 0000000..32e0e33
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/ABaseJpaRepositoryImpl.java
@@ -0,0 +1,92 @@
+package com.supwisdom.institute.backend.common.framework.repo;
+
+import java.util.Calendar;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.persistence.EntityManager;
+import javax.transaction.Transactional;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.jpa.repository.support.JpaEntityInformation;
+import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
+import org.springframework.data.repository.NoRepositoryBean;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Transactional
+@NoRepositoryBean
+public class ABaseJpaRepositoryImpl<E extends ABaseEntity> extends SimpleJpaRepository<E, String> implements BaseJpaRepository<E> {
+
+  @SuppressWarnings("unused")
+  private final EntityManager em;
+
+  public ABaseJpaRepositoryImpl(Class<E> domainClass, EntityManager em) {
+    super(domainClass, em);
+    this.em = em;
+  }
+
+  public ABaseJpaRepositoryImpl(JpaEntityInformation<E, String> information, EntityManager em) {
+    super(information, em);
+    this.em = em;
+  }
+  
+  public Page<E> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<E> page = this.findAll(pageRequest);
+
+    return page;
+  }
+
+  public E selectById(String id) {
+
+    try {
+      Optional<E> entity = this.findById(id);
+
+      if (entity.isPresent()) {
+        return entity.get();
+      }
+    } catch (RuntimeException e) {
+      System.out.println("RuntimeException:" + e.getMessage());
+    } catch (Exception e) {
+      System.out.println("Exception:" + e.getMessage());
+    }
+
+    return null;
+  }
+
+  public E insert(E entity) {
+
+    if (entity.getCompanyId() == null || entity.getCompanyId().isEmpty()) {
+      entity.setCompanyId("1");
+    }
+
+    if (entity.getDeleted() == null) {
+      entity.setDeleted(false);
+    }
+    //entity.setAddAccount(AuthUtil.getRemoteUser()); // FIXME: setAddAccount
+    if (entity.getAddTime() == null) {
+      entity.setAddTime(Calendar.getInstance().getTime());
+    }
+
+    E e = this.save(entity);
+
+    return e;
+  }
+
+  public E update(E entity) {
+
+    //entity.setEditAccount(AuthUtil.getRemoteUser()); // FIXME: setEditAccount
+    if (entity.getEditTime() == null) {
+      entity.setEditTime(Calendar.getInstance().getTime());
+    }
+    
+    E e = this.save(entity);
+
+    return e;
+  }
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/BaseJpaRepository.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/BaseJpaRepository.java
new file mode 100644
index 0000000..3451705
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/BaseJpaRepository.java
@@ -0,0 +1,123 @@
+package com.supwisdom.institute.backend.common.framework.repo;
+
+import java.util.Calendar;
+import java.util.Map;
+import java.util.Optional;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.NoRepositoryBean;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+import com.supwisdom.institute.backend.common.util.UUIDUtils;
+
+@NoRepositoryBean
+public interface BaseJpaRepository<E extends ABaseEntity> extends JpaRepository<E, String>, JpaSpecificationExecutor<E> {
+  
+
+  /**
+   * 生成主键值。 默认使用方法
+   * 如果需要生成主键,需要由子类重写此方法根据需要的方式生成主键值。 
+   * @param entity 要持久化的对象 
+   */
+  public default String generateId() {
+    return UUIDUtils.create();
+  }
+
+  public default Page<E> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<E> page = this.findAll(pageRequest);
+
+    return page;
+  }
+  
+  public default E selectById(String id) {
+
+    try {
+      Optional<E> entity = this.findById(id);
+
+      if (entity.isPresent()) {
+        return entity.get();
+      }
+    } catch (RuntimeException e) {
+      System.out.println("RuntimeException:" + e.getMessage());
+    } catch (Exception e) {
+      System.out.println("Exception:" + e.getMessage());
+    }
+
+    return null;
+  }
+  
+  public default E insert(E entity) {
+    
+    if (entity.getId() == null || entity.getId().isEmpty()) {
+      entity.setId(generateId());
+    }
+
+    if (entity.getCompanyId() == null || entity.getCompanyId().isEmpty()) {
+      entity.setCompanyId("1");
+    }
+
+    if (entity.getDeleted() == null) {
+      entity.setDeleted(false);
+    }
+    if (entity.getAddAccount() == null) {
+      //entity.setAddAccount(AuthUtil.getRemoteUser()); // FIXME: setAddAccount
+    }
+    if (entity.getAddTime() == null) {
+      entity.setAddTime(Calendar.getInstance().getTime());
+    }
+    
+    E e = this.save(entity);
+
+    return e;
+  }
+  
+  public default E update(E entity) {
+
+    if (entity.getEditAccount() == null) {
+      //entity.setEditAccount(AuthUtil.getRemoteUser()); // FIXME: setEditAccount
+    }
+    if (entity.getEditTime() == null) {
+      entity.setEditTime(Calendar.getInstance().getTime());
+    }
+    
+    E e = this.save(entity);
+
+    return e;
+  }
+  
+  
+  public default E remove(E entity) {
+    
+    if (entity.getDeleted() == null) {
+      entity.setDeleted(true);
+    }
+    if (entity.getDeleteAccount() == null) {
+      //entity.setDeleteAccount(AuthUtil.getRemoteUser()); // FIXME: setDeleteAccount
+    }
+    if (entity.getDeleteTime() == null) {
+      entity.setDeleteTime(Calendar.getInstance().getTime());
+    }
+    
+    E e = this.save(entity);
+    
+    return e;
+  }
+  
+  
+  public default void delete(String id) {
+    
+    this.deleteById(id);
+  }
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/resultTransformer/IgnoreCaseResultTransformer.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/resultTransformer/IgnoreCaseResultTransformer.java
new file mode 100644
index 0000000..ee622bc
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/resultTransformer/IgnoreCaseResultTransformer.java
@@ -0,0 +1,72 @@
+package com.supwisdom.institute.backend.common.framework.repo.resultTransformer;
+
+import com.google.common.collect.Lists;
+import com.supwisdom.institute.backend.common.util.ReflectUtils;
+
+import org.hibernate.HibernateException;
+import org.hibernate.transform.ResultTransformer;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+/**
+ * 
+ * 修正hibernate返回自定义pojo类型时找不到属性的BUG
+ * 主要发生在使用oracle或高版本的mysql时,查询返回的字段默认是大写的(除非SQL中指定了别名),这导致返回自定义pojo类型时会报找不到属性的错误,该类用于修正此BUG。
+ * 使用该类时SQL返回的字段名大小写或者带"_"都会被忽略,如数据库字段为 USER_NAME,自定义pojo的属性名为username就可以使用
+ * 
+ * @author feng*/
+public class IgnoreCaseResultTransformer implements ResultTransformer {
+        private static final long serialVersionUID = -3779317531110592988L;
+        private final Class<?> resultClass;
+        private Field[] fields;
+        private List<Class> types = Lists.newArrayList();
+        public IgnoreCaseResultTransformer(final Class<?> resultClass) {
+            this.resultClass = resultClass;
+            List<Field> list = Lists.newArrayList();
+            for (Class<?> superClass = resultClass; superClass != Object.class; superClass = superClass.getSuperclass()) {
+                Field[] fs = superClass.getDeclaredFields();
+                List<Field> newFs = Lists.newArrayList();
+                for(int i=0;i<fs.length;i++){
+                    if(fs[i].getName().equals("serialVersionUID")){
+                        continue;
+                    }
+                    types.add(fs[i].getType());
+                    ReflectUtils.makeAccessible(fs[i]);
+                    newFs.add(fs[i]);
+                }
+                list.addAll(newFs);
+            }
+            this.fields = list.toArray(new Field[list.size()]);
+        }
+         /**
+      * aliases为每条记录的数据库字段名,ORACLE字段名默认为大写
+      * tupe为与aliases对应的字段的值
+      */
+         @Override
+         public Object transformTuple(final Object[] tuple, final String[] aliases) {
+           Object result;
+             try {
+                result = this.resultClass.newInstance();
+                    for (int i = 0; i < aliases.length; i++) {
+                        for (int j=0;j<this.fields.length;j++) {
+                          String fieldName = this.fields[j].getName();
+                           //数据库字段带下划线的时候也能保证使用,如数据库字段为 USER_NAME,自定义pojo的属性名为username就可以使用
+                           if (fieldName.equalsIgnoreCase(aliases[i].replaceAll("_", ""))) {
+                               ReflectUtils.invokeSetter(result,fieldName,tuple[i],this.types.get(j));
+//                               beanUtilsBean.setProperty(result, fieldName, tuple[i]);
+                               break;
+                                   }
+                          }
+                  }
+           } catch (Exception e) {
+               throw new HibernateException("Could not instantiate resultclass: " + this.resultClass.getName(), e);
+           }
+          return result;
+      }
+      @Override
+      @SuppressWarnings("rawtypes")
+      public List transformList(final List collection) {
+           return collection;
+      }
+}
\ No newline at end of file
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/service/ABaseService.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/service/ABaseService.java
new file mode 100644
index 0000000..dccfc17
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/service/ABaseService.java
@@ -0,0 +1,42 @@
+package com.supwisdom.institute.backend.common.framework.service;
+
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+
+public abstract class ABaseService<E extends ABaseEntity, REPO extends BaseJpaRepository<E>> {
+  
+  public abstract REPO getRepo();
+  
+  public Page<E> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    
+    return getRepo().selectPageList(loadAll, pageIndex, pageSize, mapBean, orderBy);
+  }
+  
+  public E selectById(String id) {
+    
+    return getRepo().selectById(id);
+  }
+  
+  public E insert(E entity) {
+    
+    return getRepo().insert(entity);
+  }
+  
+  public E update(E entity) {
+    
+    E ret = getRepo().update(entity);
+    getRepo().flush();
+    
+    return ret;
+  }
+  
+  public void deleteById(String id) {
+    
+    getRepo().deleteById(id);
+  }
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiCreateRequest.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiCreateRequest.java
new file mode 100644
index 0000000..f118c4d
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiCreateRequest.java
@@ -0,0 +1,5 @@
+package com.supwisdom.institute.backend.common.framework.vo.request;
+
+public interface IApiCreateRequest extends IApiRequest {
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiLoadRequest.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiLoadRequest.java
new file mode 100644
index 0000000..3cf62c4
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiLoadRequest.java
@@ -0,0 +1,9 @@
+package com.supwisdom.institute.backend.common.framework.vo.request;
+
+public interface IApiLoadRequest extends IApiRequest {
+  
+  String getId();
+
+  void setId(String id);
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiQueryRequest.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiQueryRequest.java
new file mode 100644
index 0000000..da3b638
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiQueryRequest.java
@@ -0,0 +1,27 @@
+package com.supwisdom.institute.backend.common.framework.vo.request;
+
+import java.util.Map;
+
+public interface IApiQueryRequest extends IApiRequest {
+
+  boolean isLoadAll();
+  
+  void setLoadAll(boolean loadAll);
+
+  int getPageIndex();
+  
+  void setPageIndex(int pageIndex);
+
+  int getPageSize();
+  
+  void setPageSize(int pageSize);
+  
+  Map<String, Object> getMapBean();
+  
+  void setMapBean(Map<String, Object> mapBean);
+
+  Map<String, String> getOrderBy();
+  
+  void setOrderBy(Map<String, String> orderBy);
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiRemoveRequest.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiRemoveRequest.java
new file mode 100644
index 0000000..bda1e59
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiRemoveRequest.java
@@ -0,0 +1,10 @@
+package com.supwisdom.institute.backend.common.framework.vo.request;
+
+public interface IApiRemoveRequest extends IApiRequest {
+
+  String getId();
+
+
+  void setId(String id);
+  
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiRequest.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiRequest.java
new file mode 100644
index 0000000..71a4abd
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiRequest.java
@@ -0,0 +1,7 @@
+package com.supwisdom.institute.backend.common.framework.vo.request;
+
+import java.io.Serializable;
+
+public interface IApiRequest extends Serializable {
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiUpdateRequest.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiUpdateRequest.java
new file mode 100644
index 0000000..9c491c4
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/request/IApiUpdateRequest.java
@@ -0,0 +1,9 @@
+package com.supwisdom.institute.backend.common.framework.vo.request;
+
+public interface IApiUpdateRequest extends IApiRequest {
+
+  String getId();
+
+  void setId(String id);
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/AbstractApiResponse.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/AbstractApiResponse.java
new file mode 100644
index 0000000..8e979e3
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/AbstractApiResponse.java
@@ -0,0 +1,37 @@
+package com.supwisdom.institute.backend.common.framework.vo.response;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiResponseData;
+
+public abstract class AbstractApiResponse<T extends IApiResponseData> implements IApiResponse<T> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 846108786006850165L;
+  
+  @JsonIgnore
+  @Deprecated
+  protected boolean acknowleged = true;
+
+  @Override
+  @JsonIgnore
+  @Deprecated
+  public boolean isAcknowleged() {
+    return acknowleged;
+  }
+  
+  protected int code = 0;
+  protected String message = null;
+  
+  @Override
+  public int getCode() {
+    return code;
+  }
+  
+  @Override
+  public String getMessage() {
+    return message;
+  }
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/DefaultApiResponse.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/DefaultApiResponse.java
new file mode 100644
index 0000000..72ac7e2
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/DefaultApiResponse.java
@@ -0,0 +1,59 @@
+package com.supwisdom.institute.backend.common.framework.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiResponseData;
+
+public class DefaultApiResponse<T extends IApiResponseData> extends AbstractApiResponse<T> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 4380576799912565681L;
+
+  protected T data;
+
+  @Override
+  public T getData() {
+    return data;
+  }
+
+//  public void setData(T data) {
+//    this.data = data;
+//  }
+//
+//  public DefaultApiResponse() {
+//
+//  }
+
+  public DefaultApiResponse(T data) {
+    this(0, null, data);
+  }
+
+  @Deprecated
+  public DefaultApiResponse(boolean acknowleged, T data) {
+    super.acknowleged = acknowleged;
+    if (super.acknowleged == false) {
+      super.code = -1;
+      super.message = "未知错误";
+    }
+    
+    this.data = data;
+  }
+  
+  public DefaultApiResponse(int code, String message, T data) {
+    super.code = code;
+    super.message = message;
+    
+    if (code != 0) {
+      super.acknowleged = false;
+    }
+    
+    this.data = data;
+  }
+
+  public static <T extends IApiResponseData> DefaultApiResponse<T> build(T data) {
+    DefaultApiResponse<T> defaultApiResponse = new DefaultApiResponse<T>(data);
+
+    return defaultApiResponse;
+  }
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/IApiResponse.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/IApiResponse.java
new file mode 100644
index 0000000..487183a
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/IApiResponse.java
@@ -0,0 +1,20 @@
+package com.supwisdom.institute.backend.common.framework.vo.response;
+
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiResponseData;
+
+public interface IApiResponse<T extends IApiResponseData> extends Serializable {
+  
+  @JsonIgnore
+  @Deprecated
+  boolean isAcknowleged();
+  
+  int getCode();
+  
+  String getMessage();
+  
+  T getData();
+  
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiCreateResponseData.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiCreateResponseData.java
new file mode 100644
index 0000000..05ab9d2
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiCreateResponseData.java
@@ -0,0 +1,7 @@
+package com.supwisdom.institute.backend.common.framework.vo.response.data;
+
+public interface IApiCreateResponseData extends IApiResponseData {
+
+  String getId();
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiLoadResponseData.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiLoadResponseData.java
new file mode 100644
index 0000000..8741959
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiLoadResponseData.java
@@ -0,0 +1,7 @@
+package com.supwisdom.institute.backend.common.framework.vo.response.data;
+
+public interface IApiLoadResponseData extends IApiResponseData {
+
+  String getId();
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiQueryResponseData.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiQueryResponseData.java
new file mode 100644
index 0000000..4e78c10
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiQueryResponseData.java
@@ -0,0 +1,58 @@
+package com.supwisdom.institute.backend.common.framework.vo.response.data;
+
+import java.util.List;
+import java.util.Map;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+public interface IApiQueryResponseData<E extends ABaseEntity> extends IApiResponseData {
+  
+  /**
+   * 当前页码
+   * @return
+   */
+  int getPageIndex();
+  
+  /**
+   * 每页记录数
+   * @return
+   */
+  int getPageSize();
+  
+  /**
+   * 查询条件
+   * @return
+   */
+  Map<String, Object> getMapBean();
+  
+  /**
+   * 排序字段
+   * @return
+   */
+  Map<String, String> getOrderBy();
+  
+  /**
+   * 总页数
+   * @return
+   */
+  int getPageCount();
+  
+  /**
+   * 总记录数
+   * @return
+   */
+  long getRecordCount();
+  
+  /**
+   * 返回记录数
+   * @return
+   */
+  int getCurrentItemCount();
+  
+  /**
+   * 返回记录
+   * @return
+   */
+  List<E> getItems();
+  
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiRemoveResponseData.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiRemoveResponseData.java
new file mode 100644
index 0000000..820c62d
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiRemoveResponseData.java
@@ -0,0 +1,7 @@
+package com.supwisdom.institute.backend.common.framework.vo.response.data;
+
+public interface IApiRemoveResponseData extends IApiResponseData {
+
+  String getId();
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiResponseData.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiResponseData.java
new file mode 100644
index 0000000..56b9163
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiResponseData.java
@@ -0,0 +1,7 @@
+package com.supwisdom.institute.backend.common.framework.vo.response.data;
+
+import java.io.Serializable;
+
+public interface IApiResponseData extends Serializable {
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiUpdateResponseData.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiUpdateResponseData.java
new file mode 100644
index 0000000..211c437
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/vo/response/data/IApiUpdateResponseData.java
@@ -0,0 +1,7 @@
+package com.supwisdom.institute.backend.common.framework.vo.response.data;
+
+public interface IApiUpdateResponseData extends IApiResponseData {
+
+  String getId();
+
+}
diff --git a/common/pom.xml b/common/pom.xml
new file mode 100644
index 0000000..22eb667
--- /dev/null
+++ b/common/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+  
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-common</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <name>Supwisdom Backend Framework Common</name>
+  <description>Supwisdom Backend Framework Common project</description>
+
+  <modules>
+    <module>core</module>
+    <module>utils</module>
+    <module>framework</module>
+  </modules>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/common/utils/pom.xml b/common/utils/pom.xml
new file mode 100644
index 0000000..36fec72
--- /dev/null
+++ b/common/utils/pom.xml
@@ -0,0 +1,68 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-common-utils</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework Common Utils</name>
+  <description>Supwisdom Backend Framework Common Utils project</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/DateUtil.java b/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/DateUtil.java
new file mode 100644
index 0000000..0f08910
--- /dev/null
+++ b/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/DateUtil.java
@@ -0,0 +1,45 @@
+package com.supwisdom.institute.backend.common.util;
+
+import java.text.ParseException;
+import java.util.Date;
+
+import org.apache.commons.lang3.time.DateFormatUtils;
+import org.apache.commons.lang3.time.DateUtils;
+
+public class DateUtil {
+  
+  public static void main(String[] args) {
+    Date d0 = DateUtil.parseDate("2019-07-23 00:00:00", "yyyy-MM-dd HH:mm:ss");
+
+    Date d1 = DateUtil.parseDate("2019-07-23 23:59:59", "yyyy-MM-dd HH:mm:ss");
+
+    System.out.println(d0);
+    System.out.println(d1);
+    
+    String s0 = DateUtil.formatDate(DateUtil.now(), "yyyyMMddHHmmss");
+    System.out.println(s0);
+  }
+  
+  public static Date parseDate(String source, String pattern) {
+    
+    try {
+      Date d = DateUtils.parseDate(source, pattern);
+      
+      return d;
+    } catch (ParseException e) {
+      e.printStackTrace();
+    }
+    
+    return null;
+  }
+
+  public static Date now() {
+    return new Date();
+  }
+  
+  
+  public static String formatDate(Date date, String pattern) {
+    return DateFormatUtils.format(date, pattern);
+  }
+
+}
diff --git a/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/MapBeanUtils.java b/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/MapBeanUtils.java
new file mode 100644
index 0000000..0a5f50f
--- /dev/null
+++ b/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/MapBeanUtils.java
@@ -0,0 +1,226 @@
+package com.supwisdom.institute.backend.common.util;
+
+import com.google.common.collect.Lists;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Map;
+
+public class MapBeanUtils {
+
+  /**
+   * 判断 mapBean 中的 key 是否存在;若存在,则判断是否有值
+   * 
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static boolean containsValue(Map<String, Object> mapBean, String key) {
+
+    if (!mapBean.containsKey(key)) {
+      return false;
+    }
+
+    if (mapBean.get(key) == null) {
+      return false;
+    }
+
+    if (String.valueOf(mapBean.get(key)).isEmpty()) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 null
+   * 
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static String getString(Map<String, Object> mapBean, String key) {
+
+    return getString(mapBean, key, null);
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 defaultValue
+   * 
+   * @param mapBean
+   * @param key
+   * @param defaultValue
+   * @return
+   */
+  public static String getString(Map<String, Object> mapBean, String key, String defaultValue) {
+
+    if (containsValue(mapBean, key)) {
+      return String.valueOf(mapBean.get(key));
+    }
+
+    return defaultValue;
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 false
+   * 
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static Boolean getBoolean(Map<String, Object> mapBean, String key) {
+
+    return getBoolean(mapBean, key, null);
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 defaultValue
+   * 
+   * @param mapBean
+   * @param key
+   * @param defaultValue
+   * @return
+   */
+  public static Boolean getBoolean(Map<String, Object> mapBean, String key, Boolean defaultValue) {
+
+    if (containsValue(mapBean, key)) {
+      Boolean b = Boolean.valueOf(String.valueOf(mapBean.get(key)));
+      return b == null ? defaultValue : b;
+    }
+
+    return defaultValue;
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 -1
+   * 
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static Integer getInteger(Map<String, Object> mapBean, String key) {
+
+    return getInteger(mapBean, key, null);
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 defaultValue
+   * 
+   * @param mapBean
+   * @param key
+   * @param defaultValue
+   * @return
+   */
+  public static Integer getInteger(Map<String, Object> mapBean, String key, Integer defaultValue) {
+
+    if (containsValue(mapBean, key)) {
+      Integer i = Integer.valueOf(String.valueOf(mapBean.get(key)));
+      return i == null ? defaultValue : i;
+    }
+
+    return defaultValue;
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 -1L
+   * 
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static Long getLong(Map<String, Object> mapBean, String key) {
+
+    return getLong(mapBean, key, null);
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 defaultValue
+   * 
+   * @param mapBean
+   * @param key
+   * @param defaultValue
+   * @return
+   */
+  public static Long getLong(Map<String, Object> mapBean, String key, Long defaultValue) {
+
+    if (containsValue(mapBean, key)) {
+      Long l = Long.valueOf(String.valueOf(mapBean.get(key)));
+      return l == null ? defaultValue : l;
+    }
+
+    return defaultValue;
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 -1L
+   *
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static List getList(Map<String, Object> mapBean, String key) {
+
+    return getList(mapBean, key, Lists.newArrayList());
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 defaultValue
+   *
+   * @param mapBean
+   * @param key
+   * @param defaultValue
+   * @return
+   */
+  public static List getList(Map<String, Object> mapBean, String key, List defaultValue) {
+
+    if (containsValue(mapBean, key)) {
+      List l = (List)mapBean.get(key);
+      return l == null ? defaultValue : l;
+    }
+
+    return defaultValue;
+  }
+
+  /**
+   * 将一个 Map 对象转化为一个 JavaBean
+   * @param obj 要转化的对象
+   * @param map 包含属性值的 map
+   * @return 转化出来的 JavaBean 对象
+   * @throws IntrospectionException
+   *             如果分析类属性失败
+   * @throws IllegalAccessException
+   *             如果实例化 JavaBean 失败
+   * @throws InstantiationException
+   *             如果实例化 JavaBean 失败
+   * @throws InvocationTargetException
+   *             如果调用属性的 setter 方法失败
+   */
+  public static Object convert2Bean(Object obj, Map map)
+          throws IntrospectionException, IllegalAccessException,
+          InstantiationException, InvocationTargetException {
+    BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass()); // 获取类属性
+
+    // 给 JavaBean 对象的属性赋值
+    PropertyDescriptor[] propertyDescriptors =  beanInfo.getPropertyDescriptors();
+    for (int i = 0; i< propertyDescriptors.length; i++) {
+      PropertyDescriptor descriptor = propertyDescriptors[i];
+      String propertyName = descriptor.getName();
+
+      if (map.containsKey(propertyName)) {
+        // 下面一句可以 try 起来,这样当一个属性赋值失败的时候就不会影响其他属性赋值。
+        Object value = map.get(propertyName);
+
+        Object[] args = new Object[1];
+        args[0] = value;
+
+        descriptor.getWriteMethod().invoke(obj, args);
+      }
+    }
+    return obj;
+  }
+
+}
diff --git a/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/ReflectUtils.java b/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/ReflectUtils.java
new file mode 100644
index 0000000..1b9313e
--- /dev/null
+++ b/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/ReflectUtils.java
@@ -0,0 +1,386 @@
+package com.supwisdom.institute.backend.common.util;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.springframework.util.Assert;
+
+import java.lang.reflect.*;
+import java.util.Date;
+
+/**
+ * 利用反射进行操作的一个工具类
+ *
+ * @author fengpy
+ */
+@SuppressWarnings("rawtypes")
+@Slf4j
+public class ReflectUtils {
+
+  private static final String SETTER_PREFIX = "set";
+
+  private static final String GETTER_PREFIX = "get";
+
+  private static final String CGLIB_CLASS_SEPARATOR = "$$";
+
+  /**
+   * 利用反射获取指定对象里面的指定属性
+   *
+   * @param obj
+   *          目标对象
+   * @param fieldName
+   *          目标属性
+   * @return 目标字段
+   */
+  private static Field getField(Object obj, String fieldName) {
+    Field field = null;
+    for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
+      try {
+        field = clazz.getDeclaredField(fieldName);
+        break;
+      } catch (NoSuchFieldException e) {
+        // 这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。
+      }
+    }
+    return field;
+  }
+
+  /**
+   * 调用Getter方法.
+   * 支持多级,如:对象名.对象名.方法
+   */
+  public static Object invokeGetter(Object obj, String propertyName) {
+    Object object = obj;
+    for (String name : StringUtils.split(propertyName, ".")){
+      String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
+      object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
+    }
+    return object;
+  }
+
+  /**
+   * 调用Setter方法, 仅匹配方法名。
+   * 支持多级,如:对象名.对象名.方法
+   */
+  public static void invokeSetter(Object obj, String propertyName, Object value, Class valueCla) throws IllegalAccessException, InstantiationException {
+    Object object = obj;
+    String[] names = StringUtils.split(propertyName, ".");
+    for (int i=0; i<names.length; i++){
+      if(i<names.length-1){
+        String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
+        object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
+      }else{
+        String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
+        value = doSpecial(value,valueCla);
+        invokeMethodByName(object, setterMethodName, new Object[] { value });
+      }
+    }
+  }
+
+  /**
+   * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
+   */
+  public static Object getFieldValue(final Object obj, final String fieldName) {
+    Field field = getAccessibleField(obj, fieldName);
+
+    if (field == null) {
+      throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
+    }
+
+    Object result = null;
+    try {
+      result = field.get(obj);
+    } catch (IllegalAccessException e) {
+      log.error("不可能抛出的异常{}", e.getMessage());
+    }
+    return result;
+  }
+
+  /**
+   * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
+   */
+  public static void setFieldValue(final Object obj, final String fieldName, final Object value, Class valueCla) {
+    Field field = getAccessibleField(obj, fieldName);
+
+    if (field == null) {
+      throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
+    }
+
+    try {
+      doSpecial(value,valueCla);
+      field.set(obj, value);
+    } catch (IllegalAccessException e) {
+      log.error("不可能抛出的异常:{}", e.getMessage());
+    }
+  }
+
+  /**
+   * 直接调用对象方法, 无视private/protected修饰符.
+   * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
+   * 同时匹配方法名+参数类型,
+   */
+  public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
+                                    final Object[] args) {
+    Method method = getAccessibleMethod(obj, methodName, parameterTypes);
+    if (method == null) {
+      throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
+    }
+
+    try {
+      return method.invoke(obj, args);
+    } catch (Exception e) {
+      throw convertReflectionExceptionToUnchecked(e);
+    }
+  }
+
+  /**
+   * 直接调用对象方法, 无视private/protected修饰符,
+   * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
+   * 只匹配函数名,如果有多个同名函数调用第一个。
+   */
+  public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
+    Method method = getAccessibleMethodByName(obj, methodName);
+    if (method == null) {
+      throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
+    }
+
+    try {
+      return method.invoke(obj, args);
+    } catch (Exception e) {
+      throw convertReflectionExceptionToUnchecked(e);
+    }
+  }
+
+  /**
+   * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
+   *
+   * 如向上转型到Object仍无法找到, 返回null.
+   */
+  public static Field getAccessibleField(final Object obj, final String fieldName) {
+    Validate.notNull(obj, "object can't be null");
+    Validate.notBlank(fieldName, "fieldName can't be blank");
+    for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
+      try {
+        Field field = superClass.getDeclaredField(fieldName);
+        makeAccessible(field);
+        return field;
+      } catch (NoSuchFieldException e) {//NOSONAR
+        // Field不在当前类定义,继续向上转型
+        continue;// new add
+      }
+    }
+    return null;
+  }
+
+  /**
+   * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+   * 如向上转型到Object仍无法找到, 返回null.
+   * 匹配函数名+参数类型。
+   *
+   * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+   */
+  public static Method getAccessibleMethod(final Object obj, final String methodName,
+                                           final Class<?>... parameterTypes) {
+    Validate.notNull(obj, "object can't be null");
+    Validate.notBlank(methodName, "methodName can't be blank");
+
+    for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
+      try {
+        Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
+        makeAccessible(method);
+        return method;
+      } catch (NoSuchMethodException e) {
+        // Method不在当前类定义,继续向上转型
+        continue;// new add
+      }
+    }
+    return null;
+  }
+
+  /**
+   * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+   * 如向上转型到Object仍无法找到, 返回null.
+   * 只匹配函数名。
+   *
+   * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+   */
+  public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
+    Validate.notNull(obj, "object can't be null");
+    Validate.notBlank(methodName, "methodName can't be blank");
+
+    for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
+      Method[] methods = searchType.getDeclaredMethods();
+      for (Method method : methods) {
+        if (method.getName().equals(methodName)) {
+          makeAccessible(method);
+          return method;
+        }
+      }
+    }
+    return null;
+  }
+
+  /**
+   * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
+   */
+  public static void makeAccessible(Method method) {
+    if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
+            && !method.isAccessible()) {
+      method.setAccessible(true);
+    }
+  }
+
+  /**
+   * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
+   */
+  public static void makeAccessible(Field field) {
+    if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
+            .isFinal(field.getModifiers())) && !field.isAccessible()) {
+      field.setAccessible(true);
+    }
+  }
+
+  /**
+   * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
+   * 如无法找到, 返回Object.class.
+   * eg.
+   * public UserDao extends HibernateDao<User>
+   *
+   * @param clazz The class to introspect
+   * @return the first generic declaration, or Object.class if cannot be determined
+   */
+  @SuppressWarnings("unchecked")
+  public static <T> Class<T> getClassGenricType(final Class clazz) {
+    return getClassGenricType(clazz, 0);
+  }
+
+  /**
+   * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
+   * 如无法找到, 返回Object.class.
+   *
+   * 如public UserDao extends HibernateDao<User,Long>
+   *
+   * @param clazz clazz The class to introspect
+   * @param index the Index of the generic ddeclaration,start from 0.
+   * @return the index generic declaration, or Object.class if cannot be determined
+   */
+  public static Class getClassGenricType(final Class clazz, final int index) {
+
+    Type genType = clazz.getGenericSuperclass();
+
+    if (!(genType instanceof ParameterizedType)) {
+      log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
+      return Object.class;
+    }
+
+    Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
+
+    if (index >= params.length || index < 0) {
+      log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+              + params.length);
+      return Object.class;
+    }
+    if (!(params[index] instanceof Class)) {
+      log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
+      return Object.class;
+    }
+
+    return (Class) params[index];
+  }
+
+  public static Class<?> getUserClass(Object instance) {
+    Assert.notNull(instance, "Instance must not be null");
+    Class clazz = instance.getClass();
+    if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
+      Class<?> superClass = clazz.getSuperclass();
+      if (superClass != null && !Object.class.equals(superClass)) {
+        return superClass;
+      }
+    }
+    return clazz;
+
+  }
+
+  /**
+   * 将反射时的checked exception转换为unchecked exception.
+   */
+  public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
+    if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
+            || e instanceof NoSuchMethodException) {
+      return new IllegalArgumentException(e);
+    } else if (e instanceof InvocationTargetException) {
+      return new RuntimeException(((InvocationTargetException) e).getTargetException());
+    } else if (e instanceof RuntimeException) {
+      return (RuntimeException) e;
+    }
+    return new RuntimeException("Unexpected Checked Exception.", e);
+  }
+
+  /**
+   * 类型转换
+   *
+   * @param clazz
+   *          :目标类型
+   * @param source
+   *          :待转换对象
+   * @return :目标对象
+   */
+  public static Object typeConversion(Class<?> clazz, String source) {
+
+    if (clazz == null) {
+      throw new IllegalArgumentException("clazz should not be null");
+    }
+
+    Object targetObj = null;
+    String nameType = clazz.getName();
+
+    if ("java.lang.Integer".equals(nameType) || "int".equals(nameType)) {
+      targetObj = Integer.valueOf(source);
+    } else if ("java.lang.String".equals(nameType) || "string".equals(nameType)) {
+      targetObj = source;
+    } else if ("java.lang.Float".equals(nameType) || "float".equals(nameType)) {
+      targetObj = Float.valueOf(source);
+    } else if ("java.lang.Double".equals(nameType) || "double".equals(nameType)) {
+      targetObj = Double.valueOf(source);
+    } else if ("java.lang.Boolean".equals(nameType) || "boolean".equals(nameType)) {
+      targetObj = Boolean.valueOf(source);
+    } else if ("java.lang.Long".equals(nameType) || "long".equals(nameType)) {
+      targetObj = Long.valueOf(source);
+    } else if ("java.lang.Short".equals(nameType) || "short".equals(nameType)) {
+      targetObj = Short.valueOf(source);
+    } else if ("java.lang.Character".equals(nameType) || "char".equals(nameType)) {
+      targetObj = source.charAt(1);
+    }else if ("java.util.Date".equals(nameType)) {
+      targetObj = new Date(source);
+    }
+
+    return targetObj;
+  }
+
+
+  /**
+   * 根据类的全路径获取class
+   * @param fullPath
+   *          :类的全路径
+   * @return :class
+   */
+  public static Class fullPath2Class(String fullPath) {
+    Class cl = null;
+    try {
+      ClassLoader loader = ClassLoader.getSystemClassLoader();
+      cl = loader.loadClass(fullPath);
+    } catch (ClassNotFoundException e) {
+      e.printStackTrace();
+    }
+    return cl;
+  }
+
+    private static Object doSpecial(Object value, Class valueCla){
+        //TODO 针对sql脚本的类型和实体entity的类型不一致做的特殊处理(有待优化)
+        if(valueCla.equals(Boolean.class)&&value.getClass().equals(Integer.class)){
+            value = typeConversion(Boolean.class,value.toString());
+        }
+        return value;
+    }
+}
diff --git a/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/UUIDUtils.java b/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/UUIDUtils.java
new file mode 100644
index 0000000..d348d91
--- /dev/null
+++ b/common/utils/src/main/java/com/supwisdom/institute/backend/common/util/UUIDUtils.java
@@ -0,0 +1,87 @@
+package com.supwisdom.institute.backend.common.util;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class UUIDUtils {
+
+  private static boolean IS_THREADLOCALRANDOM_AVAILABLE = false;
+  private static Random random;
+  private static final long leastSigBits;
+  private static final ReentrantLock lock = new ReentrantLock();
+  private static long lastTime;
+
+  static {
+    try {
+      IS_THREADLOCALRANDOM_AVAILABLE = null != UUIDUtils.class.getClassLoader().loadClass(
+          "java.util.concurrent.ThreadLocalRandom");
+    } catch (ClassNotFoundException e) {
+    }
+
+    byte[] seed = new SecureRandom().generateSeed(8);
+    leastSigBits = new BigInteger(seed).longValue();
+    if (!IS_THREADLOCALRANDOM_AVAILABLE) {
+      random = new Random(leastSigBits);
+    }
+  }
+
+  private UUIDUtils() {}
+
+  /**
+   * 生成32位随机码
+   * @return
+   */
+  public static String random() {
+    byte[] randomBytes = new byte[16];
+    if (IS_THREADLOCALRANDOM_AVAILABLE) {
+      java.util.concurrent.ThreadLocalRandom.current().nextBytes(randomBytes);
+    } else {
+      random.nextBytes(randomBytes);
+    }
+
+    long mostSigBits = 0;
+    for (int i = 0; i < 8; i++) {
+      mostSigBits = (mostSigBits << 8) | (randomBytes[i] & 0xff);
+    }
+    long leastSigBits = 0;
+    for (int i = 8; i < 16; i++) {
+      leastSigBits = (leastSigBits << 8) | (randomBytes[i] & 0xff);
+    }
+
+    return new UUID(mostSigBits, leastSigBits).toString().replaceAll("-", "");
+  }
+
+  /**
+   * 生成32位随机码
+   * @return
+   */
+  public static String create() {
+    long timeMillis = (System.currentTimeMillis() * 10000) + 0x01B21DD213814000L;
+
+    lock.lock();
+    try {
+      if (timeMillis > lastTime) {
+        lastTime = timeMillis;
+      } else {
+        timeMillis = ++lastTime;
+      }
+    } finally {
+      lock.unlock();
+    }
+
+    long mostSigBits = timeMillis << 32;
+    mostSigBits |= (timeMillis & 0xFFFF00000000L) >> 16;
+    mostSigBits |= 0x1000 | ((timeMillis >> 48) & 0x0FFF); 
+    return new UUID(mostSigBits, leastSigBits).toString().replaceAll("-", "");
+    
+  }
+  
+  public static void main(String[] args){
+    System.out.println(random());
+    System.out.println(create());
+  }
+
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..af472b8
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.buildcommons</groupId>
+    <artifactId>spring-cloud-parent</artifactId>
+    <version>Finchley.RELEASE-1.1</version>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-parent</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <name>Supwisdom Backend Framework Parent</name>
+  <description>Supwisdom Backend Framework Parent project</description>
+
+  <modules>
+    <module>common</module>
+    
+    <module>system</module>
+    <module>biz</module>
+
+    <module>sa</module>
+    <module>bff</module>
+    
+  </modules>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <java.version>1.8</java.version>
+
+    <argLine>-Dfile.encoding=UTF-8</argLine>
+
+    <downloadSources>true</downloadSources>
+    <downloadJavadocs>true</downloadJavadocs>
+
+    <maven.compiler.source>${java.version}</maven.compiler.source>
+    <maven.compiler.target>${java.version}</maven.compiler.target>
+
+    <dockerfile-maven-plugin.version>1.4.8</dockerfile-maven-plugin.version>
+    <dockerfile.image.server>harbor.supwisdom.com</dockerfile.image.server>
+    <dockerfile.image.prefix>sw-backend</dockerfile.image.prefix>
+
+    <infras.version>0.1.0-SNAPSHOT</infras.version>
+
+    <io.springfox.version>2.9.2</io.springfox.version>
+
+    <mybatis.spring.boot.version>1.3.1</mybatis.spring.boot.version>
+
+  </properties>
+
+  <distributionManagement>
+    <repository>
+      <id>supwisdom-releases</id>
+      <name>internal release</name>
+      <url>https://app.supwisdom.com/nexus/content/repositories/releases</url>
+    </repository>
+    <snapshotRepository>
+      <id>supwisdom-snapshots</id>
+      <name>internal snapshots</name>
+      <url>https://app.supwisdom.com/nexus/content/repositories/snapshots</url>
+    </snapshotRepository>
+  </distributionManagement>
+
+  <repositories>
+    <repository>
+      <snapshots>
+        <enabled>true</enabled>
+      </snapshots>
+      <id>supwisdom</id>
+      <url>https://app.supwisdom.com/nexus/content/groups/public/</url>
+    </repository>
+    <repository>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+      <id>central</id>
+      <url>http://repo.maven.apache.org/maven2</url>
+    </repository>
+  </repositories>
+
+  <dependencyManagement>
+    <dependencies>
+
+      <dependency>
+        <groupId>com.supwisdom.infras</groupId>
+        <artifactId>infras-bom</artifactId>
+        <version>${infras.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+
+
+      <dependency>
+        <groupId>com.supwisdom.institute</groupId>
+        <artifactId>sw-backend-common-core</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>com.supwisdom.institute</groupId>
+        <artifactId>sw-backend-common-utils</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>com.supwisdom.institute</groupId>
+        <artifactId>sw-backend-common-framework</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>com.supwisdom.institute</groupId>
+        <artifactId>sw-backend-system-domain</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>com.supwisdom.institute</groupId>
+        <artifactId>sw-backend-system-api</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>com.supwisdom.institute</groupId>
+        <artifactId>sw-backend-biz-domain</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>com.supwisdom.institute</groupId>
+        <artifactId>sw-backend-biz-api</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+
+      <dependency>
+        <groupId>mysql</groupId>
+        <artifactId>mysql-connector-java</artifactId>
+        <version>8.0.12</version>
+      </dependency>
+
+      <dependency>
+        <groupId>com.alibaba</groupId>
+        <artifactId>fastjson</artifactId>
+        <version>1.2.56</version>
+      </dependency>
+
+
+      <dependency>
+        <groupId>com.google.guava</groupId>
+        <artifactId>guava</artifactId>
+        <version>28.0-jre</version>
+      </dependency>
+
+      <dependency>
+        <groupId>io.springfox</groupId>
+        <artifactId>springfox-swagger2</artifactId>
+        <version>${io.springfox.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>io.springfox</groupId>
+        <artifactId>springfox-swagger-ui</artifactId>
+        <version>${io.springfox.version}</version>
+      </dependency>
+
+    </dependencies>
+  </dependencyManagement>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>com.spotify</groupId>
+          <artifactId>dockerfile-maven-plugin</artifactId>
+          <version>${dockerfile-maven-plugin.version}</version>
+          <configuration>
+            <repository>${dockerfile.image.server}/${dockerfile.image.prefix}/${project.artifactId}</repository>
+            <tag>${project.version}</tag>
+            <useMavenSettingsForAuth>true</useMavenSettingsForAuth>
+            <buildArgs>
+              <JAR_FILE>${project.build.finalName}.${project.packaging}</JAR_FILE>
+              <VERSION>${project.version}</VERSION>
+              <NAME>${project.artifactId}</NAME>
+            </buildArgs>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+
+    <plugins>
+      <plugin>
+        <groupId>com.spotify</groupId>
+        <artifactId>dockerfile-maven-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+
+  </build>
+
+</project>
diff --git a/sa/admin/Dockerfile b/sa/admin/Dockerfile
new file mode 100644
index 0000000..4dc87c6
--- /dev/null
+++ b/sa/admin/Dockerfile
@@ -0,0 +1,21 @@
+FROM harbor.supwisdom.com/institute/openjdk:8-jre-alpine
+
+ENV ENABLE_JMX_SSL=false
+ENV JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=docker
+ENV SPRING_PROFILES_ACTIVE=docker
+
+ARG NAME
+ARG VERSION
+ARG JAR_FILE
+
+LABEL name=$NAME \
+      version=$VERSION
+
+EXPOSE 8080
+
+EXPOSE 8443
+
+COPY --chown=java-app:java-app target/${JAR_FILE} /home/java-app/lib/app.jar
+
+COPY --chown=java-app:java-app target/doc /home/java-app/doc
+COPY --chown=java-app:java-app target/api-docs /home/java-app/api-docs
diff --git a/sa/admin/pom.xml b/sa/admin/pom.xml
new file mode 100644
index 0000000..09c386c
--- /dev/null
+++ b/sa/admin/pom.xml
@@ -0,0 +1,201 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-admin-sa</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework Admin Super Admin</name>
+  <description>Supwisdom Backend Framework Admin Super Admin project</description>
+
+  <properties>
+    <start-class>com.supwisdom.institute.backend.admin.sa.Application</start-class>
+  </properties>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+
+    <!-- 微服务 健康监控 -->
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-actuator</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-online-doc</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-mvc</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-object-mapper</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-i18n</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-lang</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-system-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-biz-api</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>io.springfox</groupId>
+      <artifactId>springfox-swagger2</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.springfox</groupId>
+      <artifactId>springfox-swagger-ui</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>mysql</groupId>
+      <artifactId>mysql-connector-java</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+
+    <!-- 热部署,无需重启项目 -->
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-devtools</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <finalName>${project.artifactId}</finalName>
+
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+
+
+      <!-- <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.4.3</version>
+        <configuration>
+          <encoding>${project.build.sourceEncoding}</encoding>
+        </configuration>
+        <executions>
+          <execution>
+            <id>copy-doc-resources</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <encoding>utf-8</encoding>
+              <outputDirectory>${basedir}/target/doc</outputDirectory>
+              <overwrite>true</overwrite>
+              <resources>
+                <resource>
+                  <directory>${basedir}/../doc</directory>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+          <execution>
+            <id>copy-api-docs-resources</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <encoding>utf-8</encoding>
+              <outputDirectory>${basedir}/target/api-docs</outputDirectory>
+              <overwrite>true</overwrite>
+              <resources>
+                <resource>
+                  <directory>${basedir}/../api-docs</directory>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin> -->
+
+
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
+      </plugin>
+
+      <plugin>
+        <groupId>com.spotify</groupId>
+        <artifactId>dockerfile-maven-plugin</artifactId>
+        <configuration>
+          <skip>false</skip>
+        </configuration>
+      </plugin>
+
+    </plugins>
+
+  </build>
+
+</project>
diff --git a/sa/admin/src/main/java/com/supwisdom/institute/backend/admin/sa/Application.java b/sa/admin/src/main/java/com/supwisdom/institute/backend/admin/sa/Application.java
new file mode 100644
index 0000000..252e9bf
--- /dev/null
+++ b/sa/admin/src/main/java/com/supwisdom/institute/backend/admin/sa/Application.java
@@ -0,0 +1,45 @@
+package com.supwisdom.institute.backend.admin.sa;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+import com.supwisdom.infras.online.doc.configuration.EnableInfrasOnlineDoc;
+import com.supwisdom.institute.backend.common.core.transmit.annotation.EnableSimpleUserTransmit;
+
+@SpringBootApplication
+
+@EnableSimpleUserTransmit
+
+@EnableInfrasOnlineDoc
+
+@EntityScan(basePackages = {"com.supwisdom.**.domain.entity"})  // 扫描子项目下的实体
+@EnableJpaRepositories(basePackages = {"com.supwisdom.**.domain.repo"})  // 扫描子项目下的持久类
+@ComponentScan(basePackages = {"com.supwisdom"})
+public class Application {
+
+  public static void main(String[] args) {
+    SpringApplication.run(Application.class, args);
+  }
+  
+  @Bean
+  public CorsFilter corsFilter() {
+    final CorsConfiguration config = new CorsConfiguration();
+    // config.setAllowCredentials(true);
+    config.addAllowedOrigin("*");
+    config.addAllowedHeader("*");
+    config.addAllowedMethod("*");
+
+    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+    source.registerCorsConfiguration("/v2/api-docs", config);
+
+    return new CorsFilter(source);
+  }
+
+}
diff --git a/sa/admin/src/main/java/com/supwisdom/institute/backend/admin/sa/configuration/Swagger2Config.java b/sa/admin/src/main/java/com/supwisdom/institute/backend/admin/sa/configuration/Swagger2Config.java
new file mode 100644
index 0000000..1eb942e
--- /dev/null
+++ b/sa/admin/src/main/java/com/supwisdom/institute/backend/admin/sa/configuration/Swagger2Config.java
@@ -0,0 +1,63 @@
+package com.supwisdom.institute.backend.admin.sa.configuration;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger.web.UiConfiguration;
+import springfox.documentation.swagger.web.UiConfigurationBuilder;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableSwagger2
+public class Swagger2Config {
+
+  @Value("${swagger2.apis.basePackage:com.supwisdom.institute}")
+  private String basePackage;
+
+  @Bean
+  public Docket createRestApi() {
+    return new Docket(DocumentationType.SWAGGER_2)
+        .apiInfo(apiInfo())
+        .select()
+        .apis(RequestHandlerSelectors.basePackage(basePackage))
+        .paths(PathSelectors.any())
+        .build()
+        ;
+  }
+
+  private ApiInfo apiInfo() {
+    Contact contact = new Contact("Backend Admin Super Admin", "https://sw-backend-sa.supwisdom.com/swagger-ui.html", ""); // name, url, email
+    return new ApiInfoBuilder()
+        .title("Backend Admin Super Admin APIs")
+        .description("管理后台 - 服务接口")
+        .termsOfServiceUrl("http://www.supwisdom.com/")
+        .contact(contact)
+        .version("1.0")
+        .build();
+  }
+
+  @Bean
+  UiConfiguration uiConfig() {
+    
+    return UiConfigurationBuilder.builder().build();
+    
+//    return new UiConfiguration(null, // url
+//        "none", // docExpansion => none | list
+//        "alpha", // apiSorter => alpha
+//        "schema", // defaultModelRendering => schema
+//        UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS,
+//        false, // enableJsonEditor => true || false
+//        true, // showRequestHeaders => true | false
+//        60000L); // requestTimeout => in milliseconds, defaults to null
+//    // (uses jquery xh timeout)
+  }
+
+}
diff --git a/sa/admin/src/main/resources/application-docker.yml b/sa/admin/src/main/resources/application-docker.yml
new file mode 100644
index 0000000..ba6bbce
--- /dev/null
+++ b/sa/admin/src/main/resources/application-docker.yml
@@ -0,0 +1,46 @@
+server:
+  port: ${SERVER_PORT:8443}
+  ssl:
+    enabled: ${SSL_ENABLED:true}
+    clientAuth: NEED
+    key-store: ${SSL_KEYSTORE_FILE:file:/certs/server/server.keystore}
+    key-store-password: ${SSL_KEYSTORE_PASSWORD:}
+    trust-store: ${SSL_TRUSTSTORE_FILE:file:/certs/server/server.truststore}
+    trust-store-password: ${SSL_TRUSTSTORE_PASSWORD:}
+  tomcat: 
+    accesslog: 
+      enabled: ${TOMCAT_ACCESSLOG_ENABLED:false}
+      buffered: ${TOMCAT_ACCESSLOG_BUFFERED:true}
+      directory: ${TOMCAT_ACCESSLOG_DIR:log}
+      prefix: ${TOMCAT_ACCESSLOG_PREFIX:sa-api-accesslog}
+      suffix: ${TOMCAT_ACCESSLOG_SUFFIX:.log}
+      file-date-format: ${TOMCAT_ACCESSLOG_FILE_DATE_FORMAT:.yyyy-MM-dd}
+      rotate: ${TOMCAT_ACCESSLOG_ROTATE:true}
+
+
+##
+# logging
+#
+logging:
+  level:
+    root: INFO
+    com.supwisdom: INFO
+
+
+spring:
+  jackson:
+    time-zone: ${JACKSON_TIME_ZONE:Asia/Shanghai}
+
+  datasource:
+    driver-class-name: ${JDBC_DRIVER_CLASS_NAME:com.mysql.cj.jdbc.Driver}
+    url: ${JDBC_URL:jdbc:mysql://mysql-server:3306/user_authorization_service}
+    username: ${JDBC_USERNAME:user_authorization_service}
+    password: ${JDBC_PASSWORD:}
+
+
+##
+# online-doc
+#
+infras.online-doc.enabled: ${INFRAS_ONLINE_DOC_ENABLED:false}
+infras.online-doc.md-docs.staitc.path: ${INFRAS_ONLINE_DOC_MD_DOCS_STATIC_PATH:/doc/}
+infras.online-doc.api-docs.staitc.path: ${INFRAS_ONLINE_DOC_API_DOCS_STATIC_PATH:/api-docs/}
diff --git a/sa/admin/src/main/resources/application.yml b/sa/admin/src/main/resources/application.yml
new file mode 100644
index 0000000..571cbd7
--- /dev/null
+++ b/sa/admin/src/main/resources/application.yml
@@ -0,0 +1,48 @@
+server:
+  port: 8081
+  ssl:
+    enabled: false
+
+
+##
+# logging
+#
+logging:
+  level:
+    root: INFO
+    com.supwisdom: DEBUG
+#    org.springframework.web: INFO
+#    org.springframework.cloud.openfeign: INFO
+
+
+spring:
+  jackson:
+    time-zone: Asia/Shanghai
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://localhost:3306/sw-backend
+    username: root
+    password: root
+    hikari:
+      data-source-properties:
+        useSSL: false
+        characterEncoding: utf8
+        characterSetResults: utf8
+  jpa: 
+    hibernate:
+      ddl-auto: none
+      naming:
+        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
+    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
+    show-sql: true
+
+
+##
+# infras.online-doc
+#
+infras.online-doc.enabled: false
+infras.online-doc.md-docs.staitc.path: /Users/loie/c/work/git/institute/sw-backend/doc/
+infras.online-doc.api-docs.staitc.path: /Users/loie/c/work/git/institute/sw-backend/api-docs/
+
+
+swagger2.apis.basePackage: com.supwisdom.institute
diff --git a/sa/admin/src/main/resources/bootstrap.yml b/sa/admin/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..5e82cca
--- /dev/null
+++ b/sa/admin/src/main/resources/bootstrap.yml
@@ -0,0 +1,3 @@
+spring:
+  application:
+    name: sw-backend-admin-sa
diff --git a/sa/pom.xml b/sa/pom.xml
new file mode 100644
index 0000000..e4c2665
--- /dev/null
+++ b/sa/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+  
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-sa-aggregator</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <name>Supwisdom Backend Framework Super Admin Aggregator</name>
+  <description>Supwisdom Backend Framework Super Admin Aggregator project</description>
+
+  <modules>
+    <module>admin</module>
+  </modules>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/system/api/pom.xml b/system/api/pom.xml
new file mode 100644
index 0000000..5f7637f
--- /dev/null
+++ b/system/api/pom.xml
@@ -0,0 +1,111 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-system-api</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework System API</name>
+  <description>Supwisdom Backend Framework System API project</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-utils</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-framework</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-system-domain</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-mvc</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminAccountController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminAccountController.java
new file mode 100644
index 0000000..d23f7c9
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminAccountController.java
@@ -0,0 +1,5 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+public class AdminAccountController {
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminConfigController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminConfigController.java
new file mode 100644
index 0000000..9eac867
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminConfigController.java
@@ -0,0 +1,197 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.DefaultApiResponse;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+import com.supwisdom.institute.backend.system.domain.exception.ConfigException;
+import com.supwisdom.institute.backend.system.domain.service.ConfigService;
+import com.supwisdom.institute.backend.system.domain.vo.request.ConfigCreateRequest;
+import com.supwisdom.institute.backend.system.domain.vo.request.ConfigQueryRequest;
+import com.supwisdom.institute.backend.system.domain.vo.request.ConfigUpdateRequest;
+import com.supwisdom.institute.backend.system.domain.vo.response.ConfigCreateResponseData;
+import com.supwisdom.institute.backend.system.domain.vo.response.ConfigLoadResponseData;
+import com.supwisdom.institute.backend.system.domain.vo.response.ConfigQueryResponseData;
+import com.supwisdom.institute.backend.system.domain.vo.response.ConfigUpdateResponseData;
+
+@Api(value = "SystemAdminConfig", tags = { "SystemAdminConfig" }, description = "配置项的操作接口")
+@Slf4j
+@RestController
+@RequestMapping("/v1/admin/configs")
+public class AdminConfigController {
+  
+  @Autowired
+  private ConfigService configService;
+
+
+  /**
+   * @param configQueryRequest
+   * @return
+   */
+  @ApiOperation(value = "查询配置列表", notes = "查询配置列表", nickname = "systemAdminConfigQuery")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "loadAll", value = "是否加载全部", required = true, dataType = "boolean", paramType = "query", defaultValue = "false"),
+    @ApiImplicitParam(name = "pageIndex", value = "分页 - 页码", required = true, dataType = "int", paramType = "query", defaultValue = "0", example = "0"),
+    @ApiImplicitParam(name = "pageSize", value = "分页 - 每页记录数", required = true, dataType = "int", paramType = "query", defaultValue = "20", example = "20"),
+    @ApiImplicitParam(name = "mapBean[deleted]", value = "查询条件 - 删除状态 (精确)", required = false, dataType = "boolean", paramType = "query"),
+    @ApiImplicitParam(name = "mapBean[categoryCode]", value = "查询条件 - 分类代码 (精确)", required = false, dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "mapBean[categoryName]", value = "查询条件 - 分类名称 (模糊)", required = false, dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "mapBean[name]", value = "查询条件 - 名称 (模糊)", required = false, dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "mapBean[description]", value = "查询条件 - 描述 (模糊)", required = false, dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "mapBean[configKey]", value = "查询条件 - 配置Key (精确)", required = false, dataType = "string", paramType = "query"),
+  })
+  @RequestMapping(method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ConfigQueryResponseData> query(ConfigQueryRequest configQueryRequest) {
+    
+    Page<Config> page = configService.selectPageList(
+        configQueryRequest.isLoadAll(),
+        configQueryRequest.getPageIndex(),
+        configQueryRequest.getPageSize(),
+        configQueryRequest.getMapBean(),
+        configQueryRequest.getOrderBy());
+
+    ConfigQueryResponseData resp = ConfigQueryResponseData.of(configQueryRequest).build(page);
+    
+    return new DefaultApiResponse<ConfigQueryResponseData>(resp);
+  }
+
+  /**
+   * @param id
+   * @return
+   */
+  @ApiOperation(value = "根据ID获取配置项", notes = "根据ID获取配置项", nickname="systemAdminConfigLoad")
+  @RequestMapping(method = RequestMethod.GET, path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ConfigLoadResponseData> load(
+      @PathVariable("id") String id) {
+    
+    if (id == null || id.length() == 0) {
+      throw new ConfigException().newInstance("exception.get.id.must.not.empty");
+    }
+    
+    Config config = configService.selectById(id);
+    
+    if (config == null) {
+      throw new ConfigException().newInstance("exception.get.domain.not.exist");
+    }
+
+    ConfigLoadResponseData resp = ConfigLoadResponseData.build(config);
+    
+    return new DefaultApiResponse<ConfigLoadResponseData>(resp);
+  }
+  
+  /**
+   * @param configCreateRequest
+   * @return
+   */
+  @ApiOperation(value = "创建配置项", notes = "创建配置项", nickname = "systemAdminConfigCreate")
+  @RequestMapping(method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.CREATED)
+  @ResponseBody
+  public DefaultApiResponse<ConfigCreateResponseData> create(
+      @RequestBody ConfigCreateRequest configCreateRequest) {
+
+    // FIXME: 验证数据有效性
+
+    Config entity = configCreateRequest.getEntity();
+
+    Config ret = configService.insert(entity);
+
+    ConfigCreateResponseData resp = ConfigCreateResponseData.build(ret);
+
+    return new DefaultApiResponse<ConfigCreateResponseData>(resp);
+  }
+
+  @ApiOperation(value = "更新配置项", notes = "更新配置项", nickname = "systemAdminConfigUpdate")
+  @RequestMapping(method = RequestMethod.PUT, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ConfigUpdateResponseData> update(
+      @PathVariable("id") String id,
+      @RequestBody ConfigUpdateRequest configUpdateRequest) {
+
+    Config entity = configUpdateRequest.getEntity();
+
+    if (entity.getId() == null || entity.getId().length() == 0) {
+      throw new ConfigException().newInstance("exception.update.id.must.not.empty");
+    }
+
+    Config tmp = configService.selectById(entity.getId());
+    if (tmp == null) {
+      throw new ConfigException().newInstance("exception.update.domain.not.exist");
+    }
+
+    if (!tmp.getEditable().booleanValue()) {
+      throw new ConfigException().newInstance("exception.editable.can.not.update");
+    }
+
+    entity = EntityUtils.merge(tmp, entity);
+    
+//    if (tmp.getEditable().booleanValue() != entity.getEditable().booleanValue()) {
+//      throw new ConfigException().newInstance("exception.editable.can.not.update");
+//    }
+
+    entity.setEditable(true);  // 防止 可修改记录的 editable 被置为false
+
+    Config ret = configService.update(entity);
+
+    ConfigUpdateResponseData resp = ConfigUpdateResponseData.build(ret);
+    
+    return new DefaultApiResponse<ConfigUpdateResponseData>(resp);
+  }
+
+  
+  /**
+   * @param categoryCode
+   * @param configKey
+   * @return
+   */
+  @ApiOperation(value = "根据 categoryCode、configKey 获取配置项", notes = "根据 categoryCode、configKey 获取配置项", nickname = "systemAdminConfigLoadByCategoryKey")
+  @RequestMapping(method = RequestMethod.GET, path = "/loadByCategoryKey", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ConfigLoadResponseData> loadByCategoryKey(
+      @RequestParam("categoryCode") String categoryCode, 
+      @RequestParam("configKey") String configKey
+      ) {
+    
+    if (categoryCode == null || categoryCode.length() == 0) {
+      throw new ConfigException().newInstance("exception.load.params.must.not.empty");
+    }
+    if (configKey == null || configKey.length() == 0) {
+      throw new ConfigException().newInstance("exception.load.params.must.not.empty");
+    }
+    
+    Config config = configService.selectByCategoryKey(categoryCode, configKey);
+    
+    if (config == null) {
+      throw new ConfigException().newInstance("exception.load.domain.not.exist");
+    }
+
+    ConfigLoadResponseData resp = ConfigLoadResponseData.build(config);
+    
+    return new DefaultApiResponse<ConfigLoadResponseData>(resp);
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminFunctionController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminFunctionController.java
new file mode 100644
index 0000000..fcb3c6a
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminFunctionController.java
@@ -0,0 +1,5 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+public class AdminFunctionController {
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminResourceController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminResourceController.java
new file mode 100644
index 0000000..929d755
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminResourceController.java
@@ -0,0 +1,5 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+public class AdminResourceController {
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminRoleController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminRoleController.java
new file mode 100644
index 0000000..4a7a517
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminRoleController.java
@@ -0,0 +1,5 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+public class AdminRoleController {
+
+}
diff --git a/system/domain/pom.xml b/system/domain/pom.xml
new file mode 100644
index 0000000..8e8e2fb
--- /dev/null
+++ b/system/domain/pom.xml
@@ -0,0 +1,102 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-system-domain</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework System Domain</name>
+  <description>Supwisdom Backend Framework System Domain project</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-framework</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-data-jpa</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Config.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Config.java
new file mode 100644
index 0000000..16300ef
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Config.java
@@ -0,0 +1,80 @@
+package com.supwisdom.institute.backend.system.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+/**
+ * @author loie
+ */
+@Entity
+@Table(name = "TB_CONFIG")
+public class Config extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -2721844710909809785L;
+
+  /**
+   * 分类代码
+   */
+  @Getter
+  @Setter
+  @Column(name = "CATEGORY_CODE")
+  private String categoryCode;
+  
+  /**
+   * 分类名称
+   */
+  @Getter
+  @Setter
+  @Column(name = "CATEGORY_NAME")
+  private String categoryName;
+
+  /**
+   * 名称
+   */
+  @Getter
+  @Setter
+  @Column(name = "NAME")
+  private String name;
+
+  /**
+   * 描述
+   */
+  @Getter
+  @Setter
+  @Column(name = "DESCRIPTION")
+  private String description;
+
+  /**
+   * 配置键
+   */
+  @Getter
+  @Setter
+  @Column(name = "CONFIG_KEY")
+  private String configKey;
+
+  /**
+   * 配置值
+   */
+  @Getter
+  @Setter
+  @Column(name = "CONFIG_VALUE")
+  private String configValue;
+
+  /**
+   * 是否可修改
+   */
+  @Getter
+  @Setter
+  @Column(name = "EDITABLE")
+  private Boolean editable;
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/exception/ConfigException.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/exception/ConfigException.java
new file mode 100644
index 0000000..2a9957e
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/exception/ConfigException.java
@@ -0,0 +1,12 @@
+package com.supwisdom.institute.backend.system.domain.exception;
+
+import com.supwisdom.institute.backend.common.framework.exception.BaseException;
+
+public class ConfigException extends BaseException {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8112079911386045865L;
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/ConfigRepository.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/ConfigRepository.java
new file mode 100644
index 0000000..3d6ce38
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/ConfigRepository.java
@@ -0,0 +1,77 @@
+package com.supwisdom.institute.backend.system.domain.repo;
+
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * @author loie
+ */
+@Repository
+public interface ConfigRepository extends BaseJpaRepository<Config> {
+  
+  public default Page<Config> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    Config probe = new Config();
+    if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
+      probe.setCategoryCode(MapBeanUtils.getString(mapBean, "categoryCode"));
+      probe.setCategoryName(MapBeanUtils.getString(mapBean, "categoryName"));
+      probe.setName(MapBeanUtils.getString(mapBean, "name"));
+      probe.setDescription(MapBeanUtils.getString(mapBean, "description"));
+      probe.setConfigKey(MapBeanUtils.getString(mapBean, "configKey"));
+      probe.setEditable(MapBeanUtils.getBoolean(mapBean, "editable"));
+    }
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("categoryCode", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("categoryName", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("description", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("configKey", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("editable", ExampleMatcher.GenericPropertyMatchers.exact())
+    ;
+    
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<Config> example = Example.of(probe, matcher);
+    
+    Page<Config> page = this.findAll(example, pageRequest);
+    
+    return page;
+  }
+
+  public default Config selectByCategoryKey(String categoryCode, String configKey) {
+    Config probe = new Config();
+    
+    probe.setDeleted(false);
+    probe.setCategoryCode(categoryCode);
+    probe.setConfigKey(configKey);
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("categoryCode", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("configKey", ExampleMatcher.GenericPropertyMatchers.exact())
+    ;
+    
+    Example<Config> example = Example.of(probe, matcher);
+    
+    Optional<Config> config = this.findOne(example);
+    
+    return config.isPresent() ? config.get() : null;
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/ConfigService.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/ConfigService.java
new file mode 100644
index 0000000..858da54
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/ConfigService.java
@@ -0,0 +1,26 @@
+package com.supwisdom.institute.backend.system.domain.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+import com.supwisdom.institute.backend.system.domain.repo.ConfigRepository;
+
+@Service
+public class ConfigService extends ABaseService<Config, ConfigRepository> {
+  
+  @Autowired
+  private ConfigRepository configRepository;
+
+  @Override
+  public ConfigRepository getRepo() {
+    return configRepository;
+  }
+
+  public Config selectByCategoryKey(String categoryCode, String configKey) {
+    
+    return configRepository.selectByCategoryKey(categoryCode, configKey);
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigCreateRequest.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigCreateRequest.java
new file mode 100644
index 0000000..8c741fe
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigCreateRequest.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.system.domain.vo.request;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiCreateRequest;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+/**
+ * @author loie
+ */
+public class ConfigCreateRequest extends Config implements IApiCreateRequest {
+  
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8380208871984763567L;
+
+  public Config getEntity() {
+    return EntityUtils.copy(this, new Config());
+  }
+  
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java
new file mode 100644
index 0000000..e83083b
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java
@@ -0,0 +1,40 @@
+package com.supwisdom.institute.backend.system.domain.vo.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @author loie
+ */
+public class ConfigQueryRequest implements IApiQueryRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -1033044092932525382L;
+
+  @Getter
+  @Setter
+  private boolean loadAll = false;
+  @Getter
+  @Setter
+  private int pageIndex = 0;
+  @Getter
+  @Setter
+  private int pageSize = 20;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, Object> mapBean;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, String> orderBy;
+  
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigUpdateRequest.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigUpdateRequest.java
new file mode 100644
index 0000000..6f7e1a5
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigUpdateRequest.java
@@ -0,0 +1,29 @@
+package com.supwisdom.institute.backend.system.domain.vo.request;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiUpdateRequest;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ConfigUpdateRequest extends Config implements IApiUpdateRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 6002556449210326472L;
+
+  @Getter
+  @Setter
+  private String id;
+  
+  
+  public Config getEntity() {
+    return EntityUtils.copy(this, new Config());
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigCreateResponseData.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigCreateResponseData.java
new file mode 100644
index 0000000..a14a607
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigCreateResponseData.java
@@ -0,0 +1,32 @@
+package com.supwisdom.institute.backend.system.domain.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiCreateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ConfigCreateResponseData extends Config implements IApiCreateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -2300091307366254182L;
+  
+  @Getter
+  @Setter
+  private String id;
+
+  private ConfigCreateResponseData() {
+    
+  }
+  
+  public static ConfigCreateResponseData build(Config entity) {
+    ConfigCreateResponseData configCreateResponse = new ConfigCreateResponseData();
+    return EntityUtils.copy(entity, configCreateResponse);
+  }
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigLoadResponseData.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigLoadResponseData.java
new file mode 100644
index 0000000..a32312d
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigLoadResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.system.domain.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiLoadResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ConfigLoadResponseData extends Config implements IApiLoadResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -579946566129915779L;
+
+  @Getter
+  @Setter
+  private String id;
+  
+  
+  private ConfigLoadResponseData() {
+    
+  }
+  
+  public static ConfigLoadResponseData build(Config entity) {
+    ConfigLoadResponseData configCreateResponse = new ConfigLoadResponseData();
+    return EntityUtils.copy(entity, configCreateResponse);
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigQueryResponseData.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigQueryResponseData.java
new file mode 100644
index 0000000..906d681
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigQueryResponseData.java
@@ -0,0 +1,83 @@
+package com.supwisdom.institute.backend.system.domain.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+import com.supwisdom.institute.backend.system.domain.vo.request.ConfigQueryRequest;
+
+/**
+ * @author loie
+ */
+public class ConfigQueryResponseData implements IApiQueryResponseData<Config> {
+  
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 3188467441502226095L;
+  
+//  private ConfigQueryResponseData() {
+//  }
+  
+  public ConfigQueryResponseData(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    this.loadAll = loadAll;
+    this.pageIndex = pageIndex;
+    this.pageSize = pageSize;
+    this.mapBean = mapBean;
+    this.orderBy = orderBy;
+  }
+
+  public static ConfigQueryResponseData of(ConfigQueryRequest configQueryRequest) {
+    ConfigQueryResponseData configQueryResponse = new ConfigQueryResponseData(
+        configQueryRequest.isLoadAll(), 
+        configQueryRequest.getPageIndex(), 
+        configQueryRequest.getPageSize(), 
+        configQueryRequest.getMapBean(), 
+        configQueryRequest.getOrderBy()
+    );
+    
+    return configQueryResponse;
+  }
+  
+  public ConfigQueryResponseData build(Page<Config> page) {
+    this.currentItemCount = page.getNumberOfElements();
+    this.pageCount = page.getTotalPages();
+    this.recordCount = page.getTotalElements();
+    this.items = page.getContent();
+
+    return this;
+  }
+
+  @Getter
+  private boolean loadAll;
+  @Getter
+  private int pageIndex;
+  @Getter
+  private int pageSize;
+  @Getter
+  private Map<String, Object> mapBean;
+  @Getter
+  private Map<String, String> orderBy;
+  
+  @Getter
+  @Setter
+  private int pageCount;
+  @Getter
+  @Setter
+  private long recordCount;
+  
+  @Getter
+  @Setter
+  private int currentItemCount;
+  
+  @Getter
+  @Setter
+  private List<Config> items;
+  
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigRemoveResponseData.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigRemoveResponseData.java
new file mode 100644
index 0000000..556307b
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigRemoveResponseData.java
@@ -0,0 +1,36 @@
+package com.supwisdom.institute.backend.system.domain.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.persistence.Id;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiRemoveResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+/**
+ * @author loie
+ */
+public class ConfigRemoveResponseData implements IApiRemoveResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8510464738198696332L;
+
+  @Getter
+  @Setter
+  @Id
+  private String id;
+
+  private ConfigRemoveResponseData() {
+    
+  }
+  
+  public static ConfigRemoveResponseData build(Config entity) {
+    ConfigRemoveResponseData configRemoveResponse = new ConfigRemoveResponseData();
+    return EntityUtils.copy(entity, configRemoveResponse);
+  }
+  
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigUpdateResponseData.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigUpdateResponseData.java
new file mode 100644
index 0000000..51ca051
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigUpdateResponseData.java
@@ -0,0 +1,33 @@
+package com.supwisdom.institute.backend.system.domain.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiUpdateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ConfigUpdateResponseData extends Config implements IApiUpdateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 2798387429543859170L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private ConfigUpdateResponseData() {
+    
+  }
+  
+  public static ConfigUpdateResponseData build(Config entity) {
+    ConfigUpdateResponseData configUpdateResponse = new ConfigUpdateResponseData();
+    return EntityUtils.copy(entity, configUpdateResponse);
+  }
+  
+}
diff --git a/system/pom.xml b/system/pom.xml
new file mode 100644
index 0000000..d80ee43
--- /dev/null
+++ b/system/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+  
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-system-aggregator</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <name>Supwisdom Backend Framework System Aggregator</name>
+  <description>Supwisdom Backend Framework System Aggregator project</description>
+
+  <modules>
+    <module>domain</module>
+    <module>api</module>
+  </modules>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>