迁移samples代码
diff --git a/leaveschool/common/pom.xml b/leaveschool/common/pom.xml
new file mode 100644
index 0000000..67d0e78
--- /dev/null
+++ b/leaveschool/common/pom.xml
@@ -0,0 +1,74 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.leaveschool</groupId>
+    <artifactId>leaveschool-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <groupId>com.supwisdom.leaveschool</groupId>
+  <artifactId>leaveschool-common</artifactId>
+  <packaging>jar</packaging>
+
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+      <optional>true</optional>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-data-jpa</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+
+    <!-- Test things -->
+    <dependency>
+      <groupId>org.testng</groupId>
+      <artifactId>testng</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/controller/api/CrudApiController.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/controller/api/CrudApiController.java
new file mode 100644
index 0000000..0f32960
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/controller/api/CrudApiController.java
@@ -0,0 +1,331 @@
+package com.supwisdom.leaveschool.common.controller.api;
+
+import org.springframework.data.domain.Page;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+import com.supwisdom.leaveschool.common.domain.ABaseDomain;
+import com.supwisdom.leaveschool.common.model.PagerRequestModel;
+import com.supwisdom.leaveschool.common.model.PagerResponseModel;
+import com.supwisdom.leaveschool.common.model.SuccessResponseModel;
+import com.supwisdom.leaveschool.common.repository.BaseJpaRepository;
+import com.supwisdom.leaveschool.common.util.DomainUtils;
+
+public abstract class CrudApiController<D extends ABaseDomain, R extends BaseJpaRepository<D>> {
+  
+  protected abstract R getRepository();
+  
+  /**
+   * 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/${API_PATH_PREFIX}/domains' 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/${API_PATH_PREFIX}/domains?pageIndex=2&pageSize=50' 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/${API_PATH_PREFIX}/domains?pageIndex=0&pageSize=20&mapBean[code]=code&mapBean[name]=name&mapBean[status]=1' 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/${API_PATH_PREFIX}/domains?pageIndex=0&pageSize=20&mapBean[code]=code&mapBean[name]=name&mapBean[status]=0' 
+   * 
+   * response success: 
+   * 
+   * {
+   *   "pageIndex":0,
+   *   "pageSize":20,
+   *   "mapBean":null,
+   *   "pageCount":1,
+   *   "recordCount":1,
+   *   "items":[
+   *     {
+   *       "id":"ff80808164feb8990164feba0de50000",
+   *       "companyId":"1",
+   *       "deleted":false,
+   *       "addAccount":"group","addTime":"2018-08-03T07:39:23.000+0000",
+   *       "editAccount":null,"editTime":null,
+   *       "deleteAccount":null,"deleteTime":null,
+   *       "code":"test001",
+   *       "name":"测试001",
+   *       "memo":"测试001备注",
+   *       "status":"1"
+   *     }
+   *   ]
+   * }
+   * 
+   * response error 401:
+   * 
+   * {
+   *   "timestamp":"2018-08-03T08:48:25.777+0000",
+   *   "status":401,
+   *   "error":"Http Status 401",
+   *   "message":"Unauthorized",
+   *   "path":"/${API_PATH_PREFIX}/domains"
+   * }
+   * 
+   * @param pagerRequestModel
+   * @return
+   */
+  @GetMapping(produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public PagerResponseModel<D> list(PagerRequestModel pagerRequestModel) {
+    
+    Page<D> page = getRepository().selectPageList(pagerRequestModel.getPageIndex(), pagerRequestModel.getPageSize(), pagerRequestModel.getMapBean());
+    
+    PagerResponseModel<D> pagerResponseModel = PagerResponseModel.of(pagerRequestModel);
+    pagerResponseModel.setCurrentItemCount(page.getNumberOfElements());
+    pagerResponseModel.setPageCount(page.getTotalPages());
+    pagerResponseModel.setRecordCount(page.getTotalElements());
+    pagerResponseModel.setItems(page.getContent());
+    
+    return pagerResponseModel;
+  }
+  
+  /**
+   * 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/${API_PATH_PREFIX}/domains/1' 
+   * 
+   * response success: 
+   * 
+   * {
+   *   "id":"ff80808164feb8990164feba0de50000",
+   *   "companyId":"1",
+   *   "deleted":false,
+   *   "addAccount":"group","addTime":"2018-08-03T07:39:23.000+0000",
+   *   "editAccount":null,"editTime":null,
+   *   "deleteAccount":null,"deleteTime":null,
+   *   "code":"test001",
+   *   "name":"测试001",
+   *   "memo":"测试001备注",
+   *   "status":"1"
+   * }
+   * 
+   * response error 401:
+   * 
+   * {
+   *   "timestamp":"2018-08-03T08:43:26.080+0000",
+   *   "status":401,
+   *   "error":"Http Status 401",
+   *   "message":"Unauthorized",
+   *   "path":"/${API_PATH_PREFIX}/domains/ff80808164fecf640164fed269480000"
+   * }
+   * 
+   * response error 500:
+   * 
+   * {
+   *   "timestamp":"2018-08-03T07:44:07.963+0000",
+   *   "status":500,
+   *   "error":"Internal Server Error",
+   *   "exception":"java.lang.RuntimeException",
+   *   "message":"exception.get.domain.not.exist",
+   *   "path":"/${API_PATH_PREFIX}/domains/1"
+   * }
+   * 
+   * @param id
+   * @return
+   */
+  @GetMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public D get(@PathVariable("id") String id) {
+    
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty");  // FIXME: RestException
+    }
+    
+    D d = getRepository().selectById(id);
+    
+    if (d == null) {
+      throw new RuntimeException("exception.get.domain.not.exist");  // FIXME: RestException
+    }
+    
+    return d;
+  }
+  
+  /**
+   * 
+   * curl -i -s -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/${API_PATH_PREFIX}/domains' \
+   * -d '{"code":"test001","name":"测试001","memo":"测试001备注","status":"1","addAccount":"admin"}'
+   * 
+   * response success: 
+   * 
+   * {
+   *   "success":"info.create.success"
+   * }
+   * 
+   * response error 401:
+   * 
+   * {
+   *   "timestamp":"2018-08-03T08:48:25.777+0000",
+   *   "status":401,
+   *   "error":"Http Status 401",
+   *   "message":"Unauthorized",
+   *   "path":"/${API_PATH_PREFIX}/domains"
+   * }
+   * 
+   * response error: // FIXME: save error
+   * 
+   * {
+   *   "timestamp":"2018-08-03T07:45:43.436+0000",
+   *   "status":500,
+   *   "error":"Internal Server Error",
+   *   "exception":"org.springframework.dao.DataIntegrityViolationException",
+   *   "message":"could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
+   *   "path":"/${API_PATH_PREFIX}/domains"
+   * }
+   * 
+   * @param group
+   * @return
+   */
+  @PostMapping(consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public SuccessResponseModel create(@RequestBody D d) {
+    
+    @SuppressWarnings("unused")
+    D ret = getRepository().insert(d);
+    
+    SuccessResponseModel res = new SuccessResponseModel();
+    res.setSuccess("info.create.success");
+    
+    return res;
+  }
+  
+  /**
+   * 
+   * curl -i -s -X PUT -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/${API_PATH_PREFIX}/domains' \
+   * -d '{"id":"1","status":"0"}'
+   * 
+   * response success:
+   * 
+   * {
+   *   "success":"info.update.success"
+   * }
+   * 
+   * response error 401:
+   * 
+   * {
+   *   "timestamp":"2018-08-03T08:48:25.777+0000",
+   *   "status":401,
+   *   "error":"Http Status 401",
+   *   "message":"Unauthorized",
+   *   "path":"/${API_PATH_PREFIX}/domains"
+   * }
+   * 
+   * curl -i -s -X PUT -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/${API_PATH_PREFIX}/domains' \
+   * -d '{"status":"0"}'
+   * 
+   * response error:
+   * 
+   * {
+   *   "timestamp":"2018-08-03T07:50:52.327+0000",
+   *   "status":500,
+   *   "error":"Internal Server Error",
+   *   "exception":"java.lang.RuntimeException",
+   *   "message":"exception.update.id.must.not.empty",
+   *   "path":"/${API_PATH_PREFIX}/domains"
+   * }
+   * 
+   * curl -i -s -X PUT -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/${API_PATH_PREFIX}/domains' \
+   * -d '{"id":"1","status":"0"}'
+   * 
+   * response error:
+   * 
+   * {
+   *   "timestamp":"2018-08-03T07:48:24.774+0000",
+   *   "status":500,
+   *   "error":"Internal Server Error",
+   *   "exception":"java.lang.RuntimeException",
+   *   "message":"exception.update.domain.not.exist",
+   *   "path":"/${API_PATH_PREFIX}/domains"
+   * }
+   * 
+   * @param group
+   * @return
+   */
+  @PutMapping(consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public SuccessResponseModel update(@RequestBody D d) {
+    
+    if (d.getId() == null || d.getId().length() == 0) {
+      throw new RuntimeException("exception.update.id.must.not.empty");  // FIXME: RestException
+    }
+    
+    D tmp = getRepository().selectById(d.getId());
+    if (tmp == null) {
+      throw new RuntimeException("exception.update.domain.not.exist");  // FIXME: RestException
+    }
+    
+    tmp = DomainUtils.merge(d, tmp);
+    
+    @SuppressWarnings("unused")
+    D ret = getRepository().update(tmp);
+    getRepository().flush();
+    
+    SuccessResponseModel res = new SuccessResponseModel();
+    res.setSuccess("info.update.success");
+    
+    return res;
+  }
+  
+  /**
+   * 
+   * curl -i -s -X DELETE -H 'Accept:application/json' 'http://localhost:10010/${API_PATH_PREFIX}/domains/1'
+   * 
+   * response success: 
+   * 
+   * {
+   *   "success":"info.delete.success"
+   * }
+   * 
+   * response error 401:
+   * 
+   * {
+   *   "timestamp":"2018-08-03T08:48:25.777+0000",
+   *   "status":401,
+   *   "error":"Http Status 401",
+   *   "message":"Unauthorized",
+   *   "path":"/${API_PATH_PREFIX}/domains/1"
+   * }
+   * 
+   * response error 500: 
+   * 
+   * {
+   *   "timestamp":"2018-08-03T08:03:16.364+0000",
+   *   "status":500,
+   *   "error":"Internal Server Error",
+   *   "exception":"java.lang.RuntimeException",
+   *   "message":"exception.delete.domain.not.exist",
+   *   "path":"/${API_PATH_PREFIX}/domains/1"
+   * }
+   * 
+   * @param id
+   * @return
+   */
+  @DeleteMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public SuccessResponseModel delete(@PathVariable("id") String id) {
+    
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.delete.id.must.not.empty");  // FIXME: RestException
+    }
+    
+    D tmp = getRepository().selectById(id);
+    if (tmp == null) {
+      throw new RuntimeException("exception.delete.domain.not.exist");  // FIXME: RestException
+    }
+    
+    getRepository().delete(tmp);
+    
+    SuccessResponseModel res = new SuccessResponseModel();
+    res.setSuccess("info.delete.success");
+    
+    return res;
+  }
+  
+
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/domain/ABaseDomain.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/domain/ABaseDomain.java
new file mode 100644
index 0000000..2c01d9a
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/domain/ABaseDomain.java
@@ -0,0 +1,138 @@
+package com.supwisdom.leaveschool.common.domain;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+
+import org.hibernate.annotations.GenericGenerator;
+
+@MappedSuperclass
+public abstract class ABaseDomain implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8023881887762314483L;
+
+  @Id
+  @GeneratedValue(generator = "uuidStrategy")
+  @GenericGenerator(name = "uuidStrategy", strategy = "uuid")
+  //@ApiModelProperty(value = "ID", required = false, example = "")
+  @Column(name = "ID")
+  private String id;
+
+  /**
+   * 获取主键
+   */
+  public String getId() {
+    return id;
+  }
+
+  /**
+   * 设置ID属性,主要用于人工指定键值
+   */
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  //@ApiModelProperty(value = "CompanyID", required = true, example = "1")
+  @Column(name = "COMPANY_ID")
+  private String companyId = null;
+
+  //@ApiModelProperty(value = "是否删除", hidden = true, example = "false")
+  @Column(name = "DELETED")
+  private Boolean deleted = false;
+
+  //@ApiModelProperty(value = "创建人", hidden = true)
+  @Column(name = "ADD_ACCOUNT")
+  private String addAccount = null;
+
+  //@ApiModelProperty(value = "创建时间", hidden = true)
+  @Column(name = "ADD_TIME")
+  private Date addTime = null;
+
+  //@ApiModelProperty(value = "修改人", hidden = true)
+  @Column(name = "EDIT_ACCOUNT")
+  private String editAccount = null;
+
+  //@ApiModelProperty(value = "修改时间", hidden = true)
+  @Column(name = "EDIT_TIME")
+  private Date editTime = null;
+
+  //@ApiModelProperty(value = "删除人", hidden = true)
+  @Column(name = "DELETE_ACCOUNT")
+  private String deleteAccount = null;
+
+  //@ApiModelProperty(value = "删除时间", hidden = true)
+  @Column(name = "DELETE_TIME")
+  private Date deleteTime = null;
+
+  public String getCompanyId() {
+    return companyId;
+  }
+
+  public void setCompanyId(String companyId) {
+    this.companyId = companyId;
+  }
+
+  public Boolean isDeleted() {
+    return deleted;
+  }
+
+  public void setDeleted(Boolean deleted) {
+    this.deleted = deleted;
+  }
+
+  public String getAddAccount() {
+    return addAccount;
+  }
+
+  public void setAddAccount(String addAccount) {
+    this.addAccount = addAccount;
+  }
+
+  public Date getAddTime() {
+    return addTime;
+  }
+
+  public void setAddTime(Date addTime) {
+    this.addTime = addTime;
+  }
+
+  public String getEditAccount() {
+    return editAccount;
+  }
+
+  public void setEditAccount(String editAccount) {
+    this.editAccount = editAccount;
+  }
+
+  public Date getEditTime() {
+    return editTime;
+  }
+
+  public void setEditTime(Date editTime) {
+    this.editTime = editTime;
+  }
+
+  public String getDeleteAccount() {
+    return deleteAccount;
+  }
+
+  public void setDeleteAccount(String deleteAccount) {
+    this.deleteAccount = deleteAccount;
+  }
+
+  public Date getDeleteTime() {
+    return deleteTime;
+  }
+
+  public void setDeleteTime(Date deleteTime) {
+    this.deleteTime = deleteTime;
+  }
+
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/model/PagerRequestModel.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/model/PagerRequestModel.java
new file mode 100644
index 0000000..75309f1
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/model/PagerRequestModel.java
@@ -0,0 +1,42 @@
+package com.supwisdom.leaveschool.common.model;
+
+import java.io.Serializable;
+import java.util.Map;
+
+public class PagerRequestModel implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 6099787167570502127L;
+
+  private int pageIndex = 0;
+  private int pageSize = 20;
+
+  public int getPageIndex() {
+    return pageIndex;
+  }
+
+  public void setPageIndex(int pageIndex) {
+    this.pageIndex = pageIndex;
+  }
+
+  public int getPageSize() {
+    return pageSize;
+  }
+
+  public void setPageSize(int pageSize) {
+    this.pageSize = pageSize;
+  }
+
+  private Map<String, Object> mapBean;
+
+  public Map<String, Object> getMapBean() {
+    return mapBean;
+  }
+
+  public void setMapBean(Map<String, Object> mapBean) {
+    this.mapBean = mapBean;
+  }
+
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/model/PagerResponseModel.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/model/PagerResponseModel.java
new file mode 100644
index 0000000..5df7315
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/model/PagerResponseModel.java
@@ -0,0 +1,71 @@
+package com.supwisdom.leaveschool.common.model;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+public class PagerResponseModel<T> extends PagerRequestModel implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -3449591075961852442L;
+
+  private int currentItemCount;
+  
+  private int pageCount;
+  private long recordCount;
+
+  private Collection<T> items;
+
+  public PagerResponseModel() {
+
+  }
+
+  public PagerResponseModel(PagerRequestModel pagerRequestModel) {
+    super.setPageIndex(pagerRequestModel.getPageIndex());
+    super.setPageSize(pagerRequestModel.getPageSize());
+    super.setMapBean(pagerRequestModel.getMapBean());
+  }
+
+  public static <T> PagerResponseModel<T> of(PagerRequestModel pagerRequestModel) {
+    PagerResponseModel<T> pagerResponseModell = new PagerResponseModel<T>();
+    pagerResponseModell.setPageIndex(pagerRequestModel.getPageIndex());
+    pagerResponseModell.setPageSize(pagerRequestModel.getPageSize());
+    pagerResponseModell.setMapBean(pagerRequestModel.getMapBean());
+
+    return pagerResponseModell;
+  }
+
+  public int getCurrentItemCount() {
+    return currentItemCount;
+  }
+
+  public void setCurrentItemCount(int currentItemCount) {
+    this.currentItemCount = currentItemCount;
+  }
+
+  public int getPageCount() {
+    return pageCount;
+  }
+
+  public void setPageCount(int pageCount) {
+    this.pageCount = pageCount;
+  }
+
+  public long getRecordCount() {
+    return recordCount;
+  }
+
+  public void setRecordCount(long recordCount) {
+    this.recordCount = recordCount;
+  }
+
+  public Collection<T> getItems() {
+    return items;
+  }
+
+  public void setItems(Collection<T> items) {
+    this.items = items;
+  }
+
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/model/SuccessResponseModel.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/model/SuccessResponseModel.java
new file mode 100644
index 0000000..750e55c
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/model/SuccessResponseModel.java
@@ -0,0 +1,22 @@
+package com.supwisdom.leaveschool.common.model;
+
+import java.io.Serializable;
+
+public class SuccessResponseModel implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 280042050835200337L;
+  
+  private String success;
+
+  public String getSuccess() {
+    return success;
+  }
+
+  public void setSuccess(String success) {
+    this.success = success;
+  }
+
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/repository/ABaseJpaRepositoryImpl.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/repository/ABaseJpaRepositoryImpl.java
new file mode 100644
index 0000000..a245196
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/repository/ABaseJpaRepositoryImpl.java
@@ -0,0 +1,84 @@
+package com.supwisdom.leaveschool.common.repository;
+
+import java.util.Calendar;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.persistence.EntityManager;
+import javax.transaction.Transactional;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.jpa.repository.support.JpaEntityInformation;
+import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
+import org.springframework.data.repository.NoRepositoryBean;
+
+import com.supwisdom.leaveschool.common.domain.ABaseDomain;
+
+@Transactional
+@NoRepositoryBean
+public class ABaseJpaRepositoryImpl<T extends ABaseDomain> extends SimpleJpaRepository<T, String> implements BaseJpaRepository<T> {
+
+  @SuppressWarnings("unused")
+  private final EntityManager em;
+
+  public ABaseJpaRepositoryImpl(Class<T> domainClass, EntityManager em) {
+    super(domainClass, em);
+    this.em = em;
+  }
+
+  public ABaseJpaRepositoryImpl(JpaEntityInformation<T, String> information, EntityManager em) {
+    super(information, em);
+    this.em = em;
+  }
+  
+  public Page<T> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<T> page = this.findAll(pageRequest);
+
+    return page;
+  }
+
+  public T selectById(String id) {
+
+    try {
+      Optional<T> entity = this.findById(id);
+
+      return entity.get();
+    } catch (RuntimeException e) {
+      System.out.println("RuntimeException:" + e.getMessage());
+    } catch (Exception e) {
+      System.out.println("Exception:" + e.getMessage());
+    }
+
+    return null;
+  }
+
+  public T insert(T entity) {
+
+    if (entity.getCompanyId() == null || entity.getCompanyId().isEmpty()) {
+      entity.setCompanyId("1");
+    }
+
+    entity.setDeleted(false);
+    //entity.setAddAccount(AuthUtil.getRemoteUser()); // FIXME: setAddAccount
+    entity.setAddTime(Calendar.getInstance().getTime());
+
+    T e = this.save(entity);
+
+    return e;
+  }
+
+  public T update(T entity) {
+
+    //entity.setEditAccount(AuthUtil.getRemoteUser()); // FIXME: setEditAccount
+    entity.setEditTime(Calendar.getInstance().getTime());
+
+    T e = this.save(entity);
+
+    return e;
+  }
+
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/repository/BaseJpaRepository.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/repository/BaseJpaRepository.java
new file mode 100644
index 0000000..e1e0531
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/repository/BaseJpaRepository.java
@@ -0,0 +1,66 @@
+package com.supwisdom.leaveschool.common.repository;
+
+import java.util.Calendar;
+import java.util.Map;
+import java.util.Optional;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.repository.NoRepositoryBean;
+
+import com.supwisdom.leaveschool.common.domain.ABaseDomain;
+
+@NoRepositoryBean
+public interface BaseJpaRepository<T extends ABaseDomain> extends JpaRepository<T, String> {
+  
+  public default Page<T> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<T> page = this.findAll(pageRequest);
+
+    return page;
+  }
+  
+  public default T selectById(String id) {
+
+    try {
+      Optional<T> entity = this.findById(id);
+
+      return entity.get();
+    } catch (RuntimeException e) {
+      System.out.println("RuntimeException:" + e.getMessage());
+    } catch (Exception e) {
+      System.out.println("Exception:" + e.getMessage());
+    }
+
+    return null;
+  }
+  
+  public default T insert(T entity) {
+
+    if (entity.getCompanyId() == null || entity.getCompanyId().isEmpty()) {
+      entity.setCompanyId("1");
+    }
+
+    entity.setDeleted(false);
+    //entity.setAddAccount(AuthUtil.getRemoteUser()); // FIXME: setAddAccount
+    entity.setAddTime(Calendar.getInstance().getTime());
+
+    T e = this.save(entity);
+
+    return e;
+  }
+  
+  public default T update(T entity) {
+
+    //entity.setEditAccount(AuthUtil.getRemoteUser()); // FIXME: setEditAccount
+    entity.setEditTime(Calendar.getInstance().getTime());
+
+    T e = this.save(entity);
+
+    return e;
+  }
+
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/DomainUtils.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/DomainUtils.java
new file mode 100644
index 0000000..f02d7e5
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/DomainUtils.java
@@ -0,0 +1,133 @@
+package com.supwisdom.leaveschool.common.util;
+
+import java.lang.reflect.Field;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+
+/**
+ * 对 domain 的操作 如:复制、合并、转换等
+ * 
+ * @author loie
+ *
+ */
+public class DomainUtils {
+
+  /**
+   * 合并 domain 中带有{@link Column}注解的字段值, 将 oldDomain 中的值,使用 newDomain 中不为null的值
+   * 进行覆盖
+   * 
+   * @param newDomain
+   *          ,
+   * @param oldDomain
+   *          ,被覆盖的实体
+   * @return 合并后的oldDomain
+   */
+  public static <T> T merge(T newDomain, T oldDomain) {
+
+    for (Class<?> clazz = oldDomain.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
+      for (Field field : clazz.getDeclaredFields()) {
+        Column[] annotations = field.getAnnotationsByType(Column.class);
+        if (annotations == null || annotations.length == 0) {
+          Id[] idAnnotations = field.getAnnotationsByType(Id.class);
+          if (idAnnotations == null || idAnnotations.length == 0) {
+            continue;
+          }
+        }
+
+        String fieldName = field.getName();
+        Object newFieldValue = ReflectUtils.getFieldValue(newDomain, fieldName);
+
+        if (newFieldValue != null) {
+          ReflectUtils.setFieldValue(oldDomain, fieldName, newFieldValue);
+        }
+      }
+    }
+
+    return oldDomain;
+  }
+
+  public static <S, T> T copy(S sourceDomain, T targetDomain) {
+    
+    for (Class<?> clazz = targetDomain.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
+      for (Field field : clazz.getDeclaredFields()) {
+        Column[] annotations = field.getAnnotationsByType(Column.class);
+        if (annotations == null || annotations.length == 0) {
+          Id[] idAnnotations = field.getAnnotationsByType(Id.class);
+          if (idAnnotations == null || idAnnotations.length == 0) {
+            continue;
+          }
+        }
+
+        String fieldName = field.getName();
+        Object sFieldValue = ReflectUtils.getFieldValue(sourceDomain, fieldName);
+
+        if (sFieldValue != null) {
+          ReflectUtils.setFieldValue(targetDomain, fieldName, sFieldValue);
+        }
+      }
+    }
+
+    return targetDomain;
+  }
+
+  public static void main(String[] args) {
+
+    Test target0 = new Test();
+    target0.setId("id0");
+    target0.setCode("code");
+    target0.setName("name");
+    target0.setDate(new Date());
+    target0.setEnabled(false);
+    target0.setStatus(1);
+
+    System.out.println("target0 == " + target0.toString());
+    System.out.println();
+
+    Test source1 = new Test();
+    // source1.setId("id1");
+    source1.setCode("code1");
+    // source1.setName("name");
+    // source1.setDate(new Date());
+    source1.setEnabled(true);
+    // source1.setStatus(1);
+    System.out.println("source1 == " + source1.toString());
+
+    Test target1 = DomainUtils.merge(source1, target0);
+    System.out.println("target0 == " + target0.toString());
+    System.out.println("target1 == " + target1.toString());
+    System.out.println();
+
+    Test source2 = new Test();
+    // source2.setId("id2");
+    source2.setCode("code2");
+    source2.setName("name2");
+    // source2.setDate(new Date());
+    // source2.setEnabled(true);
+    source2.setStatus(2);
+    System.out.println("source2 == " + source2.toString());
+
+    Test target2 = DomainUtils.merge(source2, target0);
+    System.out.println("target0 == " + target0.toString());
+    System.out.println("target2 == " + target2.toString());
+    System.out.println();
+
+
+    Test test = new Test();
+    test.setId("id0");
+    test.setCode("code");
+    test.setName("name");
+    test.setDate(new Date());
+    test.setEnabled(false);
+    test.setStatus(1);
+
+    Test2 test2 = new Test2();
+    test2 = DomainUtils.copy(test, test2);
+    System.out.println("test    == " + test.toString());
+    System.out.println("test2   == " + test2.toString());
+    System.out.println();
+
+  }
+
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/MapBeanUtils.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/MapBeanUtils.java
new file mode 100644
index 0000000..b536b29
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/MapBeanUtils.java
@@ -0,0 +1,150 @@
+package com.supwisdom.leaveschool.common.util;
+
+import java.util.Map;
+
+public class MapBeanUtils {
+
+  /**
+   * 判断 mapBean 中的 key 是否存在;若存在,则判断是否有值
+   * 
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static boolean containsValue(Map<String, Object> mapBean, String key) {
+
+    if (!mapBean.containsKey(key)) {
+      return false;
+    }
+
+    if (mapBean.get(key) == null) {
+      return false;
+    }
+
+    if (String.valueOf(mapBean.get(key)).isEmpty()) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 null
+   * 
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static String getString(Map<String, Object> mapBean, String key) {
+
+    return getString(mapBean, key, null);
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 defaultValue
+   * 
+   * @param mapBean
+   * @param key
+   * @param defaultValue
+   * @return
+   */
+  public static String getString(Map<String, Object> mapBean, String key, String defaultValue) {
+
+    if (containsValue(mapBean, key)) {
+      return String.valueOf(mapBean.get(key));
+    }
+
+    return defaultValue;
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 false
+   * 
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static Boolean getBoolean(Map<String, Object> mapBean, String key) {
+
+    return getBoolean(mapBean, key, null);
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 defaultValue
+   * 
+   * @param mapBean
+   * @param key
+   * @param defaultValue
+   * @return
+   */
+  public static Boolean getBoolean(Map<String, Object> mapBean, String key, Boolean defaultValue) {
+
+    if (containsValue(mapBean, key)) {
+      Boolean b = Boolean.valueOf(String.valueOf(mapBean.get(key)));
+      return b == null ? defaultValue : b;
+    }
+
+    return defaultValue;
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 -1
+   * 
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static Integer getInteger(Map<String, Object> mapBean, String key) {
+
+    return getInteger(mapBean, key, null);
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 defaultValue
+   * 
+   * @param mapBean
+   * @param key
+   * @param defaultValue
+   * @return
+   */
+  public static Integer getInteger(Map<String, Object> mapBean, String key, Integer defaultValue) {
+
+    if (containsValue(mapBean, key)) {
+      Integer i = Integer.valueOf(String.valueOf(mapBean.get(key)));
+      return i == null ? defaultValue : i;
+    }
+
+    return defaultValue;
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 -1L
+   * 
+   * @param mapBean
+   * @param key
+   * @return
+   */
+  public static Long getLong(Map<String, Object> mapBean, String key) {
+
+    return getLong(mapBean, key, null);
+  }
+
+  /**
+   * 获取 mapBean 中 key 的 value,若不存在,则返回 defaultValue
+   * 
+   * @param mapBean
+   * @param key
+   * @param defaultValue
+   * @return
+   */
+  public static Long getLong(Map<String, Object> mapBean, String key, Long defaultValue) {
+
+    if (containsValue(mapBean, key)) {
+      Long l = Long.valueOf(String.valueOf(mapBean.get(key)));
+      return l == null ? defaultValue : l;
+    }
+
+    return defaultValue;
+  }
+
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/ReflectUtils.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/ReflectUtils.java
new file mode 100644
index 0000000..53cb150
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/ReflectUtils.java
@@ -0,0 +1,155 @@
+package com.supwisdom.leaveschool.common.util;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * 利用反射进行操作的一个工具类
+ * 
+ */
+public class ReflectUtils {
+
+  /**
+   * 利用反射获取指定对象里面的指定属性
+   * 
+   * @param obj
+   *          目标对象
+   * @param fieldName
+   *          目标属性
+   * @return 目标字段
+   */
+  private static Field getField(Object obj, String fieldName) {
+    Field field = null;
+    for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
+      try {
+        field = clazz.getDeclaredField(fieldName);
+        break;
+      } catch (NoSuchFieldException e) {
+        // 这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。
+      }
+    }
+    return field;
+  }
+
+  /**
+   * 利用反射获取指定对象的指定属性
+   * 
+   * @param obj
+   *          目标对象
+   * @param fieldName
+   *          目标属性
+   * @return 目标属性的值
+   */
+  public static Object getFieldValue(Object obj, String fieldName) {
+    Object result = null;
+    Field field = ReflectUtils.getField(obj, fieldName);
+    if (field != null) {
+      field.setAccessible(true);
+      try {
+        result = field.get(obj);
+      } catch (IllegalArgumentException e) {
+        e.printStackTrace();
+      } catch (IllegalAccessException e) {
+        e.printStackTrace();
+      }
+    }
+    return result;
+  }
+
+  /**
+   * 利用反射设置指定对象的指定属性为指定的值
+   * 
+   * @param obj
+   *          目标对象
+   * @param fieldName
+   *          目标属性
+   * @param fieldValue
+   *          目标值
+   */
+  public static void setFieldValue(Object obj, String fieldName, Object fieldValue) {
+    Field field = ReflectUtils.getField(obj, fieldName);
+    if (field != null) {
+      try {
+        field.setAccessible(true);
+
+        if (fieldValue instanceof String) {
+          Object value = typeConversion(field.getType(), String.valueOf(fieldValue));
+          field.set(obj, value);
+        } else {
+          field.set(obj, fieldValue);
+        }
+
+      } catch (IllegalArgumentException e) {
+        e.printStackTrace();
+      } catch (IllegalAccessException e) {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  /**
+   * 反射调用对象的方法
+   * 
+   * @param obj
+   *          对象
+   * @param methodName
+   *          方法名称
+   * @param paramType
+   *          参数类型 new Class[]{int.class,double.class}
+   * @param params
+   *          参数值 new Object[]{2,3.5}
+   * @return
+   * @throws Exception
+   */
+  public static Object invokeObjMethod(Object obj, String methodName, Class<?>[] paramTypes, Object[] params)
+      throws Exception {
+    // 发现类型
+    Class<?> cls = obj.getClass();
+    // 发现方法
+    Method method = cls.getDeclaredMethod(methodName, paramTypes);
+    // 访问方法时,压制Java对访问修饰符的检查
+    method.setAccessible(true);
+    Object val = method.invoke(obj, params);
+    return val;
+  }
+
+  /**
+   * 类型转换
+   * 
+   * @param clazz
+   *          :目标类型
+   * @param source
+   *          :待转换对象
+   * @return :目标对象
+   */
+  public static Object typeConversion(Class<?> clazz, String source) {
+
+    if (clazz == null) {
+      throw new IllegalArgumentException("clazz should not be null");
+    }
+
+    Object targetObj = null;
+    String nameType = clazz.getName();
+
+    if ("java.lang.Integer".equals(nameType) || "int".equals(nameType)) {
+      targetObj = Integer.valueOf(source);
+    } else if ("java.lang.String".equals(nameType) || "string".equals(nameType)) {
+      targetObj = source;
+    } else if ("java.lang.Float".equals(nameType) || "float".equals(nameType)) {
+      targetObj = Float.valueOf(source);
+    } else if ("java.lang.Double".equals(nameType) || "double".equals(nameType)) {
+      targetObj = Double.valueOf(source);
+    } else if ("java.lang.Boolean".equals(nameType) || "boolean".equals(nameType)) {
+      targetObj = Boolean.valueOf(source);
+    } else if ("java.lang.Long".equals(nameType) || "long".equals(nameType)) {
+      targetObj = Long.valueOf(source);
+    } else if ("java.lang.Short".equals(nameType) || "short".equals(nameType)) {
+      targetObj = Short.valueOf(source);
+    } else if ("java.lang.Character".equals(nameType) || "char".equals(nameType)) {
+      targetObj = source.charAt(1);
+    }
+
+    return targetObj;
+  }
+
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/Test.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/Test.java
new file mode 100644
index 0000000..a82d78c
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/Test.java
@@ -0,0 +1,77 @@
+package com.supwisdom.leaveschool.common.util;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+
+import com.supwisdom.leaveschool.common.domain.ABaseDomain;
+
+public class Test extends ABaseDomain {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 3545969960574885501L;
+  @Column
+  private String code = null;
+  @Column
+  private String name = null;
+  @Column
+  private Date date = null;
+  @Column
+  private Boolean enabled = null;
+  @Column
+  private Integer status = null;
+
+  public String getCode() {
+    return code;
+  }
+
+  public void setCode(String code) {
+    this.code = code;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public Date getDate() {
+    return date;
+  }
+
+  public void setDate(Date date) {
+    this.date = date;
+  }
+
+  public Boolean getEnabled() {
+    return enabled;
+  }
+
+  public void setEnabled(Boolean enabled) {
+    this.enabled = enabled;
+  }
+
+  public Integer getStatus() {
+    return status;
+  }
+
+  public void setStatus(Integer status) {
+    this.status = status;
+  }
+
+  @Override
+  public String toString() {
+    String s = "";
+    s+="id="+this.getId();
+    s += "&code="+String.valueOf(this.code);
+    s += "&name="+String.valueOf(this.name);
+    s += "&date="+String.valueOf(this.date);
+    s += "&enabled="+String.valueOf(this.enabled);
+    s += "&status="+String.valueOf(this.status);
+    return s;
+  }
+}
diff --git a/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/Test2.java b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/Test2.java
new file mode 100644
index 0000000..c093d0f
--- /dev/null
+++ b/leaveschool/common/src/main/java/com/supwisdom/leaveschool/common/util/Test2.java
@@ -0,0 +1,78 @@
+package com.supwisdom.leaveschool.common.util;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+
+import com.supwisdom.leaveschool.common.domain.ABaseDomain;
+
+public class Test2 extends ABaseDomain {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 3545969960574885501L;
+  @Column
+  private String name = null;
+  @Column
+  private String memo = null;
+  @Column
+  private Date date = null;
+  @Column
+  private Boolean enabled = null;
+  @Column
+  private Integer status = null;
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getMemo() {
+    return memo;
+  }
+
+  public void setMemo(String memo) {
+    this.memo = memo;
+  }
+
+  public Date getDate() {
+    return date;
+  }
+
+  public void setDate(Date date) {
+    this.date = date;
+  }
+
+  public Boolean getEnabled() {
+    return enabled;
+  }
+
+  public void setEnabled(Boolean enabled) {
+    this.enabled = enabled;
+  }
+
+  public Integer getStatus() {
+    return status;
+  }
+
+  public void setStatus(Integer status) {
+    this.status = status;
+  }
+
+  @Override
+  public String toString() {
+    String s = "";
+    s+="id="+this.getId();
+    //s += "&code="+String.valueOf(this.code);
+    s += "&name="+String.valueOf(this.name);
+    s += "&memo="+String.valueOf(this.memo);
+    s += "&date="+String.valueOf(this.date);
+    s += "&enabled="+String.valueOf(this.enabled);
+    s += "&status="+String.valueOf(this.status);
+    return s;
+  }
+}