feat, docs: 完善框架代码,示例代码,使用文档
diff --git a/bff/admin/pom.xml b/bff/admin/pom.xml
index 5bc267a..ecd5261 100644
--- a/bff/admin/pom.xml
+++ b/bff/admin/pom.xml
@@ -50,6 +50,12 @@
 
 
     <dependency>
+      <groupId>org.springframework.cloud</groupId>
+      <artifactId>spring-cloud-starter-openfeign</artifactId>
+    </dependency>
+
+
+    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-webflux</artifactId>
     </dependency>
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
index 364ed0b..942b082 100644
--- 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
@@ -2,22 +2,27 @@
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
 //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;
+import com.supwisdom.institute.backend.common.framework.exception.EnableCustomExceptionHandler;
 
 @SpringBootApplication
-//@EnableFeignClients
+@EnableFeignClients
 
 @EnableSimpleUserTransmit
+@EnableCustomExceptionHandler
 
 //@EnableInfrasOnlineDoc
 
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/model/biz/Biz.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/model/biz/Biz.java
new file mode 100644
index 0000000..f1d904e
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/model/biz/Biz.java
@@ -0,0 +1,37 @@
+package com.supwisdom.institute.backend.admin.bff.apis.model.biz;
+
+import java.util.Date;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.model.ABaseModel;
+
+public class Biz extends ABaseModel {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8755876583168251137L;
+  
+  @Getter
+  @Setter
+  private String id;
+
+  @Getter
+  @Setter
+  private String name;
+  
+  @Getter
+  @Setter
+  private Boolean bool;
+  
+  @Getter
+  @Setter
+  private Date date;
+
+  @Getter
+  @Setter
+  private Integer num;
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/remote/biz/BizRemoteFallbackFactory.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/remote/biz/BizRemoteFallbackFactory.java
new file mode 100644
index 0000000..30d312d
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/remote/biz/BizRemoteFallbackFactory.java
@@ -0,0 +1,61 @@
+package com.supwisdom.institute.backend.admin.bff.apis.remote.biz;
+
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson.JSONObject;
+import com.supwisdom.institute.backend.admin.bff.apis.model.biz.Biz;
+import com.supwisdom.institute.backend.admin.bff.remote.FallbackError;
+
+import feign.hystrix.FallbackFactory;
+
+@Component
+public class BizRemoteFallbackFactory implements FallbackFactory<BizRemoteFeignClient> {
+
+  @Override
+  public BizRemoteFeignClient create(Throwable cause) {
+    return new BizRemoteFeignClient() {
+
+      @Override
+      public JSONObject query(boolean loadAll, int pageIndex, int pageSize) {
+        if (cause != null) {
+          cause.printStackTrace();
+        }
+        return FallbackError.defaultErrorJson(cause);
+      }
+
+      @Override
+      public JSONObject load(String id) {
+        if (cause != null) {
+          cause.printStackTrace();
+        }
+        return FallbackError.defaultErrorJson(cause);
+      }
+
+      @Override
+      public JSONObject create(Biz biz) {
+        if (cause != null) {
+          cause.printStackTrace();
+        }
+        return FallbackError.defaultErrorJson(cause);
+      }
+
+      @Override
+      public JSONObject update(String id, Biz biz) {
+        if (cause != null) {
+          cause.printStackTrace();
+        }
+        return FallbackError.defaultErrorJson(cause);
+      }
+
+      @Override
+      public JSONObject delete(String id) {
+        if (cause != null) {
+          cause.printStackTrace();
+        }
+        return FallbackError.defaultErrorJson(cause);
+      }
+      
+    };
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/remote/biz/BizRemoteFeignClient.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/remote/biz/BizRemoteFeignClient.java
new file mode 100644
index 0000000..cccdd8a
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/remote/biz/BizRemoteFeignClient.java
@@ -0,0 +1,49 @@
+package com.supwisdom.institute.backend.admin.bff.apis.remote.biz;
+
+import org.springframework.cloud.openfeign.FeignClient;
+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 com.alibaba.fastjson.JSONObject;
+import com.supwisdom.institute.backend.admin.bff.apis.model.biz.Biz;
+
+@FeignClient(
+    name = "biz-biz-remote-feign-client",
+    url = "${sw-backend-biz-api.uri}/v1/admin/biz",
+    fallbackFactory = BizRemoteFallbackFactory.class
+)
+public interface BizRemoteFeignClient {
+  
+  @RequestMapping(method = RequestMethod.GET)
+  JSONObject query(
+      @RequestParam(name = "loadAll") boolean loadAll,
+      @RequestParam(name = "pageIndex") int pageIndex,
+      @RequestParam(name = "pageSize") int pageSize
+      
+  );
+  
+  @RequestMapping(method = RequestMethod.GET, path = "/{id}")
+  JSONObject load(
+      @PathVariable(name = "id") String id
+  );
+
+  @RequestMapping(method = RequestMethod.POST)
+  JSONObject create(
+      @RequestBody Biz biz
+  );
+
+  @RequestMapping(method = RequestMethod.PUT, path = "/{id}")
+  JSONObject update(
+      @PathVariable(name = "id") String id,
+      @RequestBody Biz biz
+  );
+  
+  @RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
+  JSONObject delete(
+      @PathVariable(name = "id") String id
+  );
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/service/biz/BizService.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/service/biz/BizService.java
new file mode 100644
index 0000000..7c6b8a7
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/service/biz/BizService.java
@@ -0,0 +1,30 @@
+package com.supwisdom.institute.backend.admin.bff.apis.service.biz;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.alibaba.fastjson.JSONObject;
+import com.supwisdom.institute.backend.admin.bff.apis.remote.biz.BizRemoteFeignClient;
+import com.supwisdom.institute.backend.admin.bff.apis.vo.response.biz.data.BizQueryResponseData;
+
+public class BizService {
+  
+  @Autowired
+  private BizRemoteFeignClient bizRemote;
+  
+  public BizQueryResponseData query(boolean loadAll, int pageIndex, int pageSize) {
+    
+    JSONObject jsonObject = bizRemote.query(loadAll, pageIndex, pageSize);
+    if (jsonObject == null) {
+      return null;
+    }
+    
+    if (jsonObject.getIntValue("code") == 0) {
+      JSONObject data = jsonObject.getJSONObject("data");
+      
+      return data.toJavaObject(BizQueryResponseData.class);
+    }
+    
+    return null;
+  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/vo/response/biz/data/BizQueryResponseData.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/vo/response/biz/data/BizQueryResponseData.java
new file mode 100644
index 0000000..3699ff7
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/apis/vo/response/biz/data/BizQueryResponseData.java
@@ -0,0 +1,45 @@
+package com.supwisdom.institute.backend.admin.bff.apis.vo.response.biz.data;
+
+import java.util.List;
+import java.util.Map;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.admin.bff.apis.model.biz.Biz;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+
+public class BizQueryResponseData implements IApiQueryResponseData<Biz> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -380945463584664943L;
+
+  @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<Biz> items;
+  
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/Swagger2Config.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/Swagger2Config.java
new file mode 100644
index 0000000..9559532
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/configuration/Swagger2Config.java
@@ -0,0 +1,114 @@
+package com.supwisdom.institute.backend.admin.bff.configuration;
+
+import java.util.List;
+
+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.AuthorizationScopeBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.AuthorizationScope;
+import springfox.documentation.service.BasicAuth;
+import springfox.documentation.service.Contact;
+import springfox.documentation.service.SecurityReference;
+import springfox.documentation.service.SecurityScheme;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+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;
+import static com.google.common.collect.Lists.*;
+
+
+//@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)
+        .securitySchemes(securitySchemes())
+        .securityContexts(securityContexts())
+        .apiInfo(apiInfo())
+        .select()
+        .apis(RequestHandlerSelectors.basePackage(basePackage))
+        .paths(PathSelectors.any())
+        .build()
+        ;
+  }
+
+  private ApiInfo apiInfo() {
+    Contact contact = new Contact("Backend Admin BFF", "https://sw-backend-api.supwisdom.com/swagger-ui.html", ""); // name, url, email
+    return new ApiInfoBuilder()
+        .title("Backend Admin BFF APIs")
+        .description("管理后台 - 后端接口")
+        .termsOfServiceUrl("http://www.supwisdom.com/")
+        .contact(contact)
+        .version("1.0")
+        .build();
+  }
+  
+  private List<SecurityScheme> securitySchemes() {
+    return newArrayList(new BasicAuth("sample"));
+  }
+  
+  private List<SecurityContext> securityContexts() {
+    AuthorizationScope[] authScopes = new AuthorizationScope[1];
+    authScopes[0] = new AuthorizationScopeBuilder()
+            .scope("read")
+            .description("read access")
+            .build();
+    SecurityReference securityReference = SecurityReference.builder()
+            .reference("sample")
+            .scopes(authScopes)
+            .build();
+    
+    return newArrayList(SecurityContext.builder().securityReferences(newArrayList(securityReference)).build());
+  }
+
+  @Bean
+  public 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)
+  }
+  
+  
+//  @Bean
+//  public SecurityConfiguration oauth2() {
+//      return SecurityConfigurationBuilder.builder()
+//          .clientId("common")
+//          .clientSecret("secret")
+//          .scopeSeparator(" ")
+//          .useBasicAuthenticationWithAccessCodeGrant(true)
+//          .build();
+//  }
+//  
+//  @Bean
+//  public SecurityConfiguration basic() {
+//      return SecurityConfigurationBuilder.builder()
+//          .clientId("common")
+//          .clientSecret("secret")
+//          .scopeSeparator(" ")
+//          .useBasicAuthenticationWithAccessCodeGrant(true)
+//          .build();
+//  }
+
+}
diff --git a/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/remote/FallbackError.java b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/remote/FallbackError.java
new file mode 100644
index 0000000..d46aa8d
--- /dev/null
+++ b/bff/admin/src/main/java/com/supwisdom/institute/backend/admin/bff/remote/FallbackError.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.admin.bff.remote;
+
+import com.alibaba.fastjson.JSONObject;
+
+public class FallbackError {
+  
+  private FallbackError() {
+    
+  }
+  
+  public static JSONObject defaultErrorJson(Throwable cause) {
+    JSONObject error = new JSONObject();
+    
+    error.put("code", -1);
+    error.put("message", cause.getMessage());
+    error.put("error", cause.getMessage());
+    
+    return error;
+  }
+
+}
diff --git a/bff/admin/src/main/resources/application.yml b/bff/admin/src/main/resources/application.yml
index d93888b..815040b 100644
--- a/bff/admin/src/main/resources/application.yml
+++ b/bff/admin/src/main/resources/application.yml
@@ -111,4 +111,5 @@
 ##
 # server url for feign
 #
-sw-backend-api-admin.server.url: http://localhost:8081
+sw-backend-system-api.uri: http://localhost:8081
+sw-backend-biz-api.uri: http://localhost:8081
diff --git a/biz/api/pom.xml b/biz/api/pom.xml
index bcc67f2..2c5af3b 100644
--- a/biz/api/pom.xml
+++ b/biz/api/pom.xml
@@ -37,6 +37,11 @@
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter</artifactId>
     </dependency>
+    
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+    </dependency>
 
 
     <dependency>
diff --git a/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/v1/admin/AdminBizController.java b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/v1/admin/AdminBizController.java
new file mode 100644
index 0000000..aa324c6
--- /dev/null
+++ b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/v1/admin/AdminBizController.java
@@ -0,0 +1,175 @@
+package com.supwisdom.institute.backend.biz.api.v1.admin;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+
+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.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.supwisdom.institute.backend.biz.api.vo.request.BizCreateRequest;
+import com.supwisdom.institute.backend.biz.api.vo.request.BizQueryRequest;
+import com.supwisdom.institute.backend.biz.api.vo.request.BizUpdateRequest;
+import com.supwisdom.institute.backend.biz.api.vo.response.BizCreateResponseData;
+import com.supwisdom.institute.backend.biz.api.vo.response.BizLoadResponseData;
+import com.supwisdom.institute.backend.biz.api.vo.response.BizQueryResponseData;
+import com.supwisdom.institute.backend.biz.api.vo.response.BizRemoveResponseData;
+import com.supwisdom.institute.backend.biz.api.vo.response.BizUpdateResponseData;
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.biz.domain.exception.BizException;
+import com.supwisdom.institute.backend.biz.domain.service.BizService;
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.DefaultApiResponse;
+
+@Api(value = "BizAdminBiz", tags = { "BizAdminBiz" }, description = "Biz示例接口")
+@RestController
+@RequestMapping("/v1/admin/biz")
+public class AdminBizController {
+  
+  @Autowired
+  private BizService bizService;
+
+  /**
+   * @param bizQueryRequest
+   * @return
+   */
+  @ApiOperation(value = "查询配置列表", notes = "查询配置列表", nickname = "systemAdminBizQuery")
+  @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[bizKey]", value = "查询条件 - 配置Key (精确)", required = false, dataType = "string", paramType = "query"),
+  })
+  @RequestMapping(method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<BizQueryResponseData> query(BizQueryRequest bizQueryRequest) {
+    
+    Page<Biz> page = bizService.selectPageList(
+        bizQueryRequest.isLoadAll(),
+        bizQueryRequest.getPageIndex(),
+        bizQueryRequest.getPageSize(),
+        bizQueryRequest.getMapBean(),
+        bizQueryRequest.getOrderBy());
+
+    BizQueryResponseData resp = BizQueryResponseData.of(bizQueryRequest).build(page);
+    
+    return new DefaultApiResponse<BizQueryResponseData>(resp);
+  }
+
+  /**
+   * @param id
+   * @return
+   */
+  @ApiOperation(value = "根据ID获取配置项", notes = "根据ID获取配置项", nickname="systemAdminBizLoad")
+  @RequestMapping(method = RequestMethod.GET, path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<BizLoadResponseData> load(
+      @PathVariable("id") String id) {
+    
+    if (id == null || id.length() == 0) {
+      throw BizException.newInstance("exception.get.id.must.not.empty");
+    }
+    
+    Biz biz = bizService.selectById(id);
+    
+    if (biz == null) {
+      throw BizException.newInstance("exception.get.domain.not.exist");
+    }
+
+    BizLoadResponseData resp = BizLoadResponseData.of(biz);
+    
+    return new DefaultApiResponse<BizLoadResponseData>(resp);
+  }
+  
+  /**
+   * @param bizCreateRequest
+   * @return
+   */
+  @ApiOperation(value = "创建配置项", notes = "创建配置项", nickname = "systemAdminBizCreate")
+  @RequestMapping(method = RequestMethod.POST, produces = MimeTypeUtils.APPLICATION_JSON_VALUE, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.CREATED)
+  @ResponseBody
+  public DefaultApiResponse<BizCreateResponseData> create(
+      @RequestBody BizCreateRequest bizCreateRequest) {
+
+    // FIXME: 验证数据有效性
+
+    Biz entity = EntityUtils.copy(bizCreateRequest, new Biz());
+
+    Biz ret = bizService.insert(entity);
+
+    BizCreateResponseData resp = BizCreateResponseData.of(ret);
+
+    return new DefaultApiResponse<BizCreateResponseData>(resp);
+  }
+
+  @ApiOperation(value = "更新", notes = "更新", nickname = "systemAdminBizUpdate")
+  @RequestMapping(method = RequestMethod.PUT, path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<BizUpdateResponseData> update(
+      @PathVariable("id") String id,
+      @RequestBody BizUpdateRequest bizUpdateRequest) {
+
+    if (id == null || id.length() == 0) {
+      throw BizException.newInstance("exception.update.id.must.not.empty");
+    }
+
+    Biz tmp = bizService.selectById(id);
+    if (tmp == null) {
+      throw BizException.newInstance("exception.update.domain.not.exist");
+    }
+
+    Biz entity = EntityUtils.copy(bizUpdateRequest, new Biz());
+    entity.setId(id);
+
+    entity = EntityUtils.merge(tmp, entity);
+    
+    Biz ret = bizService.update(entity);
+
+    BizUpdateResponseData resp = BizUpdateResponseData.of(ret);
+    
+    return new DefaultApiResponse<BizUpdateResponseData>(resp);
+  }
+  
+  @ApiOperation(value = "删除", notes = "删除", nickname = "systemAdminBizRemove")
+  @RequestMapping(method = RequestMethod.DELETE, path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<BizRemoveResponseData> remove(
+      @PathVariable("id") String id) {
+    
+    if (id == null || id.length() == 0) {
+      throw BizException.newInstance("exception.remove.id.must.not.empty");
+    }
+
+    Biz tmp = bizService.selectById(id);
+    if (tmp == null) {
+      throw BizException.newInstance("exception.remove.domain.not.exist");
+    }
+    
+    bizService.deleteById(id);
+    
+    BizRemoveResponseData resp = BizRemoveResponseData.of(tmp);
+    
+    return new DefaultApiResponse<BizRemoveResponseData>(resp);
+  }
+
+}
diff --git a/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/request/BizCreateRequest.java b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/request/BizCreateRequest.java
new file mode 100644
index 0000000..e6b6f0e
--- /dev/null
+++ b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/request/BizCreateRequest.java
@@ -0,0 +1,16 @@
+package com.supwisdom.institute.backend.biz.api.vo.request;
+
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiCreateRequest;
+
+/**
+ * @author loie
+ */
+public class BizCreateRequest extends Biz implements IApiCreateRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -3512866840130579457L;
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/request/BizQueryRequest.java
similarity index 74%
copy from system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java
copy to biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/request/BizQueryRequest.java
index e83083b..7f60870 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java
+++ b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/request/BizQueryRequest.java
@@ -1,4 +1,4 @@
-package com.supwisdom.institute.backend.system.domain.vo.request;
+package com.supwisdom.institute.backend.biz.api.vo.request;
 
 import lombok.Getter;
 import lombok.Setter;
@@ -12,29 +12,33 @@
 /**
  * @author loie
  */
-public class ConfigQueryRequest implements IApiQueryRequest {
+public class BizQueryRequest implements IApiQueryRequest {
 
   /**
    * 
    */
-  private static final long serialVersionUID = -1033044092932525382L;
+  private static final long serialVersionUID = -4345168235529389375L;
 
   @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/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/request/BizUpdateRequest.java b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/request/BizUpdateRequest.java
new file mode 100644
index 0000000..74973ce
--- /dev/null
+++ b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/request/BizUpdateRequest.java
@@ -0,0 +1,23 @@
+package com.supwisdom.institute.backend.biz.api.vo.request;
+
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiUpdateRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class BizUpdateRequest extends Biz implements IApiUpdateRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 6002556449210326472L;
+
+  @Getter
+  @Setter
+  private String id;
+
+}
diff --git a/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizCreateResponseData.java b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizCreateResponseData.java
new file mode 100644
index 0000000..9a91fce
--- /dev/null
+++ b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizCreateResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.biz.api.vo.response;
+
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiCreateResponseData;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class BizCreateResponseData extends Biz implements IApiCreateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -7081539211184618366L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private BizCreateResponseData() {
+
+  }
+
+  public static BizCreateResponseData of(Biz entity) {
+    BizCreateResponseData data = new BizCreateResponseData();
+
+    return EntityUtils.copy(entity, data);
+  }
+
+}
diff --git a/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizLoadResponseData.java b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizLoadResponseData.java
new file mode 100644
index 0000000..84c2864
--- /dev/null
+++ b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizLoadResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.biz.api.vo.response;
+
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiLoadResponseData;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class BizLoadResponseData extends Biz implements IApiLoadResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -921871332091924834L;
+  
+  @Getter
+  @Setter
+  private String id;
+  
+  private BizLoadResponseData() {
+    
+  }
+  
+  public static BizLoadResponseData of(Biz entity) {
+    BizLoadResponseData data = new BizLoadResponseData();
+    
+    return EntityUtils.copy(entity, data);
+  }
+
+}
diff --git a/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizQueryResponseData.java b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizQueryResponseData.java
new file mode 100644
index 0000000..3c19ad1
--- /dev/null
+++ b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizQueryResponseData.java
@@ -0,0 +1,80 @@
+package com.supwisdom.institute.backend.biz.api.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.biz.api.vo.request.BizQueryRequest;
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+
+/**
+ * @author loie
+ */
+public class BizQueryResponseData implements IApiQueryResponseData<Biz> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5706417972093485886L;
+  
+  private BizQueryResponseData(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 BizQueryResponseData of(BizQueryRequest queryRequest) {
+    BizQueryResponseData data = new BizQueryResponseData(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(), 
+        queryRequest.getMapBean(), 
+        queryRequest.getOrderBy()
+    );
+    
+    return data;
+  }
+  
+  public BizQueryResponseData build(Page<Biz> 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<Biz> items;
+  
+}
diff --git a/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizRemoveResponseData.java b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizRemoveResponseData.java
new file mode 100644
index 0000000..0d3f019
--- /dev/null
+++ b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizRemoveResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.biz.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiRemoveResponseData;
+
+/**
+ * @author loie
+ */
+public class BizRemoveResponseData implements IApiRemoveResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 7920962172100289008L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private BizRemoveResponseData() {
+
+  }
+
+  public static BizRemoveResponseData of(Biz entity) {
+    BizRemoveResponseData data = new BizRemoveResponseData();
+
+    return EntityUtils.copy(entity, data);
+  }
+
+}
diff --git a/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizUpdateResponseData.java b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizUpdateResponseData.java
new file mode 100644
index 0000000..19bef62
--- /dev/null
+++ b/biz/api/src/main/java/com/supwisdom/institute/backend/biz/api/vo/response/BizUpdateResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.biz.api.vo.response;
+
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiUpdateResponseData;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class BizUpdateResponseData extends Biz implements IApiUpdateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 4502820318022107903L;
+  
+  @Getter
+  @Setter
+  private String id;
+
+  private BizUpdateResponseData() {
+    
+  }
+  
+  public static BizUpdateResponseData of(Biz entity) {
+    BizUpdateResponseData data = new BizUpdateResponseData();
+    
+    return EntityUtils.copy(entity, data);
+  }
+  
+}
diff --git a/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/entity/Biz.java b/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/entity/Biz.java
new file mode 100644
index 0000000..553cc05
--- /dev/null
+++ b/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/entity/Biz.java
@@ -0,0 +1,43 @@
+package com.supwisdom.institute.backend.biz.domain.entity;
+
+import java.util.Date;
+
+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;
+
+@Entity
+@Table(name = "TB_BIZ")
+public class Biz extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5503233707196628811L;
+  
+  @Getter
+  @Setter
+  @Column(name = "NAME")
+  private String name;
+  
+  @Getter
+  @Setter
+  @Column(name = "BOOL")
+  private Boolean bool;
+  
+  @Getter
+  @Setter
+  @Column(name = "DATE")
+  private Date date;
+
+  @Getter
+  @Setter
+  @Column(name = "NUM")
+  private Integer num;
+
+}
diff --git a/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/exception/BizException.java b/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/exception/BizException.java
new file mode 100644
index 0000000..2ae5778
--- /dev/null
+++ b/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/exception/BizException.java
@@ -0,0 +1,12 @@
+package com.supwisdom.institute.backend.biz.domain.exception;
+
+import com.supwisdom.institute.backend.common.framework.exception.BaseException;
+
+public class BizException extends BaseException {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8112079911386045865L;
+
+}
diff --git a/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/repo/BizRepository.java b/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/repo/BizRepository.java
new file mode 100644
index 0000000..cfeae8f
--- /dev/null
+++ b/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/repo/BizRepository.java
@@ -0,0 +1,114 @@
+package com.supwisdom.institute.backend.biz.domain.repo;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Order;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Repository;
+import org.springframework.util.StringUtils;
+
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.DateUtil;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Repository
+public interface BizRepository extends BaseJpaRepository<Biz> {
+  
+  default Specification<Biz> convertSpecification(Map<String, Object> mapBean) {
+
+    Specification<Biz> spec = new Specification<Biz>() {
+
+      /**
+       * 
+       */
+      private static final long serialVersionUID = -1820403213133310124L;
+
+      @Override
+      public Predicate toPredicate(Root<Biz> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
+        List<Predicate> predicates = new ArrayList<>();
+        
+        if (mapBean != null) {
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "name"))) {
+            predicates.add(criteriaBuilder.like(root.get("name"), MapBeanUtils.getString(mapBean, "name")));
+          }
+
+          if (!StringUtils.isEmpty(MapBeanUtils.getBoolean(mapBean, "bool"))) {
+            predicates.add(criteriaBuilder.equal(root.get("bool"), MapBeanUtils.getBoolean(mapBean, "bool")));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "dateBegin"))) {
+            String grantTimeBegin = MapBeanUtils.getString(mapBean, "dateBegin");
+            Date d = DateUtil.parseDate(grantTimeBegin+" 00:00:00", "yyyy-MM-dd HH:mm:ss");
+            
+            if (d != null) {
+              predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("date"), d));
+            }
+          }
+
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "dateEnd"))) {
+            String grantTimeEnd = MapBeanUtils.getString(mapBean, "dateEnd");
+            Date d = DateUtil.parseDate(grantTimeEnd+" 23:59:59", "yyyy-MM-dd HH:mm:ss");
+            
+            if (d != null) {
+              predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("date"), d));
+            }
+          }
+        }
+        
+        return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
+      }
+      
+    };
+    
+    return spec;
+  }
+  
+  @Override
+  public default Page<Biz> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    
+    Specification<Biz> spec = this.convertSpecification(mapBean);
+
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    Sort sort = new Sort(Sort.Direction.DESC, "date");  // Sort.unsorted
+
+    if (orderBy != null) {
+      List<Order> orders = new ArrayList<>();
+      
+      orderBy.forEach((k, v) -> {
+        if ("asc".equalsIgnoreCase(v)) {
+          Order order = Order.asc(k);
+          orders.add(order);
+        } else if ("desc".equalsIgnoreCase(v)) {
+          Order order = Order.desc(k);
+          orders.add(order);
+        } else {
+          Order order = Order.by(k);
+          orders.add(order);
+        }
+      });
+      
+      sort = Sort.by(orders);
+    }
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize, sort);
+    
+    return this.findAll(spec, pageRequest);
+  }
+
+}
diff --git a/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/service/BizService.java b/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/service/BizService.java
new file mode 100644
index 0000000..43f1dd7
--- /dev/null
+++ b/biz/domain/src/main/java/com/supwisdom/institute/backend/biz/domain/service/BizService.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.biz.domain.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.biz.domain.repo.BizRepository;
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+
+@Service
+public class BizService extends ABaseService<Biz, BizRepository> {
+  
+  @Autowired
+  private BizRepository bizRepository;
+
+  @Override
+  public BizRepository getRepo() {
+    return bizRepository;
+  }
+
+}
diff --git a/common/core/pom.xml b/common/core/pom.xml
index d535132..0193355 100644
--- a/common/core/pom.xml
+++ b/common/core/pom.xml
@@ -36,6 +36,7 @@
     <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-openfeign</artifactId>
+      <optional>true</optional>
     </dependency>
 
     <dependency>
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
index 00f2e43..13f4d25 100644
--- 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
@@ -17,5 +17,17 @@
   public static void setUser(User value) {
     user.set(value);
   }
+  
+  
+  
+  public static String getUsername() {
+    User u = user.get();
+    
+    if (u != null) {
+      return u.getUsername();
+    }
+    
+    return null;
+  }
 
 }
diff --git a/common/framework/pom.xml b/common/framework/pom.xml
index 328b83c..18d0ac5 100644
--- a/common/framework/pom.xml
+++ b/common/framework/pom.xml
@@ -44,6 +44,11 @@
 
     <dependency>
       <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-jpa</artifactId>
       <optional>true</optional>
     </dependency>
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
index ee21f7a..5f10b42 100644
--- 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
@@ -6,11 +6,8 @@
    * 
    */
   private static final long serialVersionUID = 2278568118369300446L;
-
-  /**
-   * 异常信息
-   */
-  protected String msg;
+  
+  public static final int DEFAULT_CODE = -1;
 
   /**
    * 具体异常码
@@ -20,7 +17,6 @@
   public BaseException(int code, String msgFormat, Object... args) {
       super(String.format(msgFormat, args));
       this.code = code;
-      this.msg = String.format(msgFormat, args);
   }
 
   public BaseException() {
@@ -39,10 +35,6 @@
       super(message);
   }
 
-  public String getMsg() {
-      return msg;
-  }
-
   public int getCode() {
       return code;
   }
@@ -55,11 +47,11 @@
    * @return
    */
   @Deprecated
-  public BaseException newInstance(String msgFormat, Object... args) {
-      return new BaseException(this.code, msgFormat, args);
+  public static BaseException newInstance(String msgFormat, Object... args) {
+      return new BaseException(DEFAULT_CODE, msgFormat, args);
   }
   
-  public BaseException newInstance(int code, String msgFormat, Object... args) {
+  public static 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/exception/EnableCustomExceptionHandler.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/EnableCustomExceptionHandler.java
new file mode 100644
index 0000000..28553c6
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/EnableCustomExceptionHandler.java
@@ -0,0 +1,17 @@
+package com.supwisdom.institute.backend.common.framework.exception;
+
+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;
+
+@Documented
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Import({ExceptionConfiguration.class})
+public @interface EnableCustomExceptionHandler {
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/ErrorResponse.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/ErrorResponse.java
new file mode 100644
index 0000000..e0e4235
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/ErrorResponse.java
@@ -0,0 +1,38 @@
+package com.supwisdom.institute.backend.common.framework.exception;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiResponseData;
+
+public class ErrorResponse implements IApiResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5810078993746894780L;
+
+  /**
+   * 异常信息
+   */
+  @Getter
+  @Setter
+  private String message;
+
+  /**
+   * 具体异常码
+   */
+  @Getter
+  @Setter
+  private int code = -1;
+
+  private ErrorResponse(int code, String msgFormat, Object... args) {
+    this.code = code;
+    this.message = String.format(msgFormat, args);
+  }
+
+  public static ErrorResponse of(int code, String msgFormat, Object... args) {
+    return new ErrorResponse(code, msgFormat, args);
+  }
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/ExceptionConfiguration.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/ExceptionConfiguration.java
new file mode 100644
index 0000000..845e935
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/ExceptionConfiguration.java
@@ -0,0 +1,14 @@
+package com.supwisdom.institute.backend.common.framework.exception;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ExceptionConfiguration {
+  
+  @Bean
+  public GlobalExceptionHandler globalExceptionHandler() {
+    return new GlobalExceptionHandler();
+  }
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/GlobalExceptionHandler.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..d32199c
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/exception/GlobalExceptionHandler.java
@@ -0,0 +1,30 @@
+package com.supwisdom.institute.backend.common.framework.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+  
+  @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
+  @ExceptionHandler({Exception.class})
+  public ErrorResponse DefaultExceptionHandler(Exception e) {
+    
+    ErrorResponse error = ErrorResponse.of(BaseException.DEFAULT_CODE, e.getMessage());
+    
+    return error;
+  }
+  
+  
+  @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
+  @ExceptionHandler({BaseException.class})
+  public ErrorResponse BaseExceptionHandler(BaseException e) {
+    
+    ErrorResponse error = ErrorResponse.of(e.getCode(), e.getMessage());
+    
+    return error;
+  }
+  
+}
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
deleted file mode 100644
index 3b8d6d3..0000000
--- a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/modal/ABaseModal.java
+++ /dev/null
@@ -1,10 +0,0 @@
-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
deleted file mode 100644
index cb6f72b..0000000
--- a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/modal/IModal.java
+++ /dev/null
@@ -1,7 +0,0 @@
-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/model/ABaseModel.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/model/ABaseModel.java
new file mode 100644
index 0000000..efa3e25
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/model/ABaseModel.java
@@ -0,0 +1,10 @@
+package com.supwisdom.institute.backend.common.framework.model;
+
+public abstract class ABaseModel implements IModel {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8717041105592152819L;
+
+}
diff --git a/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/model/IModel.java b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/model/IModel.java
new file mode 100644
index 0000000..a6258d3
--- /dev/null
+++ b/common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/model/IModel.java
@@ -0,0 +1,7 @@
+package com.supwisdom.institute.backend.common.framework.model;
+
+import java.io.Serializable;
+
+public interface IModel extends Serializable {
+
+}
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/ABaseJpaRepository.java
similarity index 67%
rename from common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/ABaseJpaRepositoryImpl.java
rename to common/framework/src/main/java/com/supwisdom/institute/backend/common/framework/repo/ABaseJpaRepository.java
index 32e0e33..d787e59 100644
--- 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/ABaseJpaRepository.java
@@ -13,21 +13,22 @@
 import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
 import org.springframework.data.repository.NoRepositoryBean;
 
+import com.supwisdom.institute.backend.common.core.transmit.user.UserContext;
 import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
 
 @Transactional
 @NoRepositoryBean
-public class ABaseJpaRepositoryImpl<E extends ABaseEntity> extends SimpleJpaRepository<E, String> implements BaseJpaRepository<E> {
+public class ABaseJpaRepository<E extends ABaseEntity> extends SimpleJpaRepository<E, String> implements BaseJpaRepository<E> {
 
   @SuppressWarnings("unused")
   private final EntityManager em;
 
-  public ABaseJpaRepositoryImpl(Class<E> domainClass, EntityManager em) {
+  public ABaseJpaRepository(Class<E> domainClass, EntityManager em) {
     super(domainClass, em);
     this.em = em;
   }
 
-  public ABaseJpaRepositoryImpl(JpaEntityInformation<E, String> information, EntityManager em) {
+  public ABaseJpaRepository(JpaEntityInformation<E, String> information, EntityManager em) {
     super(information, em);
     this.em = em;
   }
@@ -67,7 +68,9 @@
     if (entity.getDeleted() == null) {
       entity.setDeleted(false);
     }
-    //entity.setAddAccount(AuthUtil.getRemoteUser()); // FIXME: setAddAccount
+    if (entity.getAddAccount() == null) {
+      entity.setAddAccount(UserContext.getUsername());
+    }
     if (entity.getAddTime() == null) {
       entity.setAddTime(Calendar.getInstance().getTime());
     }
@@ -79,7 +82,9 @@
 
   public E update(E entity) {
 
-    //entity.setEditAccount(AuthUtil.getRemoteUser()); // FIXME: setEditAccount
+    if (entity.getEditAccount() == null) {
+      entity.setEditAccount(UserContext.getUsername());
+    }
     if (entity.getEditTime() == null) {
       entity.setEditTime(Calendar.getInstance().getTime());
     }
@@ -88,5 +93,22 @@
 
     return e;
   }
+  
+  public E remove(E entity) {
+    
+    if (entity.getDeleted() == null) {
+      entity.setDeleted(true);
+    }
+    if (entity.getDeleteAccount() == null) {
+      entity.setDeleteAccount(UserContext.getUsername());
+    }
+    if (entity.getDeleteTime() == null) {
+      entity.setDeleteTime(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
index 3451705..ef0a932 100644
--- 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
@@ -10,6 +10,7 @@
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.repository.NoRepositoryBean;
 
+import com.supwisdom.institute.backend.common.core.transmit.user.UserContext;
 import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
 import com.supwisdom.institute.backend.common.util.UUIDUtils;
 
@@ -71,7 +72,7 @@
       entity.setDeleted(false);
     }
     if (entity.getAddAccount() == null) {
-      //entity.setAddAccount(AuthUtil.getRemoteUser()); // FIXME: setAddAccount
+      entity.setAddAccount(UserContext.getUsername());
     }
     if (entity.getAddTime() == null) {
       entity.setAddTime(Calendar.getInstance().getTime());
@@ -85,7 +86,7 @@
   public default E update(E entity) {
 
     if (entity.getEditAccount() == null) {
-      //entity.setEditAccount(AuthUtil.getRemoteUser()); // FIXME: setEditAccount
+      entity.setEditAccount(UserContext.getUsername());
     }
     if (entity.getEditTime() == null) {
       entity.setEditTime(Calendar.getInstance().getTime());
@@ -96,14 +97,13 @@
     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
+      entity.setDeleteAccount(UserContext.getUsername());
     }
     if (entity.getDeleteTime() == null) {
       entity.setDeleteTime(Calendar.getInstance().getTime());
@@ -114,7 +114,6 @@
     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
index ee622bc..0736f3e 100644
--- 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
@@ -10,63 +10,66 @@
 import java.util.List;
 
 /**
- * 
  * 修正hibernate返回自定义pojo类型时找不到属性的BUG
  * 主要发生在使用oracle或高版本的mysql时,查询返回的字段默认是大写的(除非SQL中指定了别名),这导致返回自定义pojo类型时会报找不到属性的错误,该类用于修正此BUG。
- * 使用该类时SQL返回的字段名大小写或者带"_"都会被忽略,如数据库字段为 USER_NAME,自定义pojo的属性名为username就可以使用
- * 
- * @author feng*/
+ * 使用该类时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()]);
+  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;
         }
-         /**
-      * 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;
+        types.add(fs[i].getType());
+        ReflectUtils.makeAccessible(fs[i]);
+        newFs.add(fs[i]);
       }
-      @Override
-      @SuppressWarnings("rawtypes")
-      public List transformList(final List collection) {
-           return collection;
+      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;
+          }
+        }
       }
-}
\ No newline at end of file
+    } 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;
+  }
+}
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
index 8e979e3..20de33c 100644
--- 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
@@ -1,6 +1,5 @@
 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> {
@@ -10,17 +9,6 @@
    */
   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;
   
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
index 72ac7e2..5ea45c5 100644
--- 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
@@ -16,37 +16,14 @@
     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;
   }
 
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
index 487183a..f8f2573 100644
--- 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
@@ -2,15 +2,10 @@
 
 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();
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
index 4e78c10..5789a96 100644
--- 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
@@ -1,11 +1,10 @@
 package com.supwisdom.institute.backend.common.framework.vo.response.data;
 
+import java.io.Serializable;
 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 {
+public interface IApiQueryResponseData<E extends Serializable> extends IApiResponseData {
   
   /**
    * 当前页码
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
index 0a5f50f..136f9de 100644
--- 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
@@ -1,13 +1,5 @@
 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 {
@@ -155,72 +147,72 @@
     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;
-  }
+//  /**
+//   * 获取 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/doc/USAGE.md b/doc/USAGE.md
new file mode 100644
index 0000000..40d7b96
--- /dev/null
+++ b/doc/USAGE.md
@@ -0,0 +1,688 @@
+# 应用开发框架 - 项目开发说明
+
+
+[TOC]
+
+
+## 项目介绍
+
+
+### 公共类库
+
+common,提供公用的工具类、框架代码
+
+
+
+### 业务类库
+
+以 业务领域 为单位,实现 业务领域、业务接口,如:
+
+* system,系统功能
+
+* biz,业务示例
+
+每个 业务领域项目下,又分为 领域层 domain、接口层 api
+
+业务类库中,尽量以通用服务的方式实现业务
+
+
+
+### 微服务项目 sa
+
+将 业务类库 包装为 微服务,对外提供 RESTful API,以及相关的接口文档的访问、测试
+
+
+
+### 后端项目 bff
+
+提供 面向UI 的后端接口
+
+对服务接口的转发(建议,避免使用)
+
+对服务接口的聚合、裁剪、适配
+
+提供用户认证,保护接口的访问权限
+
+
+
+## 项目开发
+
+
+### 业务类库
+
+面对业务需求,设计时,进行领域划分,保证划分的粒度适中
+
+* 在 领域层 domain,创建 实体 entity、数据传输对象 dto、持久化 repo、业务逻辑 service
+
+* 在 接口层 api,创建 值对象 vo、接口 api
+
+#### 实体 entity
+
+```java
+package com.supwisdom.institute.backend.biz.domain.entity;
+
+import java.util.Date;
+
+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;
+
+@Entity
+@Table(name = "TB_BIZ")
+public class Biz extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5503233707196628811L;
+  
+  @Getter
+  @Setter
+  @Column(name = "NAME")
+  private String name;
+  
+  @Getter
+  @Setter
+  @Column(name = "BOOL")
+  private Boolean bool;
+  
+  @Getter
+  @Setter
+  @Column(name = "DATE")
+  private Date date;
+
+  @Getter
+  @Setter
+  @Column(name = "NUM")
+  private Integer num;
+
+}
+
+```
+
+继承 `ABaseEntity`
+
+注解 `@Entity`,指定该 class 为一个实体
+
+注解 `@Table`,指定该实体对应的数据库表的表名
+
+注解 `@Column`,指定该属性对应的数据库表的字段名
+
+表名、字段名 都采用大写,多个单词用 `下划线(_)` 隔开
+
+
+
+#### 数据传输对象 dto
+
+```java
+
+```
+
+
+#### 持久化 repo
+
+```java
+package com.supwisdom.institute.backend.biz.domain.repo;
+
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+
+@Repository
+public interface BizRepository extends BaseJpaRepository<Biz> {
+  
+  @Override
+  public default Page<Biz> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    
+    
+    return null;
+  }
+
+}
+
+```
+
+继承 `BaseJpaRepository<E>`,基类中,已经实现了基本的 CURD 逻辑,方法如下:
+
+* 分页查询
+```java
+  public default Page<E> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy)
+```
+
+* 根据ID获取
+```java
+  public default E selectById(String id)
+```
+
+* 新增
+```java
+  public default E insert(E entity)
+```
+
+* 更新
+```java
+  public default E update(E entity)
+```
+
+* 删除
+```java
+  public default void delete(String id)
+```
+
+
+注解 `@Repository`,指定该 class 为一个数据持久化类
+
+其中 `BaseJpaRepository` 的 `selectPageList` 方法,默认返回所有数据,不会处理查询条件、排序,故一般都需要由业务自行重写
+
+```java
+  default Specification<Biz> convertSpecification(Map<String, Object> mapBean) {
+
+    Specification<Biz> spec = new Specification<Biz>() {
+
+      /**
+       * 
+       */
+      private static final long serialVersionUID = -1820403213133310124L;
+
+      @Override
+      public Predicate toPredicate(Root<Biz> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
+        List<Predicate> predicates = new ArrayList<>();
+        
+        if (mapBean != null) {
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "name"))) {
+            predicates.add(criteriaBuilder.like(root.get("name"), MapBeanUtils.getString(mapBean, "name")));
+          }
+
+          if (!StringUtils.isEmpty(MapBeanUtils.getBoolean(mapBean, "bool"))) {
+            predicates.add(criteriaBuilder.equal(root.get("bool"), MapBeanUtils.getBoolean(mapBean, "bool")));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "dateBegin"))) {
+            String grantTimeBegin = MapBeanUtils.getString(mapBean, "dateBegin");
+            Date d = DateUtil.parseDate(grantTimeBegin+" 00:00:00", "yyyy-MM-dd HH:mm:ss");
+            
+            if (d != null) {
+              predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("date"), d));
+            }
+          }
+
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "dateEnd"))) {
+            String grantTimeEnd = MapBeanUtils.getString(mapBean, "dateEnd");
+            Date d = DateUtil.parseDate(grantTimeEnd+" 23:59:59", "yyyy-MM-dd HH:mm:ss");
+            
+            if (d != null) {
+              predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("date"), d));
+            }
+          }
+        }
+        
+        return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
+      }
+      
+    };
+    
+    return spec;
+  }
+  
+  @Override
+  public default Page<Biz> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    
+    Specification<Biz> spec = this.convertSpecification(mapBean);
+
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    Sort sort = new Sort(Sort.Direction.DESC, "date");  // Sort.unsorted
+
+    if (orderBy != null) {
+      List<Order> orders = new ArrayList<>();
+      
+      orderBy.forEach((k, v) -> {
+        if ("asc".equalsIgnoreCase(v)) {
+          Order order = Order.asc(k);
+          orders.add(order);
+        } else if ("desc".equalsIgnoreCase(v)) {
+          Order order = Order.desc(k);
+          orders.add(order);
+        } else {
+          Order order = Order.by(k);
+          orders.add(order);
+        }
+      });
+      
+      sort = Sort.by(orders);
+    }
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize, sort);
+    
+    return this.findAll(spec, pageRequest);
+  }
+
+```
+
+
+
+#### 业务逻辑 service
+
+```java
+package com.supwisdom.institute.backend.biz.domain.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.supwisdom.institute.backend.biz.domain.entity.Biz;
+import com.supwisdom.institute.backend.biz.domain.repo.BizRepository;
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+
+@Service
+public class BizService extends ABaseService<Biz, BizRepository> {
+  
+  @Autowired
+  private BizRepository bizRepository;
+
+  @Override
+  public BizRepository getRepo() {
+    return bizRepository;
+  }
+
+}
+
+```
+
+继承 `ABaseService<E, REPO>`
+
+注解 `@Service`,指定该 class 为一个业务逻辑类
+
+注入 业务对应的 Repository,并实现 `public REPO getRepo()`
+
+
+#### 值对象 vo
+
+这里的vo,目前主要用于接口的请求、响应对象的封装
+
+
+
+#### 接口 api
+
+```java
+package com.supwisdom.institute.backend.biz.api.v1.admin;
+
+import io.swagger.annotations.Api;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Api(value = "BizAdminBiz", tags = { "BizAdminBiz" }, description = "Biz示例接口")
+@RestController
+@RequestMapping("/v1/admin/biz")
+public class AdminBizController {
+
+}
+
+```
+
+
+
+### 微服务项目
+
+* 关于 Application
+
+```java
+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;
+import com.supwisdom.institute.backend.common.framework.exception.EnableCustomExceptionHandler;
+
+@SpringBootApplication
+
+@EnableSimpleUserTransmit
+@EnableCustomExceptionHandler
+
+@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);
+  }
+
+}
+
+```
+
+注解 `@SpringBootApplication`,
+
+注解 `@EnableSimpleUserTransmit`,从请求中接收 User 信息,通过 Feign 调用外部服务时,传递 User 信息
+
+注解 `@EnableCustomExceptionHandler`,将异常转换为符合开发规范的 json 数据
+
+注解 `@EntityScan`,扫描实体
+
+注解 `@EnableJpaRepositories`,扫描持久类
+
+注解 `@ComponentScan`,扫描组件,如 @Service、@Controller、@RestController 等
+
+Filter `corsFilter`,允许跨域请求,此处允许对路径 `/v2/api-docs` 的跨域请求
+
+
+* 在 pom 中,添加依赖配置
+
+```xml
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-biz-api</artifactId>
+    </dependency>
+
+```
+
+* (可选)在 application.yml 中,添加业务相关的配置项
+
+
+
+### 后端项目
+
+* 关于 Application
+
+```java
+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.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;
+import com.supwisdom.institute.backend.common.framework.exception.EnableCustomExceptionHandler;
+
+@SpringBootApplication
+@EnableFeignClients
+
+@EnableSimpleUserTransmit
+@EnableCustomExceptionHandler
+
+@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);
+  }
+
+}
+
+```
+
+注解 `@SpringBootApplication`,
+
+注解 `@EnableFeignClients`,支持 FeignClient
+
+注解 `@EnableSimpleUserTransmit`,从请求中接收 User 信息,通过 Feign 调用外部服务时,传递 User 信息
+
+注解 `@EnableCustomExceptionHandler`,将异常转换为符合开发规范的 json 数据
+
+注解 `@EnableInfrasCasSecurity`,支持 cas,在 application.yml 可配置是否启用
+
+注解 `@EnableInfrasBasicApi`,支持 basic 认证(一般在开发环境启用),在 application.yml 可配置是否启用
+
+注解 `@EnableInfrasJWTApi`,支持 jwt 认证(一般在生产环境启用),在 application.yml 可配置是否启用
+
+
+
+* 关于接口请求
+
+后端项目中,使用服务接口的方式有 2 种,一是 请求转发,二是 远程调用
+
+
+#### 请求转发
+
+请求转发的方式,基于 spring-cloud-gateway 实现
+
+* 在 pom.xml 中,添加依赖配置
+
+```xml
+    <dependency>
+      <groupId>org.springframework.cloud</groupId>
+      <artifactId>spring-cloud-starter-gateway</artifactId>
+    </dependency>
+
+```
+
+* 在 application.yml 中,添加 spring.cloud.gateway.routes 配置
+
+```yaml
+spring:
+  cloud:
+    gateway:
+      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}
+
+```
+
+**疑问?为何不用服务注册与发现**
+
+考虑到,后期部署采用 k8s,而 k8s 会提供服务注册与发现的能力,所以此处不再考虑
+
+若存在脱离 k8s 部署的情况,可以考虑采用 nginx 实现服务端负载均衡即可,或其他方案
+
+
+#### 远程调用
+
+远程调用的方式,基于 spring-cloud-openfeign 实现
+
+* 在 pom.xml 中,添加依赖配置
+
+```xml
+    <dependency>
+      <groupId>org.springframework.cloud</groupId>
+      <artifactId>spring-cloud-starter-openfeign</artifactId>
+    </dependency>
+
+```
+
+* 在 Application 中,添加注解 `@EnableFeignClients`,`@EnableSimpleUserTransmit`
+
+注解 `@EnableFeignClients`,表示启用 FeignClients 的配置
+
+注解 `@EnableSimpleUserTransmit`,表示将 后端的登录用户信息,在请求 服务接口 的过程中,进行传递(加入到请求头 Header 中)
+
+* 在 application.yml 中,添加 服务接口地址 配置
+
+如:
+```yml
+sw-backend-biz-api.uri: http://localhost:8081
+```
+
+* 在 remote 包 下,创建 FeignClient 类、FallbackFactory 类
+
+```java
+package com.supwisdom.institute.backend.admin.bff.apis.remote.biz;
+
+import org.springframework.cloud.openfeign.FeignClient;
+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 com.alibaba.fastjson.JSONObject;
+import com.supwisdom.institute.backend.admin.bff.apis.model.biz.Biz;
+
+@FeignClient(
+    name = "biz-biz-remote-feign-client",
+    url = "${sw-backend-biz-api.uri}/v1/admin/biz",
+    fallbackFactory = BizRemoteFallbackFactory.class
+)
+public interface BizRemoteFeignClient {
+  
+  @RequestMapping(method = RequestMethod.GET)
+  JSONObject query(
+      @RequestParam(name = "loadAll") boolean loadAll,
+      @RequestParam(name = "pageIndex") int pageIndex,
+      @RequestParam(name = "pageSize") int pageSize
+      
+  );
+  
+  @RequestMapping(method = RequestMethod.GET, path = "/{id}")
+  JSONObject load(
+      @PathVariable(name = "id") String id
+  );
+
+  @RequestMapping(method = RequestMethod.POST)
+  JSONObject create(
+      @RequestBody Biz biz
+  );
+
+  @RequestMapping(method = RequestMethod.PUT, path = "/{id}")
+  JSONObject update(
+      @PathVariable(name = "id") String id,
+      @RequestBody Biz biz
+  );
+  
+  @RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
+  JSONObject delete(
+      @PathVariable(name = "id") String id
+  );
+
+}
+
+```
+
+注解 `@FeignClient`,`url` 指定后端服务的地址,`fallbackFactory` 指定熔断回调处理的工厂类
+
+```java
+package com.supwisdom.institute.backend.admin.bff.apis.remote.biz;
+
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson.JSONObject;
+import com.supwisdom.institute.backend.admin.bff.apis.model.biz.Biz;
+import com.supwisdom.institute.backend.admin.bff.remote.FallbackError;
+
+import feign.hystrix.FallbackFactory;
+
+@Component
+public class BizRemoteFallbackFactory implements FallbackFactory<BizRemoteFeignClient> {
+
+  @Override
+  public BizRemoteFeignClient create(Throwable cause) {
+    return new BizRemoteFeignClient() {
+
+      @Override
+      public JSONObject query(boolean loadAll, int pageIndex, int pageSize) {
+        if (cause != null) {
+          cause.printStackTrace();
+        }
+        return FallbackError.defaultErrorJson(cause);
+      }
+
+      @Override
+      public JSONObject load(String id) {
+        if (cause != null) {
+          cause.printStackTrace();
+        }
+        return FallbackError.defaultErrorJson(cause);
+      }
+
+      @Override
+      public JSONObject create(Biz biz) {
+        if (cause != null) {
+          cause.printStackTrace();
+        }
+        return FallbackError.defaultErrorJson(cause);
+      }
+
+      @Override
+      public JSONObject update(String id, Biz biz) {
+        if (cause != null) {
+          cause.printStackTrace();
+        }
+        return FallbackError.defaultErrorJson(cause);
+      }
+
+      @Override
+      public JSONObject delete(String id) {
+        if (cause != null) {
+          cause.printStackTrace();
+        }
+        return FallbackError.defaultErrorJson(cause);
+      }
+      
+    };
+  }
+
+}
+
+```
\ No newline at end of file
diff --git a/sa/admin/pom.xml b/sa/admin/pom.xml
index 09c386c..a03165a 100644
--- a/sa/admin/pom.xml
+++ b/sa/admin/pom.xml
@@ -35,6 +35,13 @@
       <artifactId>spring-boot-starter-actuator</artifactId>
     </dependency>
 
+
+    <dependency>
+      <groupId>org.springframework.cloud</groupId>
+      <artifactId>spring-cloud-starter-openfeign</artifactId>
+    </dependency>
+
+
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
@@ -46,10 +53,10 @@
     </dependency>
 
 
-    <dependency>
+    <!-- <dependency>
       <groupId>com.supwisdom.infras</groupId>
       <artifactId>infras-mvc</artifactId>
-    </dependency>
+    </dependency> -->
 
     <dependency>
       <groupId>com.supwisdom.infras</groupId>
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
index 252e9bf..8bf05fd 100644
--- 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
@@ -12,10 +12,12 @@
 
 import com.supwisdom.infras.online.doc.configuration.EnableInfrasOnlineDoc;
 import com.supwisdom.institute.backend.common.core.transmit.annotation.EnableSimpleUserTransmit;
+import com.supwisdom.institute.backend.common.framework.exception.EnableCustomExceptionHandler;
 
 @SpringBootApplication
 
 @EnableSimpleUserTransmit
+@EnableCustomExceptionHandler
 
 @EnableInfrasOnlineDoc
 
diff --git a/system/api/pom.xml b/system/api/pom.xml
index 76a9dcd..07e9732 100644
--- a/system/api/pom.xml
+++ b/system/api/pom.xml
@@ -38,6 +38,11 @@
       <artifactId>spring-boot-starter</artifactId>
     </dependency>
 
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+    </dependency>
+
 
     <dependency>
       <groupId>com.supwisdom.institute</groupId>
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
index 9eac867..b67493a 100644
--- 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
@@ -21,16 +21,16 @@
 
 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.api.vo.request.ConfigCreateRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.ConfigQueryRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.ConfigUpdateRequest;
+import com.supwisdom.institute.backend.system.api.vo.response.ConfigCreateResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.ConfigLoadResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.ConfigQueryResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.ConfigUpdateResponseData;
 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
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/.gitkeep b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/.gitkeep
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigCreateRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ConfigCreateRequest.java
similarity index 88%
rename from system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigCreateRequest.java
rename to system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ConfigCreateRequest.java
index 8c741fe..94d8578 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigCreateRequest.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ConfigCreateRequest.java
@@ -1,4 +1,4 @@
-package com.supwisdom.institute.backend.system.domain.vo.request;
+package com.supwisdom.institute.backend.system.api.vo.request;
 
 import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
 import com.supwisdom.institute.backend.common.framework.vo.request.IApiCreateRequest;
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ConfigQueryRequest.java
similarity index 91%
rename from system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java
rename to system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ConfigQueryRequest.java
index e83083b..d167604 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ConfigQueryRequest.java
@@ -1,4 +1,4 @@
-package com.supwisdom.institute.backend.system.domain.vo.request;
+package com.supwisdom.institute.backend.system.api.vo.request;
 
 import lombok.Getter;
 import lombok.Setter;
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigUpdateRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ConfigUpdateRequest.java
similarity index 89%
rename from system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigUpdateRequest.java
rename to system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ConfigUpdateRequest.java
index 6f7e1a5..8ebf5f2 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigUpdateRequest.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ConfigUpdateRequest.java
@@ -1,4 +1,4 @@
-package com.supwisdom.institute.backend.system.domain.vo.request;
+package com.supwisdom.institute.backend.system.api.vo.request;
 
 import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
 import com.supwisdom.institute.backend.common.framework.vo.request.IApiUpdateRequest;
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigCreateResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigCreateResponseData.java
similarity index 91%
rename from system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigCreateResponseData.java
rename to system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigCreateResponseData.java
index a14a607..3d130d8 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigCreateResponseData.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigCreateResponseData.java
@@ -1,4 +1,4 @@
-package com.supwisdom.institute.backend.system.domain.vo.response;
+package com.supwisdom.institute.backend.system.api.vo.response;
 
 import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
 import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiCreateResponseData;
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigLoadResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigLoadResponseData.java
similarity index 91%
rename from system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigLoadResponseData.java
rename to system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigLoadResponseData.java
index a32312d..c93fa8c 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigLoadResponseData.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigLoadResponseData.java
@@ -1,4 +1,4 @@
-package com.supwisdom.institute.backend.system.domain.vo.response;
+package com.supwisdom.institute.backend.system.api.vo.response;
 
 import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
 import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiLoadResponseData;
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigQueryResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigQueryResponseData.java
similarity index 92%
rename from system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigQueryResponseData.java
rename to system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigQueryResponseData.java
index 906d681..aea651a 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigQueryResponseData.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigQueryResponseData.java
@@ -1,4 +1,4 @@
-package com.supwisdom.institute.backend.system.domain.vo.response;
+package com.supwisdom.institute.backend.system.api.vo.response;
 
 import lombok.Getter;
 import lombok.Setter;
@@ -9,8 +9,8 @@
 import org.springframework.data.domain.Page;
 
 import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+import com.supwisdom.institute.backend.system.api.vo.request.ConfigQueryRequest;
 import com.supwisdom.institute.backend.system.domain.entity.Config;
-import com.supwisdom.institute.backend.system.domain.vo.request.ConfigQueryRequest;
 
 /**
  * @author loie
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigRemoveResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigRemoveResponseData.java
similarity index 92%
rename from system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigRemoveResponseData.java
rename to system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigRemoveResponseData.java
index 556307b..d593ed4 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigRemoveResponseData.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigRemoveResponseData.java
@@ -1,4 +1,4 @@
-package com.supwisdom.institute.backend.system.domain.vo.response;
+package com.supwisdom.institute.backend.system.api.vo.response;
 
 import lombok.Getter;
 import lombok.Setter;
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigUpdateResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigUpdateResponseData.java
similarity index 91%
rename from system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigUpdateResponseData.java
rename to system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigUpdateResponseData.java
index 51ca051..95a1d24 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigUpdateResponseData.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ConfigUpdateResponseData.java
@@ -1,4 +1,4 @@
-package com.supwisdom.institute.backend.system.domain.vo.response;
+package com.supwisdom.institute.backend.system.api.vo.response;
 
 import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
 import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiUpdateResponseData;
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/.gitkeep b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/.gitkeep
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/exception/.gitkeep b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/exception/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/exception/.gitkeep
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/model/.gitkeep b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/model/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/model/.gitkeep
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/.gitkeep b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/.gitkeep
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/.gitkeep b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/.gitkeep