完成Group、Role、GroupUser、UserRole、GroupRole的管理接口
diff --git a/samples/common/src/main/java/com/supwisdom/leaveschool/common/controller/api/CrudApiController.java b/samples/common/src/main/java/com/supwisdom/leaveschool/common/controller/api/CrudApiController.java
index eb45af1..a84d7f4 100644
--- a/samples/common/src/main/java/com/supwisdom/leaveschool/common/controller/api/CrudApiController.java
+++ b/samples/common/src/main/java/com/supwisdom/leaveschool/common/controller/api/CrudApiController.java
@@ -1,10 +1,8 @@
 package com.supwisdom.leaveschool.common.controller.api;
 
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.collections.IteratorUtils;
 import org.springframework.data.domain.Page;
 import org.springframework.http.HttpStatus;
 import org.springframework.util.MimeTypeUtils;
@@ -78,13 +76,11 @@
     
     Page<D> page = getRepository().selectPageList(pagerRequestModel.getPageIndex(), pagerRequestModel.getPageSize(), pagerRequestModel.getMapBean());
     
-    @SuppressWarnings("unchecked")
-    List<D> list = IteratorUtils.toList(page.iterator());
-    
     PagerResponseModel<D> pagerResponseModel = PagerResponseModel.of(pagerRequestModel);
+    pagerResponseModel.setCurrentItemCount(page.getNumberOfElements());
     pagerResponseModel.setPageCount(page.getTotalPages());
     pagerResponseModel.setRecordCount(page.getTotalElements());
-    pagerResponseModel.setItems(list);
+    pagerResponseModel.setItems(page.getContent());
     
     return pagerResponseModel;
   }
diff --git a/samples/common/src/main/java/com/supwisdom/leaveschool/common/model/PagerResponseModel.java b/samples/common/src/main/java/com/supwisdom/leaveschool/common/model/PagerResponseModel.java
index 1b7bd7b..5df7315 100644
--- a/samples/common/src/main/java/com/supwisdom/leaveschool/common/model/PagerResponseModel.java
+++ b/samples/common/src/main/java/com/supwisdom/leaveschool/common/model/PagerResponseModel.java
@@ -10,6 +10,8 @@
    */
   private static final long serialVersionUID = -3449591075961852442L;
 
+  private int currentItemCount;
+  
   private int pageCount;
   private long recordCount;
 
@@ -34,6 +36,14 @@
     return pagerResponseModell;
   }
 
+  public int getCurrentItemCount() {
+    return currentItemCount;
+  }
+
+  public void setCurrentItemCount(int currentItemCount) {
+    this.currentItemCount = currentItemCount;
+  }
+
   public int getPageCount() {
     return pageCount;
   }
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminGroupController.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminGroupController.java
index ad2b7f7..745eb94 100644
--- a/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminGroupController.java
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminGroupController.java
@@ -1,12 +1,31 @@
 package com.supwisdom.leaveschool.user.controller.api.admin;
 
+import java.util.HashMap;
+import java.util.List;
+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.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.RestController;
 
 import com.supwisdom.leaveschool.common.controller.api.CrudApiController;
+import com.supwisdom.leaveschool.common.model.PagerRequestModel;
+import com.supwisdom.leaveschool.common.model.PagerResponseModel;
 import com.supwisdom.leaveschool.user.domain.Group;
+import com.supwisdom.leaveschool.user.domain.GroupRole;
+import com.supwisdom.leaveschool.user.domain.GroupUser;
+import com.supwisdom.leaveschool.user.model.GroupRoles;
+import com.supwisdom.leaveschool.user.model.GroupUsers;
 import com.supwisdom.leaveschool.user.repository.GroupRepository;
+import com.supwisdom.leaveschool.user.repository.GroupRoleRepository;
+import com.supwisdom.leaveschool.user.repository.GroupUserRepository;
 
 @RestController
 @RequestMapping("/api/v1/admin/groups")
@@ -14,10 +33,170 @@
 
   @Autowired
   private GroupRepository groupRepository;
-  
+
+  @Autowired
+  private GroupUserRepository groupUserRepository;
+
+  @Autowired
+  private GroupRoleRepository groupRoleRepository;
+
   @Override
   protected GroupRepository getRepository() {
     return groupRepository;
   }
-  
+
+  /**
+   * 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/groups/1/users'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/groups/1/users?pageIndex=2&pageSize=50'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/groups/1/users?pageIndex=0&pageSize=20&mapBean[username]=username&mapBean[name]=name'
+   * 
+   * 
+   * 
+   * @param id
+   * @param pagerRequestModel
+   * @return
+   */
+  @RequestMapping(value = "/{id}/users", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public PagerResponseModel<GroupUser> groupUsers(@PathVariable("id") String id, PagerRequestModel pagerRequestModel) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Group group = groupRepository.selectById(id);
+
+    if (group == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    if (pagerRequestModel.getMapBean() == null) {
+      pagerRequestModel.setMapBean(new HashMap<String, Object>());
+    }
+    pagerRequestModel.getMapBean().put("groupId", group.getId());
+
+    Page<GroupUser> page = groupUserRepository.selectGroupUsers(pagerRequestModel.getPageIndex(),
+        pagerRequestModel.getPageSize(), pagerRequestModel.getMapBean());
+
+    @SuppressWarnings("unchecked")
+    List<GroupUser> list = IteratorUtils.toList(page.iterator());
+
+    PagerResponseModel<GroupUser> pagerResponseModel = PagerResponseModel.of(pagerRequestModel);
+    pagerResponseModel.setPageCount(page.getTotalPages());
+    pagerResponseModel.setRecordCount(page.getTotalElements());
+    pagerResponseModel.setItems(list);
+
+    return pagerResponseModel;
+  }
+
+  /**
+   * 
+   * curl -i -s -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/groups/1/users' \
+   * -d '{"groupUsers":[{"username":"test001"},{"username":"test002"}]}'
+   * 
+   * 
+   * @param id
+   * @param groupUsers
+   * @return
+   */
+  @RequestMapping(value = "/{id}/users", method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public Map<String, Object> relateUsers(@PathVariable("id") String id, @RequestBody GroupUsers groupUsers) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Group group = groupRepository.selectById(id);
+
+    if (group == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    groupUserRepository.relateGroupUsers(group, groupUsers.getGroupUsers());
+
+    Map<String, Object> res = new HashMap<String, Object>();
+    res.put("success", "info.set.success");
+
+    return res;
+  }
+
+  /**
+   * 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/groups/1/roles'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/groups/1/roles?pageIndex=2&pageSize=50'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/groups/1/roles?pageIndex=0&pageSize=20&mapBean[rolecode]=code&mapBean[rolename]=name'
+   * 
+   * 
+   * 
+   * @param id
+   * @param pagerRequestModel
+   * @return
+   */
+  @RequestMapping(value = "/{id}/roles", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public PagerResponseModel<GroupRole> groupRoles(@PathVariable("id") String id, PagerRequestModel pagerRequestModel) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Group group = groupRepository.selectById(id);
+
+    if (group == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    if (pagerRequestModel.getMapBean() == null) {
+      pagerRequestModel.setMapBean(new HashMap<String, Object>());
+    }
+    pagerRequestModel.getMapBean().put("groupId", group.getId());
+
+    Page<GroupRole> page = groupRoleRepository.selectGroupRoles(pagerRequestModel.getPageIndex(),
+        pagerRequestModel.getPageSize(), pagerRequestModel.getMapBean());
+
+    @SuppressWarnings("unchecked")
+    List<GroupRole> list = IteratorUtils.toList(page.iterator());
+
+    PagerResponseModel<GroupRole> pagerResponseModel = PagerResponseModel.of(pagerRequestModel);
+    pagerResponseModel.setPageCount(page.getTotalPages());
+    pagerResponseModel.setRecordCount(page.getTotalElements());
+    pagerResponseModel.setItems(list);
+
+    return pagerResponseModel;
+  }
+
+  /**
+   * 
+   * curl -i -s -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/groups/1/roles' \
+   * -d '{"groupRoles":[{"rolecode":"role001"},{"rolecode":"role002"}]}'
+   * 
+   * 
+   * @param id
+   * @param groupUsers
+   * @return
+   */
+  @RequestMapping(value = "/{id}/roles", method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public Map<String, Object> relateRoles(@PathVariable("id") String id, @RequestBody GroupRoles groupRoles) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Group group = groupRepository.selectById(id);
+
+    if (group == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    groupRoleRepository.relateGroupRoles(group, groupRoles.getGroupRoles());
+
+    Map<String, Object> res = new HashMap<String, Object>();
+    res.put("success", "info.set.success");
+
+    return res;
+  }
+
 }
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminRoleController.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminRoleController.java
index a4c3e24..3765112 100644
--- a/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminRoleController.java
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/controller/api/admin/Api1AdminRoleController.java
@@ -1,12 +1,31 @@
 package com.supwisdom.leaveschool.user.controller.api.admin;
 
+import java.util.HashMap;
+import java.util.List;
+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.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.RestController;
 
 import com.supwisdom.leaveschool.common.controller.api.CrudApiController;
+import com.supwisdom.leaveschool.common.model.PagerRequestModel;
+import com.supwisdom.leaveschool.common.model.PagerResponseModel;
+import com.supwisdom.leaveschool.user.domain.GroupRole;
 import com.supwisdom.leaveschool.user.domain.Role;
+import com.supwisdom.leaveschool.user.domain.UserRole;
+import com.supwisdom.leaveschool.user.model.GroupRoles;
+import com.supwisdom.leaveschool.user.model.UserRoles;
+import com.supwisdom.leaveschool.user.repository.GroupRoleRepository;
 import com.supwisdom.leaveschool.user.repository.RoleRepository;
+import com.supwisdom.leaveschool.user.repository.UserRoleRepository;
 
 @RestController
 @RequestMapping("/api/v1/admin/roles")
@@ -14,10 +33,173 @@
 
   @Autowired
   private RoleRepository roleRepository;
-  
+
   @Override
   protected RoleRepository getRepository() {
     return roleRepository;
   }
+
+  @Autowired
+  private UserRoleRepository userRoleRepository;
+
+  /**
+   * 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/roles/1/users'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/roles/1/users?pageIndex=2&pageSize=50'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/roles/1/users?pageIndex=0&pageSize=20&mapBean[username]=username'
+   * 
+   * 
+   * 
+   * @param id
+   * @param pagerRequestModel
+   * @return
+   */
+  @RequestMapping(value = "/{id}/users", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public PagerResponseModel<UserRole> roleUsers(@PathVariable("id") String id, PagerRequestModel pagerRequestModel) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Role role = roleRepository.selectById(id);
+
+    if (role == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    if (pagerRequestModel.getMapBean() == null) {
+      pagerRequestModel.setMapBean(new HashMap<String, Object>());
+    }
+    pagerRequestModel.getMapBean().put("rolecode", role.getCode());
+
+    Page<UserRole> page = userRoleRepository.selectUserRoles(pagerRequestModel.getPageIndex(),
+        pagerRequestModel.getPageSize(), pagerRequestModel.getMapBean());
+
+    @SuppressWarnings("unchecked")
+    List<UserRole> list = IteratorUtils.toList(page.iterator());
+
+    PagerResponseModel<UserRole> pagerResponseModel = PagerResponseModel.of(pagerRequestModel);
+    pagerResponseModel.setPageCount(page.getTotalPages());
+    pagerResponseModel.setRecordCount(page.getTotalElements());
+    pagerResponseModel.setItems(list);
+
+    return pagerResponseModel;
+  }
+
+  /**
+   * 
+   * curl -i -s -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/roles/1/users' \
+   * -d '{"userRoles":[{"username":"test001"},{"username":"test002"}]}'
+   * 
+   * 
+   * @param id
+   * @param userRoles
+   * @return
+   */
+  @RequestMapping(value = "/{id}/users", method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public Map<String, Object> relateUsers(@PathVariable("id") String id, @RequestBody UserRoles userRoles) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Role role = roleRepository.selectById(id);
+
+    if (role == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    userRoleRepository.relateRoleUsers(role, userRoles.getUserRoles());
+
+    Map<String, Object> res = new HashMap<String, Object>();
+    res.put("success", "info.set.success");
+
+    return res;
+  }
+
   
+  
+
+  @Autowired
+  private GroupRoleRepository groupRoleRepository;
+
+  /**
+   * 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/roles/1/groups'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/roles/1/groups?pageIndex=2&pageSize=50'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/roles/1/groups?pageIndex=0&pageSize=20&mapBean[username]=username'
+   * 
+   * 
+   * 
+   * @param id
+   * @param pagerRequestModel
+   * @return
+   */
+  @RequestMapping(value = "/{id}/groups", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public PagerResponseModel<GroupRole> roleGroups(@PathVariable("id") String id, PagerRequestModel pagerRequestModel) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Role role = roleRepository.selectById(id);
+
+    if (role == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    if (pagerRequestModel.getMapBean() == null) {
+      pagerRequestModel.setMapBean(new HashMap<String, Object>());
+    }
+    pagerRequestModel.getMapBean().put("rolecode", role.getCode());
+
+    Page<GroupRole> page = groupRoleRepository.selectGroupRoles(pagerRequestModel.getPageIndex(),
+        pagerRequestModel.getPageSize(), pagerRequestModel.getMapBean());
+
+    @SuppressWarnings("unchecked")
+    List<GroupRole> list = IteratorUtils.toList(page.iterator());
+
+    PagerResponseModel<GroupRole> pagerResponseModel = PagerResponseModel.of(pagerRequestModel);
+    pagerResponseModel.setPageCount(page.getTotalPages());
+    pagerResponseModel.setRecordCount(page.getTotalElements());
+    pagerResponseModel.setItems(list);
+
+    return pagerResponseModel;
+  }
+
+  /**
+   * 
+   * curl -i -s -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/roles/1/groups' \
+   * -d '{"userRoles":[{"groupId":"1"},{"groupId":"2"}]}'
+   * 
+   * 
+   * @param id
+   * @param groupRoles
+   * @return
+   */
+  @RequestMapping(value = "/{id}/groups", method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public Map<String, Object> relateGroups(@PathVariable("id") String id, @RequestBody GroupRoles groupRoles) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Role role = roleRepository.selectById(id);
+
+    if (role == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    groupRoleRepository.relateRoleGroups(role, groupRoles.getGroupRoles());
+
+    Map<String, Object> res = new HashMap<String, Object>();
+    res.put("success", "info.set.success");
+
+    return res;
+  }
+
 }
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
index 16f84f2..d1a6137 100644
--- 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
@@ -16,6 +16,7 @@
 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.RequestMethod;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestController;
@@ -24,8 +25,14 @@
 import com.supwisdom.leaveschool.common.model.PagerRequestModel;
 import com.supwisdom.leaveschool.common.model.PagerResponseModel;
 import com.supwisdom.leaveschool.common.util.DomainUtils;
+import com.supwisdom.leaveschool.user.domain.GroupUser;
 import com.supwisdom.leaveschool.user.domain.User;
+import com.supwisdom.leaveschool.user.domain.UserRole;
+import com.supwisdom.leaveschool.user.model.GroupUsers;
+import com.supwisdom.leaveschool.user.model.UserRoles;
+import com.supwisdom.leaveschool.user.repository.GroupUserRepository;
 import com.supwisdom.leaveschool.user.repository.UserRepository;
+import com.supwisdom.leaveschool.user.repository.UserRoleRepository;
 
 @RestController
 @RequestMapping("/api/v1/admin/users")
@@ -34,21 +41,28 @@
   @Autowired
   private UserRepository userRepository;
 
+  @Autowired
+  private GroupUserRepository groupUserRepository;
+
+  @Autowired
+  private UserRoleRepository userRoleRepository;
+
   @Override
   protected UserRepository getRepository() {
-    
+
     return 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' 
+   * 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: 
+   * response success:
    * 
+   * <pre>
    * {
    *   "pageIndex":0,
    *   "pageSize":20,
@@ -76,9 +90,11 @@
    *     }
    *   ]
    * }
+   * </pre>
    * 
    * response error 401:
    * 
+   * <pre>
    * {
    *   "timestamp":"2018-08-03T08:48:25.777+0000",
    *   "status":401,
@@ -86,6 +102,7 @@
    *   "message":"Unauthorized",
    *   "path":"/api/v1/admin/users"
    * }
+   * </pre>
    * 
    * @param pagerRequestModel
    * @return
@@ -95,26 +112,26 @@
   @ResponseStatus(value = HttpStatus.OK)
   @ResponseBody
   public PagerResponseModel<User> list(PagerRequestModel pagerRequestModel) {
-    
-    Page<User> page = userRepository.selectPageList(pagerRequestModel.getPageIndex(), pagerRequestModel.getPageSize(), pagerRequestModel.getMapBean());
-    
-    @SuppressWarnings("unchecked")
-    List<User> list = IteratorUtils.toList(page.iterator());
-    
+
+    Page<User> page = userRepository.selectPageList(pagerRequestModel.getPageIndex(), pagerRequestModel.getPageSize(),
+        pagerRequestModel.getMapBean());
+
     PagerResponseModel<User> pagerResponseModel = PagerResponseModel.of(pagerRequestModel);
+    pagerResponseModel.setCurrentItemCount(page.getNumberOfElements());
     pagerResponseModel.setPageCount(page.getTotalPages());
     pagerResponseModel.setRecordCount(page.getTotalElements());
-    pagerResponseModel.setItems(list);
-    
+    pagerResponseModel.setItems(page.getContent());
+
     return pagerResponseModel;
   }
-  
+
   /**
    * 
-   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1' 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1'
    * 
-   * response success: 
+   * response success:
    * 
+   * <pre>
    * {
    *   "id":"ff80808164feb8990164feba0de50000",
    *   "companyId":"1",
@@ -133,9 +150,11 @@
    *   "mobile":null,
    *   "email":null
    * }
+   * </pre>
    * 
    * response error 401:
    * 
+   * <pre>
    * {
    *   "timestamp":"2018-08-03T08:43:26.080+0000",
    *   "status":401,
@@ -143,9 +162,11 @@
    *   "message":"Unauthorized",
    *   "path":"/api/v1/admin/users/ff80808164fecf640164fed269480000"
    * }
+   * </pre>
    * 
    * response error 500:
    * 
+   * <pre>
    * {
    *   "timestamp":"2018-08-03T07:44:07.963+0000",
    *   "status":500,
@@ -154,6 +175,7 @@
    *   "message":"exception.get.domain.not.exist",
    *   "path":"/api/v1/admin/users/1"
    * }
+   * </pre>
    * 
    * @param id
    * @return
@@ -163,33 +185,36 @@
   @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
+      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
+      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: 
+   * response success:
    * 
+   * <pre>
    * {
    *   "success":"info.save.success"
    * }
+   * </pre>
    * 
    * response error 401:
    * 
+   * <pre>
    * {
    *   "timestamp":"2018-08-03T08:48:25.777+0000",
    *   "status":401,
@@ -197,9 +222,11 @@
    *   "message":"Unauthorized",
    *   "path":"/api/v1/admin/users"
    * }
+   * </pre>
    * 
    * response error: // FIXME: save error
    * 
+   * <pre>
    * {
    *   "timestamp":"2018-08-03T07:45:43.436+0000",
    *   "status":500,
@@ -208,6 +235,7 @@
    *   "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"
    * }
+   * </pre>
    * 
    * @param user
    * @return
@@ -217,16 +245,16 @@
   @ResponseStatus(value = HttpStatus.OK)
   @ResponseBody
   public Map<String, Object> save(@RequestBody User user) {
-    
+
     @SuppressWarnings("unused")
     User ret = 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' \
@@ -234,12 +262,15 @@
    * 
    * response success:
    * 
+   * <pre>
    * {
    *   "success":"info.update.success"
    * }
+   * </pre>
    * 
    * response error 401:
    * 
+   * <pre>
    * {
    *   "timestamp":"2018-08-03T08:48:25.777+0000",
    *   "status":401,
@@ -247,12 +278,14 @@
    *   "message":"Unauthorized",
    *   "path":"/api/v1/admin/users"
    * }
+   * </pre>
    * 
    * 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:
    * 
+   * <pre>
    * {
    *   "timestamp":"2018-08-03T07:50:52.327+0000",
    *   "status":500,
@@ -261,12 +294,14 @@
    *   "message":"exception.update.id.must.not.empty",
    *   "path":"/api/v1/admin/users"
    * }
+   * </pre>
    * 
    * 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:
    * 
+   * <pre>
    * {
    *   "timestamp":"2018-08-03T07:48:24.774+0000",
    *   "status":500,
@@ -275,6 +310,7 @@
    *   "message":"exception.update.domain.not.exist",
    *   "path":"/api/v1/admin/users"
    * }
+   * </pre>
    * 
    * @param user
    * @return
@@ -284,40 +320,43 @@
   @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
+      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
+      throw new RuntimeException("exception.update.domain.not.exist"); // FIXME: RestException
     }
-    
+
     tmp = DomainUtils.merge(user, tmp);
-    
+
     @SuppressWarnings("unused")
     User ret = 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: 
+   * response success:
    * 
+   * <pre>
    * {
    *   "success":"info.delete.success"
    * }
+   * </pre>
    * 
    * response error 401:
    * 
+   * <pre>
    * {
    *   "timestamp":"2018-08-03T08:48:25.777+0000",
    *   "status":401,
@@ -325,9 +364,11 @@
    *   "message":"Unauthorized",
    *   "path":"/api/v1/admin/users/1"
    * }
+   * </pre>
    * 
-   * response error 500: 
+   * response error 500:
    * 
+   * <pre>
    * {
    *   "timestamp":"2018-08-03T08:03:16.364+0000",
    *   "status":500,
@@ -336,6 +377,7 @@
    *   "message":"exception.delete.domain.not.exist",
    *   "path":"/api/v1/admin/users/1"
    * }
+   * </pre>
    * 
    * @param id
    * @return
@@ -345,21 +387,175 @@
   @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
+      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
+      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;
+  }
+
+  /**
+   * 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1/groups'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1/groups?pageIndex=2&pageSize=50'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1/groups?pageIndex=0&pageSize=20&mapBean[rolecode]=code&mapBean[rolename]=name'
+   * 
+   * 
+   * 
+   * @param id
+   * @param pagerRequestModel
+   * @return
+   */
+  @RequestMapping(value = "/{id}/groups", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public PagerResponseModel<GroupUser> userGroups(@PathVariable("id") String id, PagerRequestModel pagerRequestModel) {
+
+    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
+    }
+
+    if (pagerRequestModel.getMapBean() == null) {
+      pagerRequestModel.setMapBean(new HashMap<String, Object>());
+    }
+    pagerRequestModel.getMapBean().put("username", user.getUsername());
+
+    Page<GroupUser> page = groupUserRepository.selectGroupUsers(pagerRequestModel.getPageIndex(),
+        pagerRequestModel.getPageSize(), pagerRequestModel.getMapBean());
+
+    @SuppressWarnings("unchecked")
+    List<GroupUser> list = IteratorUtils.toList(page.iterator());
+
+    PagerResponseModel<GroupUser> pagerResponseModel = PagerResponseModel.of(pagerRequestModel);
+    pagerResponseModel.setPageCount(page.getTotalPages());
+    pagerResponseModel.setRecordCount(page.getTotalElements());
+    pagerResponseModel.setItems(list);
+
+    return pagerResponseModel;
+  }
+
+  /**
+   * 
+   * curl -i -s -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1/groups' \
+   * -d '{"groupUsers":[{"groupId":"1"},{"groupId":"2"}]}'
+   * 
+   * 
+   * @param id
+   * @param userUsers
+   * @return
+   */
+  @RequestMapping(value = "/{id}/groups", method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public Map<String, Object> relateGroups(@PathVariable("id") String id, @RequestBody GroupUsers groupUsers) {
+
+    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
+    }
+
+    groupUserRepository.relateUserGroups(user, groupUsers.getGroupUsers());
+
+    Map<String, Object> res = new HashMap<String, Object>();
+    res.put("success", "info.set.success");
+
+    return res;
+  }
+
+  /**
+   * 
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1/roles'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1/roles?pageIndex=2&pageSize=50'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1/roles?pageIndex=0&pageSize=20&mapBean[rolecode]=code&mapBean[rolename]=name'
+   * 
+   * 
+   * 
+   * @param id
+   * @param pagerRequestModel
+   * @return
+   */
+  @RequestMapping(value = "/{id}/roles", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public PagerResponseModel<UserRole> userRoles(@PathVariable("id") String id, PagerRequestModel pagerRequestModel) {
+
+    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
+    }
+
+    if (pagerRequestModel.getMapBean() == null) {
+      pagerRequestModel.setMapBean(new HashMap<String, Object>());
+    }
+    pagerRequestModel.getMapBean().put("username", user.getUsername());
+
+    Page<UserRole> page = userRoleRepository.selectUserRoles(pagerRequestModel.getPageIndex(),
+        pagerRequestModel.getPageSize(), pagerRequestModel.getMapBean());
+
+    @SuppressWarnings("unchecked")
+    List<UserRole> list = IteratorUtils.toList(page.iterator());
+
+    PagerResponseModel<UserRole> pagerResponseModel = PagerResponseModel.of(pagerRequestModel);
+    pagerResponseModel.setPageCount(page.getTotalPages());
+    pagerResponseModel.setRecordCount(page.getTotalElements());
+    pagerResponseModel.setItems(list);
+
+    return pagerResponseModel;
+  }
+
+  /**
+   * 
+   * curl -i -s -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' 'http://localhost:10010/api/v1/admin/users/1/roles' \
+   * -d '{"userRoles":[{"rolecode":"role001"},{"rolecode":"role002"}]}'
+   * 
+   * 
+   * @param id
+   * @param userUsers
+   * @return
+   */
+  @RequestMapping(value = "/{id}/roles", method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public Map<String, Object> relateRoles(@PathVariable("id") String id, @RequestBody UserRoles userRoles) {
+
+    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
+    }
+
+    userRoleRepository.relateUserRoles(user, userRoles.getUserRoles());
+
+    Map<String, Object> res = new HashMap<String, Object>();
+    res.put("success", "info.set.success");
+
     return res;
   }
 
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/GroupRole.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/GroupRole.java
new file mode 100644
index 0000000..7e61da5
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/GroupRole.java
@@ -0,0 +1,46 @@
+package com.supwisdom.leaveschool.user.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.leaveschool.common.domain.ABaseDomain;
+
+@Entity
+@Table(name = "TB_U_GROUP_ROLE")
+public class GroupRole extends ABaseDomain {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -3141266845902556712L;
+
+  /**
+   * 用户组ID
+   */
+  @Column(name = "GROUP_ID")
+  private String groupId;
+
+  /**
+   * 角色代码
+   */
+  @Column(name = "ROLECODE")
+  private String rolecode;
+
+  public String getGroupId() {
+    return groupId;
+  }
+
+  public void setGroupId(String groupId) {
+    this.groupId = groupId;
+  }
+
+  public String getRolecode() {
+    return rolecode;
+  }
+
+  public void setRolecode(String rolecode) {
+    this.rolecode = rolecode;
+  }
+
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/GroupUser.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/GroupUser.java
new file mode 100644
index 0000000..82b9323
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/GroupUser.java
@@ -0,0 +1,46 @@
+package com.supwisdom.leaveschool.user.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.leaveschool.common.domain.ABaseDomain;
+
+@Entity
+@Table(name = "TB_U_GROUP_USER")
+public class GroupUser extends ABaseDomain {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -4239845385965871983L;
+
+  /**
+   * 用户组ID
+   */
+  @Column(name = "GROUP_ID")
+  private String groupId;
+
+  /**
+   * 用户名
+   */
+  @Column(name = "USERNAME")
+  private String username;
+
+  public String getGroupId() {
+    return groupId;
+  }
+
+  public void setGroupId(String groupId) {
+    this.groupId = groupId;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+
+  public void setUsername(String username) {
+    this.username = username;
+  }
+
+}
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
index 9a2c0d5..db696e8 100644
--- 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
@@ -15,27 +15,59 @@
    */
   private static final long serialVersionUID = 7955624268022038897L;
 
+  /**
+   * 用户名
+   */
   @Column(name = "USERNAME", unique = true)
   private String username;
+  
+  /**
+   * 密码
+   */
   @Column(name = "PASSWORD")
   private String password;
 
+  /**
+   * 是否可用,1 可用,0 不可用,默认:1
+   */
   @Column(name = "ENABLED")
   private Boolean enabled;
+  /**
+   * 账号未过期,1 未过期,0 过期,默认:1
+   */
   @Column(name = "ACCOUNT_NON_EXPIRED")
   private Boolean accountNonExpired;
+  /**
+   * 账号未锁定,1 未锁定,0 锁定,默认:1
+   */
   @Column(name = "ACCOUNT_NON_LOCKED")
   private Boolean accountNonLocked;
+  /**
+   * 密码未过期,1 未过期,0 过期,默认:1
+   */
   @Column(name = "CREDENTIALS_NON_EXPIRED")
   private Boolean credentialsNonExpired;
 
+  /**
+   * 姓名
+   */
   @Column(name = "NAME")
   private String name;
+  
+  /**
+   * 状态(1 启用,0 停用)
+   */
   @Column(name = "STATUS")
   private String status;
 
+  /**
+   * 登录手机
+   */
   @Column(name = "MOBILE")
   private String mobile;
+  /**
+   * 登录邮箱
+   */
   @Column(name = "EMAIL")
   private String email;
 
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/UserRole.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/UserRole.java
new file mode 100644
index 0000000..d6264b5
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/domain/UserRole.java
@@ -0,0 +1,46 @@
+package com.supwisdom.leaveschool.user.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.leaveschool.common.domain.ABaseDomain;
+
+@Entity
+@Table(name = "TB_U_USER_ROLE")
+public class UserRole extends ABaseDomain {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -6158470486381850942L;
+
+  /**
+   * 用户名
+   */
+  @Column(name = "USERNAME")
+  private String username;
+
+  /**
+   * 角色代码
+   */
+  @Column(name = "ROLECODE")
+  private String rolecode;
+
+  public String getUsername() {
+    return username;
+  }
+
+  public void setUsername(String username) {
+    this.username = username;
+  }
+
+  public String getRolecode() {
+    return rolecode;
+  }
+
+  public void setRolecode(String rolecode) {
+    this.rolecode = rolecode;
+  }
+
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/GroupRoles.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/GroupRoles.java
new file mode 100644
index 0000000..14b8565
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/GroupRoles.java
@@ -0,0 +1,25 @@
+package com.supwisdom.leaveschool.user.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import com.supwisdom.leaveschool.user.domain.GroupRole;
+
+public class GroupRoles implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -5839141864223755990L;
+
+  private List<GroupRole> groupRoles;
+
+  public List<GroupRole> getGroupRoles() {
+    return groupRoles;
+  }
+
+  public void setGroupRoles(List<GroupRole> groupRoles) {
+    this.groupRoles = groupRoles;
+  }
+
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/GroupUsers.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/GroupUsers.java
new file mode 100644
index 0000000..205b3a8
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/GroupUsers.java
@@ -0,0 +1,25 @@
+package com.supwisdom.leaveschool.user.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import com.supwisdom.leaveschool.user.domain.GroupUser;
+
+public class GroupUsers implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8195230337021165172L;
+
+  private List<GroupUser> groupUsers;
+
+  public List<GroupUser> getGroupUsers() {
+    return groupUsers;
+  }
+
+  public void setGroupUsers(List<GroupUser> groupUsers) {
+    this.groupUsers = groupUsers;
+  }
+
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/UserRoles.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/UserRoles.java
new file mode 100644
index 0000000..e17bd2f
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/model/UserRoles.java
@@ -0,0 +1,25 @@
+package com.supwisdom.leaveschool.user.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import com.supwisdom.leaveschool.user.domain.UserRole;
+
+public class UserRoles implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5444997122746118950L;
+
+  private List<UserRole> userRoles;
+
+  public List<UserRole> getUserRoles() {
+    return userRoles;
+  }
+
+  public void setUserRoles(List<UserRole> userRoles) {
+    this.userRoles = userRoles;
+  }
+
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/GroupRoleRepository.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/GroupRoleRepository.java
new file mode 100644
index 0000000..fb83e07
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/GroupRoleRepository.java
@@ -0,0 +1,149 @@
+package com.supwisdom.leaveschool.user.repository;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.leaveschool.common.repository.BaseJpaRepository;
+import com.supwisdom.leaveschool.common.util.MapBeanUtils;
+import com.supwisdom.leaveschool.user.domain.Group;
+import com.supwisdom.leaveschool.user.domain.GroupRole;
+import com.supwisdom.leaveschool.user.domain.Role;
+
+@Repository
+public interface GroupRoleRepository extends BaseJpaRepository<GroupRole> {
+
+  public default Page<GroupRole> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+    GroupRole probe = new GroupRole();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setRolecode(MapBeanUtils.getString(mapBean, "rolecode"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("rolecode", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    Page<GroupRole> page = this.findAll(example, pageRequest);
+
+    return page;
+  }
+
+  public default Page<GroupRole> selectGroupRoles(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    GroupRole probe = new GroupRole();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setRolecode(MapBeanUtils.getString(mapBean, "rolecode"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("rolecode", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<GroupRole> page = this.findAll(example, pageRequest);  // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public default void relateGroupRoles(Group group, List<GroupRole> groupRoles) {
+
+    List<GroupRole> existGroupRoles = this.selectListByGroupId(group.getId());
+
+    Map<String, GroupRole> existMapGroupRoles = new LinkedHashMap<String, GroupRole>();
+    for (GroupRole groupRole : existGroupRoles) {
+      String k = String.format("%s", groupRole.getRolecode());
+      existMapGroupRoles.put(k, groupRole);
+    }
+
+    for (GroupRole groupRole : groupRoles) {
+      String k = String.format("%s", groupRole.getRolecode());
+
+      if (existMapGroupRoles.containsKey(k)) {
+        existMapGroupRoles.remove(k);
+      } else {
+        groupRole.setCompanyId(group.getCompanyId());
+        groupRole.setGroupId(group.getId());
+
+        this.insert(groupRole);
+      }
+    }
+
+    for (GroupRole groupRole : existMapGroupRoles.values()) {
+      this.deleteById(groupRole.getId());
+    }
+  }
+
+  public default List<GroupRole> selectListByGroupId(String groupId) {
+
+    GroupRole probe = new GroupRole();
+    probe.setGroupId(groupId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("groupId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    List<GroupRole> groupRoles = this.findAll(example);
+
+    return groupRoles;
+  }
+
+
+  public default void relateRoleGroups(Role role, List<GroupRole> groupRoles) {
+
+    List<GroupRole> existRoleGroups = this.selectListByRolecode(role.getCode());
+
+    Map<String, GroupRole> existMapRoleGroups = new LinkedHashMap<String, GroupRole>();
+    for (GroupRole groupRole : existRoleGroups) {
+      String k = String.format("%s", groupRole.getGroupId());
+      existMapRoleGroups.put(k, groupRole);
+    }
+
+    for (GroupRole groupRole : groupRoles) {
+      String k = String.format("%s", groupRole.getGroupId());
+
+      if (existMapRoleGroups.containsKey(k)) {
+        existMapRoleGroups.remove(k);
+      } else {
+        groupRole.setCompanyId(role.getCompanyId());
+        groupRole.setRolecode(role.getCode());
+
+        this.insert(groupRole);
+      }
+    }
+
+    for (GroupRole groupRole : existMapRoleGroups.values()) {
+      this.deleteById(groupRole.getId());
+    }
+  }
+
+  public default List<GroupRole> selectListByRolecode(String rolecode) {
+
+    GroupRole probe = new GroupRole();
+    probe.setRolecode(rolecode);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("rolecode", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    List<GroupRole> groupRoles = this.findAll(example);
+
+    return groupRoles;
+  }
+
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/GroupUserRepository.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/GroupUserRepository.java
new file mode 100644
index 0000000..ae28e04
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/GroupUserRepository.java
@@ -0,0 +1,150 @@
+package com.supwisdom.leaveschool.user.repository;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.leaveschool.common.repository.BaseJpaRepository;
+import com.supwisdom.leaveschool.common.util.MapBeanUtils;
+import com.supwisdom.leaveschool.user.domain.Group;
+import com.supwisdom.leaveschool.user.domain.GroupUser;
+import com.supwisdom.leaveschool.user.domain.User;
+
+@Repository
+public interface GroupUserRepository extends BaseJpaRepository<GroupUser> {
+
+  public default Page<GroupUser> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+    GroupUser probe = new GroupUser();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setUsername(MapBeanUtils.getString(mapBean, "username"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupUser> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<GroupUser> page = this.findAll(example, pageRequest);
+
+    return page;
+  }
+
+  public default Page<GroupUser> selectGroupUsers(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    GroupUser probe = new GroupUser();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setUsername(MapBeanUtils.getString(mapBean, "username"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupUser> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<GroupUser> page = this.findAll(example, pageRequest);  // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public default void relateGroupUsers(Group group, List<GroupUser> groupUsers) {
+
+    List<GroupUser> existGroupUsers = this.selectListByGroupId(group.getId());
+
+    Map<String, GroupUser> existMapGroupUsers = new LinkedHashMap<String, GroupUser>();
+    for (GroupUser groupUser : existGroupUsers) {
+      String k = String.format("%s", groupUser.getUsername());
+      existMapGroupUsers.put(k, groupUser);
+    }
+
+    for (GroupUser groupUser : groupUsers) {
+      String k = String.format("%s", groupUser.getUsername());
+
+      if (existMapGroupUsers.containsKey(k)) {
+        existMapGroupUsers.remove(k);
+      } else {
+        groupUser.setCompanyId(group.getCompanyId());
+        groupUser.setGroupId(group.getId());
+
+        this.insert(groupUser);
+      }
+    }
+
+    for (GroupUser groupUser : existMapGroupUsers.values()) {
+      this.deleteById(groupUser.getId());
+    }
+  }
+
+  public default List<GroupUser> selectListByGroupId(String groupId) {
+
+    GroupUser probe = new GroupUser();
+    probe.setGroupId(groupId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupUser> example = Example.of(probe, matcher);
+
+    List<GroupUser> groupUsers = this.findAll(example);
+
+    return groupUsers;
+  }
+
+
+  public default void relateUserGroups(User user, List<GroupUser> groupUsers) {
+
+    List<GroupUser> existUserGroups = this.selectListByUsername(user.getUsername());
+
+    Map<String, GroupUser> existMapUserGroups = new LinkedHashMap<String, GroupUser>();
+    for (GroupUser groupUser : existUserGroups) {
+      String k = String.format("%s", groupUser.getGroupId());
+      existMapUserGroups.put(k, groupUser);
+    }
+
+    for (GroupUser groupUser : groupUsers) {
+      String k = String.format("%s", groupUser.getGroupId());
+
+      if (existMapUserGroups.containsKey(k)) {
+        existMapUserGroups.remove(k);
+      } else {
+        groupUser.setCompanyId(user.getCompanyId());
+        groupUser.setUsername(user.getUsername());
+
+        this.insert(groupUser);
+      }
+    }
+
+    for (GroupUser groupUser : existMapUserGroups.values()) {
+      this.deleteById(groupUser.getId());
+    }
+  }
+
+  public default List<GroupUser> selectListByUsername(String username) {
+
+    GroupUser probe = new GroupUser();
+    probe.setUsername(username);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupUser> example = Example.of(probe, matcher);
+
+    List<GroupUser> groupUsers = this.findAll(example);
+
+    return groupUsers;
+  }
+
+}
diff --git a/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/UserRoleRepository.java b/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/UserRoleRepository.java
new file mode 100644
index 0000000..aabefc8
--- /dev/null
+++ b/samples/user/src/main/java/com/supwisdom/leaveschool/user/repository/UserRoleRepository.java
@@ -0,0 +1,150 @@
+package com.supwisdom.leaveschool.user.repository;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.leaveschool.common.repository.BaseJpaRepository;
+import com.supwisdom.leaveschool.common.util.MapBeanUtils;
+import com.supwisdom.leaveschool.user.domain.Role;
+import com.supwisdom.leaveschool.user.domain.User;
+import com.supwisdom.leaveschool.user.domain.UserRole;
+
+@Repository
+public interface UserRoleRepository extends BaseJpaRepository<UserRole> {
+
+  public default Page<UserRole> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    UserRole probe = new UserRole();
+    if (mapBean != null) {
+      probe.setUsername(MapBeanUtils.getString(mapBean, "username"));
+      probe.setRolecode(MapBeanUtils.getString(mapBean, "rolecode"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("rolecode", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<UserRole> example = Example.of(probe, matcher);
+
+    Page<UserRole> page = this.findAll(example, pageRequest);
+
+    return page;
+  }
+
+  public default Page<UserRole> selectUserRoles(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    UserRole probe = new UserRole();
+    if (mapBean != null) {
+      probe.setUsername(MapBeanUtils.getString(mapBean, "username"));
+      probe.setRolecode(MapBeanUtils.getString(mapBean, "rolecode"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("rolecode", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<UserRole> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<UserRole> page = this.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public default void relateUserRoles(User user, List<UserRole> userRoles) {
+
+    List<UserRole> existUserRoles = this.selectListByUsername(user.getUsername());
+
+    Map<String, UserRole> existMapUserRoles = new LinkedHashMap<String, UserRole>();
+    for (UserRole userRole : existUserRoles) {
+      String k = String.format("%s", userRole.getRolecode());
+      existMapUserRoles.put(k, userRole);
+    }
+
+    for (UserRole userRole : userRoles) {
+      String k = String.format("%s", userRole.getRolecode());
+
+      if (existMapUserRoles.containsKey(k)) {
+        existMapUserRoles.remove(k);
+      } else {
+        userRole.setCompanyId(user.getCompanyId());
+        userRole.setUsername(user.getUsername());
+
+        this.insert(userRole);
+      }
+    }
+
+    for (UserRole userRole : existMapUserRoles.values()) {
+      this.deleteById(userRole.getId());
+    }
+  }
+
+  public default List<UserRole> selectListByUsername(String username) {
+
+    UserRole probe = new UserRole();
+    probe.setUsername(username);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<UserRole> example = Example.of(probe, matcher);
+
+    List<UserRole> userRoles = this.findAll(example);
+
+    return userRoles;
+  }
+
+  
+  public default void relateRoleUsers(Role role, List<UserRole> userRoles) {
+
+    List<UserRole> existRoleUsers = this.selectListByRolecode(role.getCode());
+
+    Map<String, UserRole> existMapRoleUsers = new LinkedHashMap<String, UserRole>();
+    for (UserRole userRole : existRoleUsers) {
+      String k = String.format("%s", userRole.getUsername());
+      existMapRoleUsers.put(k, userRole);
+    }
+
+    for (UserRole userRole : userRoles) {
+      String k = String.format("%s", userRole.getUsername());
+
+      if (existMapRoleUsers.containsKey(k)) {
+        existMapRoleUsers.remove(k);
+      } else {
+        userRole.setCompanyId(role.getCompanyId());
+        userRole.setRolecode(role.getCode());
+
+        this.insert(userRole);
+      }
+    }
+
+    for (UserRole userRole : existMapRoleUsers.values()) {
+      this.deleteById(userRole.getId());
+    }
+  }
+
+  public default List<UserRole> selectListByRolecode(String rolecode) {
+
+    UserRole probe = new UserRole();
+    probe.setRolecode(rolecode);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("rolecode", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<UserRole> example = Example.of(probe, matcher);
+
+    List<UserRole> userRoles = this.findAll(example);
+
+    return userRoles;
+  }
+
+}
diff --git a/sql/user.sql b/sql/user.sql
index 40214e5..3304062 100644
--- a/sql/user.sql
+++ b/sql/user.sql
@@ -25,8 +25,115 @@
   `MOBILE` VARCHAR(100) COMMENT '登录手机',
   `EMAIL` VARCHAR(100) COMMENT '登录邮箱',
 
-
   PRIMARY KEY (`ID`),
   UNIQUE KEY `UQ_USERNAME` (`USERNAME`)
 )
 COMMENT = '用户表';
+
+
+
+CREATE TABLE `TB_U_GROUP` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `CODE` VARCHAR(200) NOT NULL COMMENT '代码',
+  `NAME` VARCHAR(200) NOT NULL COMMENT '名称',
+  `MEMO` VARCHAR(500) COMMENT '备注',
+  `STATUS` VARCHAR(10) NOT NULL COMMENT '状态(1 启用,0 停用)',
+
+  PRIMARY KEY (`ID`),
+  UNIQUE KEY `UQ_CODE` (`COMPANY_ID`,`CODE`)
+)
+COMMENT = '用户组表';
+
+
+
+CREATE TABLE `TB_U_ROLE` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `CODE` VARCHAR(200) NOT NULL COMMENT '代码',
+  `NAME` VARCHAR(200) NOT NULL COMMENT '名称',
+  `MEMO` VARCHAR(500) COMMENT '备注',
+  `STATUS` VARCHAR(10) NOT NULL COMMENT '状态(1 启用,0 停用)',
+
+  PRIMARY KEY (`ID`),
+  UNIQUE KEY `UQ_CODE` (`COMPANY_ID`,`CODE`)
+)
+COMMENT = '角色表';
+
+
+
+CREATE TABLE `TB_U_GROUP_USER` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `GROUP_ID` VARCHAR(200) NOT NULL COMMENT '用户组ID',
+  `USERNAME` VARCHAR(200) NOT NULL COMMENT '用户名',
+
+  PRIMARY KEY (`ID`)
+)
+COMMENT = '用户组 - 用户表';
+
+
+CREATE TABLE `TB_U_USER_ROLE` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `USERNAME` VARCHAR(200) NOT NULL COMMENT '用户名',
+  `ROLECODE` VARCHAR(200) NOT NULL COMMENT '角色代码',
+
+  PRIMARY KEY (`ID`)
+)
+COMMENT = '用户 - 角色表';
+
+
+
+CREATE TABLE `TB_U_GROUP_ROLE` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `GROUP_ID` VARCHAR(200) NOT NULL COMMENT '用户组ID',
+  `ROLECODE` VARCHAR(200) NOT NULL COMMENT '角色代码',
+
+  PRIMARY KEY (`ID`)
+)
+COMMENT = '用户组 - 角色表';
+
+
+