新增User的增删改查示例(基于jpa实现)
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminUserController.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminUserController.java
new file mode 100644
index 0000000..474e9c5
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminUserController.java
@@ -0,0 +1,298 @@
+package com.supwisdom.leaveschool.user.controller.api.admin;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.collections.IteratorUtils;
+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.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.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.supwisdom.leaveschool.user.domain.User;
+import com.supwisdom.leaveschool.user.model.PagerRequestModel;
+import com.supwisdom.leaveschool.user.model.PagerResponseModel;
+import com.supwisdom.leaveschool.user.repository.UserRepository;
+import com.supwisdom.leaveschool.user.util.DomainUtils;
+
+@RestController
+@RequestMapping("/api/v1/admin/users")
+public class Api1AdminUserController {
+
+  @Autowired
+  private UserRepository userRepository;
+  
+  /**
+   * 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users' 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users?pageIndex=2&pageSize=50' 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users?pageIndex=0&pageSize=20&mapBean[username]=username&mapBean[name]=name&mapBean[status]=1' 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users?pageIndex=0&pageSize=20&mapBean[username]=username&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":"user","addTime":"2018-08-03T07:39:23.000+0000",
+   *       "editAccount":null,"editTime":null,
+   *       "deleteAccount":null,"deleteTime":null,
+   *       "username":"test001",
+   *       "password":"test001",
+   *       "enabled":true,
+   *       "accountNonExpired":true,
+   *       "accountNonLocked":true,
+   *       "credentialsNonExpired":true,
+   *       "name":"测试001",
+   *       "status":"1",
+   *       "mobile":null,
+   *       "email":null
+   *     }
+   *   ]
+   * }
+   * 
+   * @param pagerRequestModel
+   * @return
+   */
+  @GetMapping(produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public PagerResponseModel<User> list(PagerRequestModel pagerRequestModel) {
+    
+    Page<User> page = userRepository.selectPageList(pagerRequestModel.getPageIndex(), pagerRequestModel.getPageSize(), pagerRequestModel.getMapBean());
+    
+    PagerResponseModel<User> pagerResponseModel = PagerResponseModel.of(pagerRequestModel);
+    pagerResponseModel.setPageCount(page.getTotalPages());
+    pagerResponseModel.setRecordCount(page.getTotalElements());
+    pagerResponseModel.setItems(IteratorUtils.toList(page.iterator()));
+    
+    return pagerResponseModel;
+  }
+  
+  /**
+   * 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1' 
+   * 
+   * response success: 
+   * 
+   * {
+   *   "id":"ff80808164feb8990164feba0de50000",
+   *   "companyId":"1",
+   *   "deleted":false,
+   *   "addAccount":"user","addTime":"2018-08-03T07:39:23.000+0000",
+   *   "editAccount":null,"editTime":null,
+   *   "deleteAccount":null,"deleteTime":null,
+   *   "username":"test001",
+   *   "password":"test001",
+   *   "enabled":true,
+   *   "accountNonExpired":true,
+   *   "accountNonLocked":true,
+   *   "credentialsNonExpired":true,
+   *   "name":"测试001",
+   *   "status":"1",
+   *   "mobile":null,
+   *   "email":null
+   * }
+   * 
+   * response error:
+   * 
+   * {
+   *   "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/v1/admin/users/1"
+   * }
+   * 
+   * @param id
+   * @return
+   */
+  @GetMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public User get(@PathVariable("id") String id) {
+    
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty");  // FIXME: RestException
+    }
+    
+    User user = userRepository.selectById(id);
+    
+    if (user == null) {
+      throw new RuntimeException("exception.get.domain.not.exist");  // FIXME: RestException
+    }
+    
+    return user;
+  }
+  
+  /**
+   * 
+   * curl -i -s -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users' \
+   * -d '{"username":"test001","password":"test001","enabled":true,"accountNonExpired":true,"accountNonLocked":true,"credentialsNonExpired":true,"name":"测试001","status":"1"}'
+   * 
+   * response success: 
+   * 
+   * {
+   *   "success":"info.save.success"
+   * }
+   * 
+   * 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/v1/admin/users"
+   * }
+   * 
+   * @param user
+   * @return
+   */
+  @PostMapping(consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public Map<String, Object> save(@RequestBody User user) {
+    
+    User u = userRepository.insert(user);
+    
+    Map<String, Object> res = new HashMap<String, Object>();
+    res.put("success", "info.save.success");
+    
+    return res;
+  }
+  
+  /**
+   * 
+   * curl -i -s -X PUT -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users' \
+   * -d '{"id":"1","status":"0"}'
+   * 
+   * response success:
+   * 
+   * {
+   *   "success":"info.update.success"
+   * }
+   * 
+   * curl -i -s -X PUT -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users' \
+   * -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/v1/admin/users"
+   * }
+   * 
+   * curl -i -s -X PUT -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users' \
+   * -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/v1/admin/users"
+   * }
+   * 
+   * @param user
+   * @return
+   */
+  @PutMapping(consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public Map<String, Object> update(@RequestBody User user) {
+    
+    if (user.getId() == null || user.getId().length() == 0) {
+      throw new RuntimeException("exception.update.id.must.not.empty");  // FIXME: RestException
+    }
+    
+    User tmp = userRepository.selectById(user.getId());
+    if (tmp == null) {
+      throw new RuntimeException("exception.update.domain.not.exist");  // FIXME: RestException
+    }
+    
+    tmp = DomainUtils.merge(user, tmp);
+    
+    User u = userRepository.update(tmp);
+    userRepository.flush();
+    
+    Map<String, Object> res = new HashMap<String, Object>();
+    res.put("success", "info.update.success");
+    
+    return res;
+  }
+  
+  /**
+   * 
+   * curl -i -s -X DELETE -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1'
+   * 
+   * response success: 
+   * 
+   * {
+   *   "success":"info.delete.success"
+   * }
+   * 
+   * response error: 
+   * 
+   * {
+   *   "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/v1/admin/users/1"
+   * }
+   * 
+   * @param id
+   * @return
+   */
+  @DeleteMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public Map<String, Object> delete(@PathVariable("id") String id) {
+    
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.delete.id.must.not.empty");  // FIXME: RestException
+    }
+    
+    User tmp = userRepository.selectById(id);
+    if (tmp == null) {
+      throw new RuntimeException("exception.delete.domain.not.exist");  // FIXME: RestException
+    }
+    
+    userRepository.delete(tmp);
+    
+    Map<String, Object> res = new HashMap<String, Object>();
+    res.put("success", "info.delete.success");
+    
+    return res;
+  }
+  
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/ApiAdminUserController.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/demo/ApiDemoUserController.java
similarity index 81%
rename from samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/ApiAdminUserController.java
rename to samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/demo/ApiDemoUserController.java
index ee17ba3..c0242c3 100644
--- a/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/ApiAdminUserController.java
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/demo/ApiDemoUserController.java
@@ -1,4 +1,4 @@
-package com.supwisdom.leaveschool.user.controller.api.admin;
+package com.supwisdom.leaveschool.user.controller.api.demo;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -12,13 +12,13 @@
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
-@RequestMapping("/api/admin/users")
-public class ApiAdminUserController {
+@RequestMapping("/api/demo/users")
+public class ApiDemoUserController {
   
-  private static final Logger logger = LoggerFactory.getLogger(ApiAdminUserController.class);
+  private static final Logger logger = LoggerFactory.getLogger(ApiDemoUserController.class);
 
   /**
-   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/admin/users/greeting/abc'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/demo/users/greeting/abc'
    *
    * @param name
    * @return
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/ADomain.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/ADomain.java
new file mode 100644
index 0000000..9ec4049
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/ADomain.java
@@ -0,0 +1,138 @@
+package com.supwisdom.leaveschool.user.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 ADomain 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/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/User.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/User.java
new file mode 100644
index 0000000..86fc807
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/User.java
@@ -0,0 +1,123 @@
+package com.supwisdom.leaveschool.user.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import lombok.Data;
+
+@Entity
+@Table(name = "TB_U_USER")
+@Data
+public class User extends ADomain {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 7955624268022038897L;
+
+  @Column(name = "USERNAME", unique = true)
+  private String username;
+  @Column(name = "PASSWORD")
+  private String password;
+
+  @Column(name = "ENABLED")
+  private Boolean enabled;
+  @Column(name = "ACCOUNT_NON_EXPIRED")
+  private Boolean accountNonExpired;
+  @Column(name = "ACCOUNT_NON_LOCKED")
+  private Boolean accountNonLocked;
+  @Column(name = "CREDENTIALS_NON_EXPIRED")
+  private Boolean credentialsNonExpired;
+
+  @Column(name = "NAME")
+  private String name;
+  @Column(name = "STATUS")
+  private String status;
+
+  @Column(name = "MOBILE")
+  private String mobile;
+  @Column(name = "EMAIL")
+  private String email;
+
+  public String getUsername() {
+    return username;
+  }
+
+  public void setUsername(String username) {
+    this.username = username;
+  }
+
+  public String getPassword() {
+    return password;
+  }
+
+  public void setPassword(String password) {
+    this.password = password;
+  }
+
+  public Boolean getEnabled() {
+    return enabled;
+  }
+
+  public void setEnabled(Boolean enabled) {
+    this.enabled = enabled;
+  }
+
+  public Boolean getAccountNonExpired() {
+    return accountNonExpired;
+  }
+
+  public void setAccountNonExpired(Boolean accountNonExpired) {
+    this.accountNonExpired = accountNonExpired;
+  }
+
+  public Boolean getAccountNonLocked() {
+    return accountNonLocked;
+  }
+
+  public void setAccountNonLocked(Boolean accountNonLocked) {
+    this.accountNonLocked = accountNonLocked;
+  }
+
+  public Boolean getCredentialsNonExpired() {
+    return credentialsNonExpired;
+  }
+
+  public void setCredentialsNonExpired(Boolean credentialsNonExpired) {
+    this.credentialsNonExpired = credentialsNonExpired;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  public String getMobile() {
+    return mobile;
+  }
+
+  public void setMobile(String mobile) {
+    this.mobile = mobile;
+  }
+
+  public String getEmail() {
+    return email;
+  }
+
+  public void setEmail(String email) {
+    this.email = email;
+  }
+
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/PagerRequestModel.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/PagerRequestModel.java
new file mode 100644
index 0000000..c31ab0b
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/PagerRequestModel.java
@@ -0,0 +1,42 @@
+package com.supwisdom.leaveschool.user.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/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/PagerResponseModel.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/PagerResponseModel.java
new file mode 100644
index 0000000..3cab2b7
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/PagerResponseModel.java
@@ -0,0 +1,61 @@
+package com.supwisdom.leaveschool.user.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 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 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/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/UserRepository.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/UserRepository.java
new file mode 100644
index 0000000..86d6e84
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/UserRepository.java
@@ -0,0 +1,81 @@
+package com.supwisdom.leaveschool.user.repository;
+
+import java.util.Calendar;
+import java.util.Map;
+import java.util.Optional;
+
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.leaveschool.user.domain.User;
+import com.supwisdom.leaveschool.user.util.AuthenticationUtil;
+
+@Repository
+public interface UserRepository extends JpaRepository<User, String> {
+  
+  public default Page<User> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+    User probe = new User();
+    if (mapBean != null) {
+      probe.setUsername(String.valueOf(mapBean.get("username")));
+      probe.setName(String.valueOf(mapBean.get("name")));
+      probe.setStatus(String.valueOf(mapBean.get("status")));
+    }
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<User> example = Example.of(probe, matcher);
+    
+    Page<User> page = this.findAll(example, pageRequest);
+    
+    return page;
+  }
+  
+  public default User selectById(String id) {
+    
+    try {
+      Optional<User> 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 User insert(User entity) {
+    
+    if (entity.getCompanyId() == null || entity.getCompanyId().isEmpty()) {
+      entity.setCompanyId("1");
+    }
+    
+    entity.setDeleted(false);
+    entity.setAddAccount(AuthenticationUtil.currentUsername());
+    entity.setAddTime(Calendar.getInstance().getTime());
+    
+    User e = this.save(entity);
+    
+    return e;
+  }
+  
+  public default User update(User entity) {
+    
+    entity.setEditAccount(AuthenticationUtil.currentUsername());
+    entity.setEditTime(Calendar.getInstance().getTime());
+    
+    User e = this.save(entity);
+    
+    return e;
+  }
+
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/AuthenticationUtil.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/AuthenticationUtil.java
new file mode 100644
index 0000000..b98e3cb
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/AuthenticationUtil.java
@@ -0,0 +1,45 @@
+package com.supwisdom.leaveschool.user.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AuthenticationUtil {
+
+  private static final Logger logger = LoggerFactory.getLogger(AuthenticationUtil.class);
+
+  public static String currentUsername() {
+    
+    logger.warn("FIXME: currentUsername. return 'user' by default.");
+    return "user";  // FIXME: currentUsername
+
+    /*
+    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+
+    if (authentication == null) {
+      logger.error("authentication is null");
+      return null;
+    }
+
+    logger.debug("authentication is {}", authentication.getPrincipal());
+
+    if (!authentication.isAuthenticated()) {
+      logger.error("authentication is not authenticated");
+      return null;
+    }
+
+    if (authentication.getPrincipal() == null) {
+      logger.error("authentication's principal is null");
+      return null;
+    }
+
+    logger.debug("authentication's principal is {}", authentication.getPrincipal());
+
+    if (authentication.getPrincipal() instanceof MyUser) {
+      return ((MyUser) authentication.getPrincipal()).getUsername();
+    }
+
+    return null;
+    */
+  }
+
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/DomainUtils.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/DomainUtils.java
new file mode 100644
index 0000000..48e9047
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/DomainUtils.java
@@ -0,0 +1,133 @@
+package com.supwisdom.leaveschool.user.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/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/ReflectUtils.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/ReflectUtils.java
new file mode 100644
index 0000000..3bec43d
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/ReflectUtils.java
@@ -0,0 +1,155 @@
+package com.supwisdom.leaveschool.user.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/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/Test.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/Test.java
new file mode 100644
index 0000000..2ded0aa
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/Test.java
@@ -0,0 +1,77 @@
+package com.supwisdom.leaveschool.user.util;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+
+import com.supwisdom.leaveschool.user.domain.ADomain;
+
+public class Test extends ADomain {
+
+  /**
+   * 
+   */
+  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/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/Test2.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/Test2.java
new file mode 100644
index 0000000..426209f
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/util/Test2.java
@@ -0,0 +1,78 @@
+package com.supwisdom.leaveschool.user.util;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+
+import com.supwisdom.leaveschool.user.domain.ADomain;
+
+public class Test2 extends ADomain {
+
+  /**
+   * 
+   */
+  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;
+  }
+}
diff --git a/samples/user/src/main/resources/application.yml b/samples/user/src/main/resources/application.yml
index d7c4020..fff91a4 100755
--- a/samples/user/src/main/resources/application.yml
+++ b/samples/user/src/main/resources/application.yml
@@ -12,3 +12,29 @@
 spring:
   application:
     name: sample-user
+  datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    url: jdbc:mysql://172.50.10.15:3306/lixiao?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull
+    username: lixiao
+    password: lixiao@1234
+  jpa:
+    hibernate:
+      ddl-auto: none
+      naming:
+        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
+    show-sql: true
+
+infras:
+  mvc:
+# 自定义error输出的例子
+    custom-error:
+      enabled: true
+      error-map:
+        org.springframework.validation.BindException: Customized Bind Error Reason
+      include-message: true
+      include-errors: true
+      include-error: true
+      include-exception: true
+      include-path: true
+      include-timestamp: true
+      include-status: true