实现基于中间表的多对多关联的注解绑定

This commit is contained in:
mazhicheng 2019-05-25 13:55:08 +08:00
parent 5a5143cde6
commit 87342883eb
23 changed files with 306 additions and 516 deletions

View File

@ -64,30 +64,37 @@ public class EntityBinder<T> extends BaseBinder<T> {
return;
}
if(referencedEntityPrimaryKey == null){
log.warn("调用错误:必须调用joinOn()方法连接两个字段.");
log.warn("调用错误:无法从condition中解析出字段关联.");
}
// 提取主键pk列表
// 提取注解条件中指定的对应的列表
String annoObjectForeignKeyField = S.toLowerCaseCamel(annoObjectForeignKey);
List annoObjectForeignKeyList = BeanUtils.collectToList(annoObjectList, annoObjectForeignKeyField);
if(V.isEmpty(annoObjectForeignKeyList)){
return;
}
// 解析中间表查询关联
// 通过中间表关联Entity
// @BindEntity(entity = Organization.class, condition = "this.department_id=department.id AND department.org_id=id AND department.deleted=0")
// Organization organization;
if(middleTable != null){
// 提取中间表查询SQL
String sql = middleTable.toSQL(annoObjectForeignKeyList);
// 执行查询并合并结果
String keyName = middleTable.getEqualsToRefEntityPkColumn(), valueName = middleTable.getEqualsToAnnoObjectFKColumn();
Map<Object, Object> middleTableResultMap = SqlExecutor.executeQueryAndMergeResult(sql, annoObjectForeignKeyList, keyName, valueName);
Map<String, List> middleTableResultMap = SqlExecutor.executeQueryAndMergeResult(sql, annoObjectForeignKeyList, keyName, valueName);
if(V.notEmpty(middleTableResultMap)){
// 提取entity主键值集合
Collection middleTableColumnValueList = middleTableResultMap.keySet();
// 构建查询条件
queryWrapper.in(S.toSnakeCase(referencedEntityPrimaryKey), middleTableColumnValueList);
// 查询entity列表
List<T> list = referencedService.getEntityList(queryWrapper);
// 绑定结果
bindingResult(S.toLowerCaseCamel(referencedEntityPrimaryKey), list, middleTableResultMap);
// 基于中间表查询结果和entity列表绑定结果
bindingResultWithMiddleTable(S.toLowerCaseCamel(referencedEntityPrimaryKey), list, middleTableResultMap);
}
}
// 直接关联Entity
// @BindEntity(entity = Department.class, condition="department_id=id")
// Department department;
else{
// 构建查询条件
queryWrapper.in(S.toSnakeCase(referencedEntityPrimaryKey), annoObjectForeignKeyList);
@ -99,20 +106,23 @@ public class EntityBinder<T> extends BaseBinder<T> {
}
/***
* 绑定结果
* 基于中间表查询结果和entity列表绑定结果
* @param doPkPropName
* @param list
*/
protected void bindingResult(String doPkPropName, List<T> list, Map<Object, Object> middleTableResultMap) {
Map<String, T> valueEntityMap = new HashMap<>(list.size());
for(T entity : list){
Object pkValue = BeanUtils.getProperty(entity, doPkPropName);
Object annoObjFK = middleTableResultMap.get(pkValue);
if(annoObjFK != null){
valueEntityMap.put(String.valueOf(annoObjFK), entity);
private <E> void bindingResultWithMiddleTable(String doPkPropName, List<E> list, Map<String, List> middleTableResultMap) {
// 构建IdString-Entity之间的映射Map
Map<String, E> valueEntityMap = new HashMap<>(list.size());
for(E entity : list){
// 获取主键值
String pkValue = BeanUtils.getStringProperty(entity, doPkPropName);
// 得到对应Entity
List annoObjFKList = middleTableResultMap.get(pkValue);
if(V.notEmpty(annoObjFKList)){
valueEntityMap.put(String.valueOf(annoObjFKList.get(0)), entity);
}
else{
log.warn("转换结果异常,中间关联条件数据不一致");
log.warn("{}.{}={} 无匹配结果!", entity.getClass().getSimpleName(), doPkPropName, pkValue);
}
}
// 绑定
@ -124,11 +134,11 @@ public class EntityBinder<T> extends BaseBinder<T> {
* @param doPkPropName
* @param list
*/
protected void bindingResult(String doPkPropName, List<T> list) {
Map<Object, T> valueEntityMap = new HashMap<>(list.size());
private void bindingResult(String doPkPropName, List<T> list) {
Map<String, T> valueEntityMap = new HashMap<>(list.size());
for(T entity : list){
Object pkValue = BeanUtils.getProperty(entity, doPkPropName);
valueEntityMap.put(String.valueOf(pkValue), entity);
String pkValue = BeanUtils.getStringProperty(entity, doPkPropName);
valueEntityMap.put(pkValue, entity);
}
// 绑定
BeanUtils.bindPropValueOfList(annoObjectField, annoObjectList, annoObjectForeignKey, valueEntityMap);

View File

@ -3,15 +3,16 @@ package com.diboot.core.binding;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.diboot.core.service.BaseService;
import com.diboot.core.util.BeanUtils;
import com.diboot.core.util.S;
import com.diboot.core.util.SqlExecutor;
import com.diboot.core.util.V;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* Entity集合绑定实现
* @author Mazhicheng
* @version v2.0
* @date 2019/1/19
@ -31,7 +32,92 @@ public class EntityListBinder<T> extends EntityBinder<T> {
}
@Override
protected void bindingResult(String fkName, List<T> list) {
public void bind() {
if(V.isEmpty(annoObjectList)){
return;
}
if(referencedEntityPrimaryKey == null){
log.warn("调用错误无法从condition中解析出字段关联.");
}
// 提取主键pk列表
String annoObjectForeignKeyField = S.toLowerCaseCamel(annoObjectForeignKey);
List annoObjectForeignKeyList = BeanUtils.collectToList(annoObjectList, annoObjectForeignKeyField);
if(V.isEmpty(annoObjectForeignKeyList)){
return;
}
// 解析中间表查询 1-N关联
//User.class @BindEntityList(entity = Role.class, condition="this.id=user_role.user_id AND user_role.role_id=id")
if(middleTable != null){
// 构建查询SQL SELECT user_id, role_id FROM user_role WHERE user_id IN (?)
String sql = middleTable.toSQL(annoObjectForeignKeyList);
// 执行查询并合并结果
String valueName = middleTable.getEqualsToRefEntityPkColumn(), keyName = middleTable.getEqualsToAnnoObjectFKColumn();
Map<String, List> middleTableResultMap = SqlExecutor.executeQueryAndMergeResult(sql, annoObjectForeignKeyList, keyName, valueName);
if(V.notEmpty(middleTableResultMap)){
// 收集查询结果values集合
List entityIdList = new ArrayList();
for(Map.Entry<String, List> entry : middleTableResultMap.entrySet()){
if(V.notEmpty(entry.getValue())){
for(Object id : entry.getValue()){
if(!entityIdList.contains(id)){
entityIdList.add(id);
}
}
}
}
// 构建查询条件
queryWrapper.in(S.toSnakeCase(referencedEntityPrimaryKey), entityIdList);
// 查询entity列表: List<Role>
List list = referencedService.getEntityList(queryWrapper);
// 绑定结果
bindingResultWithMiddleTable(S.toLowerCaseCamel(annoObjectForeignKey), list, middleTableResultMap);
}
}
else{
// 构建查询条件
queryWrapper.in(S.toSnakeCase(referencedEntityPrimaryKey), annoObjectForeignKeyList);
// 查询entity列表
List<T> list = referencedService.getEntityList(queryWrapper);
// 绑定结果
bindingResult(S.toLowerCaseCamel(referencedEntityPrimaryKey), list);
}
}
/***
* 基于中间表查询结果和entity列表绑定结果
* @param annoObjectForeignKey
* @param list
*/
private <E> void bindingResultWithMiddleTable(String annoObjectForeignKey, List<E> list, Map<String, List> middleTableResultMap) {
if(V.isEmpty(list)){
return;
}
// List<Role> 转换为 Map<Id,Role>
Map<String, E> entityMap = BeanUtils.convertToStringKeyObjectMap(list, annoObjectForeignKey);
// 将Map<String, List<Id>> 转换为 Map<String, List<Role>>
Map<String, List<E>> valueEntityMap = new HashMap<>(list.size());
for(Map.Entry<String, List> entry : middleTableResultMap.entrySet()){
// List<roleId>
List annoObjFKList = entry.getValue();
if(V.notEmpty(annoObjFKList)){
List<E> valueList = new ArrayList();
for(Object obj : annoObjFKList){
E ent = entityMap.get(String.valueOf(obj));
if(ent != null){
valueList.add(ent);
}
}
valueEntityMap.put(entry.getKey(), valueList);
}
else{
log.warn("转换结果异常,中间关联条件数据不一致");
}
}
// 绑定
BeanUtils.bindPropValueOfList(annoObjectField, annoObjectList, annoObjectForeignKey, valueEntityMap);
}
private void bindingResult(String fkName, List<T> list) {
Map<Object, List<T>> valueEntityListMap = new HashMap<>(list.size());
for(T entity : list){
Object keyValue = BeanUtils.getProperty(entity, fkName);

View File

@ -77,13 +77,6 @@ public class MiddleTable {
if(V.isEmpty(annoObjectForeignKeyList)){
return null;
}
Object object = annoObjectForeignKeyList.get(0);
// 不需要加引号的类型
boolean noQuotes = object instanceof Integer
|| object instanceof Long
|| object instanceof Double
|| object instanceof Float
|| object instanceof BigDecimal;
// 构建SQL
StringBuilder sb = new StringBuilder();
sb.append("SELECT ").append(this.equalsToAnnoObjectFKColumn).append(Cons.SEPARATOR_COMMA)

View File

@ -183,8 +183,8 @@ public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl
@Override
public List<KeyValue> getKeyValueList(Wrapper queryWrapper) {
String sqlSelect = queryWrapper.getSqlSelect();
if(V.isEmpty(sqlSelect) || S.countMatches(sqlSelect, Cons.SEPARATOR_COMMA) != 1){
log.error("调用错误: getKeyValueList必须用select依次指定返回的键值字段,如: new QueryWrapper<Metadata>().lambda().select(Metadata::getItemName, Metadata::getItemValue)");
if(V.isEmpty(sqlSelect) || S.countMatches(sqlSelect, Cons.SEPARATOR_COMMA) > 2){
log.error("调用错误: getKeyValueList必须用select依次指定返回的Key,Value, ext键值字段,如: new QueryWrapper<Metadata>().lambda().select(Metadata::getItemName, Metadata::getItemValue)");
return Collections.emptyList();
}
// 获取mapList
@ -198,6 +198,9 @@ public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl
for(Map<String, Object> map : mapList){
if(map.get(keyValueArray[0]) != null){
KeyValue kv = new KeyValue((String)map.get(keyValueArray[0]), map.get(keyValueArray[1]));
if(keyValueArray.length > 2){
kv.setExt(map.get(keyValueArray[2]));
}
keyValueList.add(kv);
}
}

View File

@ -196,6 +196,20 @@ public class BeanUtils {
return wrapper.getPropertyValue(field);
}
/***
* 获取对象的属性值并转换为String
* @param obj
* @param field
* @return
*/
public static String getStringProperty(Object obj, String field){
Object property = getProperty(obj, field);
if(property == null){
return null;
}
return String.valueOf(property);
}
/***
* 设置属性值
* @param obj
@ -212,22 +226,22 @@ public class BeanUtils {
* @param allLists
* @return
*/
public static <T> Map<Object, T> convert2KeyObjectMap(List<T> allLists, String... fields){
public static <T> Map<String, T> convertToStringKeyObjectMap(List<T> allLists, String... fields){
if(allLists == null || allLists.isEmpty()){
return null;
}
Map<Object, T> allListMap = new LinkedHashMap<>(allLists.size());
Map<String, T> allListMap = new LinkedHashMap<>(allLists.size());
// 转换为map
try{
for(T model : allLists){
Object key = null;
String key = null;
if(V.isEmpty(fields)){
//未指定字段以id为key
key = getProperty(model, Cons.FieldName.parentId.name());;
key = getStringProperty(model, Cons.FieldName.parentId.name());
}
// 指定了一个字段以该字段为key类型同该字段
else if(fields.length == 1){
key = getProperty(model, fields[0]);
key = getStringProperty(model, fields[0]);
}
else{ // 指定了多个字段以字段S.join的结果为key类型为String
List list = new ArrayList();
@ -240,7 +254,7 @@ public class BeanUtils {
allListMap.put(key, model);
}
else{
log.warn(model.getClass().getName() + " 的属性 "+fields[0]+" 值存在 nullBeanUtils.convert2KeyModelMap转换结果需要确认!");
log.warn(model.getClass().getName() + " 的属性 "+fields[0]+" 值存在 null转换结果需要确认!");
}
}
}
@ -285,10 +299,10 @@ public class BeanUtils {
*/
private static <T extends BaseEntity> void buildDeeperLevelTree(List<T> parentModels, List<T> allModels){
List<T> deeperLevelModels = new ArrayList();
Map<Object, T> parentLevelModelMap = convert2KeyObjectMap(parentModels);
Map<String, T> parentLevelModelMap = convertToStringKeyObjectMap(parentModels);
for(T model : allModels){
Object parentId = getProperty(model, Cons.FieldName.parentId.name());
if(parentLevelModelMap.keySet().contains(parentId) && !parentId.equals(model.getId())){
if(parentLevelModelMap.keySet().contains(String.valueOf(parentId)) && !parentId.equals(model.getId())){
deeperLevelModels.add(model);
}
}
@ -297,7 +311,7 @@ public class BeanUtils {
}
for(T model : deeperLevelModels){
Object parentId = getProperty(model, Cons.FieldName.parentId.name());
T parentModel = parentLevelModelMap.get(parentId);
T parentModel = parentLevelModelMap.get(String.valueOf(parentId));
if(parentModel!=null){
List children = (List) getProperty(parentModel, Cons.FieldName.children.name());
if(children == null){
@ -454,9 +468,9 @@ public class BeanUtils {
try{
for(E object : fromList){
// 获取到当前的属性值
Object fieldValue = getProperty(object, getterFieldName);
String fieldValue = getStringProperty(object, getterFieldName);
// 获取到当前的value
Object value = valueMatchMap.get(String.valueOf(fieldValue));
Object value = valueMatchMap.get(fieldValue);
// 赋值
setProperty(object, setterFieldName, value);
}

View File

@ -6,10 +6,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* 原生SQL执行类
@ -21,11 +18,12 @@ public class SqlExecutor {
private static final Logger log = LoggerFactory.getLogger(SqlExecutor.class);
/***
* 执行Select语句
* 执行Select语句: SELECT user_id,role_id FROM user_role WHERE user_id IN (?,?,?,?)
* 查询结果如: [{"user_id":1001,"role_id":101},{"user_id":1001,"role_id":102},{"user_id":1003,"role_id":102},{"user_id":1003,"role_id":103}]
* @param sql
* @return
*/
public static List<Map<String,Object>> executeQuery(String sql, List params) throws Exception{
public static <E> List<Map<String,E>> executeQuery(String sql, List<E> params) throws Exception{
if(V.isEmpty(sql)){
return null;
}
@ -36,8 +34,10 @@ public class SqlExecutor {
return null;
}
// 替换单个?参数为多个用于拼接IN参数
if(sql.contains("?") && V.notEmpty(params)){
sql = S.replace(sql, "?", S.repeat("?", ",", params.size()));
if(V.notEmpty(params)){
if(params.size() > 2000){
log.warn("查询参数集合数量过多, size={},请检查调用是否合理!", params.size());
}
}
log.debug("执行查询SQL: "+sql);
try(SqlSession session = sqlSessionFactory.openSession(); Connection conn = session.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql)){
@ -48,13 +48,13 @@ public class SqlExecutor {
}
ResultSet rs = stmt.executeQuery();
ResultSetMetaData meta = rs.getMetaData();
List<Map<String,Object>> mapList = new ArrayList<>();
List<Map<String,E>> mapList = new ArrayList<>();
if(meta.getColumnCount() > 0){
// 添加数据行
while(rs.next()){
Map<String,Object> dataRow = new HashMap<>();
Map<String,E> dataRow = new HashMap<>();
for(int i=1; i<=meta.getColumnCount(); i++){
dataRow.put(meta.getColumnLabel(i), rs.getObject(i));
dataRow.put(meta.getColumnLabel(i), (E)rs.getObject(i));
}
mapList.add(dataRow);
}
@ -69,14 +69,16 @@ public class SqlExecutor {
}
}
/**
* 执行查询和合并结果
* 执行查询和合并结果并将结果Map的key类型转成String
*
* @param sql
* @param params
* @return
*/
public static Map<Object, Object> executeQueryAndMergeResult(String sql, List params, String keyName, String valueName){
List<Map<String,Object>> resultSetMapList = null;
public static <E> Map<String, List> executeQueryAndMergeResult(String sql, List<E> params, String keyName, String valueName){
List<Map<String, E>> resultSetMapList = null;
try {
resultSetMapList = executeQuery(sql, params);
}
@ -84,10 +86,16 @@ public class SqlExecutor {
log.warn("执行查询异常", e);
}
// 合并list为map
Map<Object, Object> resultMap = new HashMap<>();
Map<String, List> resultMap = new HashMap<>();
if(V.notEmpty(resultSetMapList)){
for(Map<String, Object> row : resultSetMapList){
resultMap.put(row.get(keyName), row.get(valueName));
for(Map<String, E> row : resultSetMapList){
String key = String.valueOf(row.get(keyName));
List valueList = resultMap.get(key);
if(valueList == null){
valueList = new ArrayList();
resultMap.put(key, valueList);
}
valueList.add(row.get(valueName));
}
}
return resultMap;

View File

@ -30,9 +30,6 @@ public class JsonResult implements Serializable {
* 默认成功无返回数据
*/
public JsonResult(){
this.code = Status.OK.code();
this.msg = Status.OK.label();
this.data = null;
}
/**

View File

@ -28,6 +28,11 @@ public class KeyValue implements Serializable {
*/
private Object v;
/**
* 扩展值
*/
private Object ext;
public String getK() {
return k;
}
@ -43,4 +48,12 @@ public class KeyValue implements Serializable {
public void setV(Object v) {
this.v = v;
}
public Object getExt() {
return ext;
}
public void setExt(Object ext) {
this.ext = ext;
}
}

View File

@ -68,7 +68,7 @@ public class DepartmentController extends BaseCrudRestController {
@GetMapping("/kv")
public JsonResult getKVPairList(HttpServletRequest request){
Wrapper wrapper = new QueryWrapper<Department>().lambda()
.select(Department::getName, Department::getId);
.select(Department::getName, Department::getId, Department::getCode);
List<KeyValue> list = departmentService.getKeyValueList(wrapper);
return new JsonResult(list);
}

View File

@ -1,161 +0,0 @@
package com.diboot.example.controller;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.diboot.core.controller.BaseCrudRestController;
import com.diboot.core.service.BaseService;
import com.diboot.core.util.BeanUtils;
import com.diboot.core.util.JSON;
import com.diboot.core.vo.JsonResult;
import com.diboot.core.vo.KeyValue;
import com.diboot.core.vo.Status;
import com.diboot.example.entity.Department;
import com.diboot.example.entity.Employee;
import com.diboot.example.entity.Organization;
import com.diboot.example.service.EmployeeService;
import com.diboot.example.vo.DepartmentVO;
import com.diboot.example.vo.EmployeeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
/**
* Organization相关Controller
* @author Mazhicheng
* @version 2018/12/23
* Copyright © www.dibo.ltd
*/
@RestController
@RequestMapping("/employee")
public class EmployeeController extends BaseCrudRestController {
@Autowired
private EmployeeService employeeService;
@GetMapping("/test")
public JsonResult test(HttpServletRequest request) throws Exception{
// List<Long> userIdList = new ArrayList<>();
// userIdList.add(1001L);
// userIdList.add(1003L);
// String sql = "SELECT user_id, role_id FROM user_role WHERE user_id IN (?)";
// List<Map<String, Object>> list = SqlExecutor.executeQuery(sql, userIdList);
List<Long> userIdList = new ArrayList<>();
userIdList.add(1L);
QueryWrapper<Employee> queryWrapper = new QueryWrapper<Employee>();
//IN条件一定不能为空否则就会删除整张表数据
queryWrapper.in("id", userIdList);
System.out.println(JSON.stringify(queryWrapper));
employeeService.deleteEntities(queryWrapper)
;
userIdList.clear();
queryWrapper = new QueryWrapper<Employee>();
queryWrapper.in("id", userIdList);
employeeService.deleteEntities(queryWrapper);
return new JsonResult();
}
/***
* 默认的分页实现
* <p>
* url参数示例: /list?_pageSize=20&_pageIndex=1&_orderBy=itemValue&type=GENDAR
* </p>
* @return
* @throws Exception
*/
@GetMapping("/list")
public JsonResult getDefaultVOList(HttpServletRequest request) throws Exception{
QueryWrapper<Department> queryWrapper = buildQuery(request);
return super.getEntityListWithPaging(request, queryWrapper, DepartmentVO.class);
}
/***
* 默认的分页实现
* <p>
* url参数示例: /listVo?page.size=20&page.index=1&page.orderBy=itemValue&type=GENDAR
* </p>
* @return
* @throws Exception
*/
@GetMapping("/listVo")
public JsonResult getCustomVOList(HttpServletRequest request) throws Exception{
QueryWrapper<Employee> queryWrapper = buildQuery(request);
// 查询当前页的数据
List entityList = employeeService.getEntityList(queryWrapper);
List voList = employeeService.getViewObjectList(entityList, EmployeeVO.class);
// 返回结果
return new JsonResult(Status.OK, voList);
}
@GetMapping("/kv")
public JsonResult getKVPairList(HttpServletRequest request){
Wrapper wrapper = new QueryWrapper<Employee>().lambda()
.select(Employee::getRealname, Employee::getId);
List<KeyValue> list = employeeService.getKeyValueList(wrapper);
return new JsonResult(list);
}
/***
* 创建Entity
* @return
* @throws Exception
*/
@PostMapping("/")
public JsonResult createEntity(@ModelAttribute EmployeeVO viewObject, BindingResult result, HttpServletRequest request, ModelMap modelMap)
throws Exception{
// 转换
Employee entity = BeanUtils.convert(viewObject, Employee.class);
// 创建
return super.createEntity(entity, result, modelMap);
}
/***
* 查询Entity
* @param id ID
* @return
* @throws Exception
*/
@GetMapping("/{id}")
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request, ModelMap modelMap)
throws Exception{
EmployeeVO vo = employeeService.getViewObject(id, EmployeeVO.class);
return new JsonResult(vo);
}
/***
* 更新Entity
* @param id ID
* @return
* @throws Exception
*/
@PutMapping("/{id}")
public JsonResult updateModel(@PathVariable("id")Long id, @ModelAttribute Organization entity, BindingResult result,
HttpServletRequest request, ModelMap modelMap) throws Exception{
return super.updateEntity(entity, result, modelMap);
}
/***
* 删除用户
* @param id 用户ID
* @return
* @throws Exception
*/
@DeleteMapping("/{id}")
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
return super.deleteEntity(id);
}
@Override
protected BaseService getService() {
return employeeService;
}
}

View File

@ -1,130 +0,0 @@
package com.diboot.example.controller;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.diboot.core.controller.BaseCrudRestController;
import com.diboot.core.service.BaseService;
import com.diboot.core.util.BeanUtils;
import com.diboot.core.vo.JsonResult;
import com.diboot.core.vo.KeyValue;
import com.diboot.core.vo.Status;
import com.diboot.example.entity.Organization;
import com.diboot.example.service.OrganizationService;
import com.diboot.example.vo.OrganizationVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* Organization相关Controller
* @author Mazhicheng
* @version 2018/12/23
* Copyright © www.dibo.ltd
*/
@RestController
@RequestMapping("/organization")
public class OrganizationController extends BaseCrudRestController {
@Autowired
private OrganizationService organizationService;
/***
* 默认的分页实现
* <p>
* url参数示例: /list?_pageSize=20&_pageIndex=1&_orderBy=itemValue&type=GENDAR
* </p>
* @return
* @throws Exception
*/
@GetMapping("/list")
public JsonResult getDefaultVOList(HttpServletRequest request) throws Exception{
QueryWrapper<Organization> queryWrapper = buildQuery(request);
return super.getEntityListWithPaging(request, queryWrapper, OrganizationVO.class);
}
/***
* 默认的分页实现
* <p>
* url参数示例: /listVo?page.size=20&page.index=1&page.orderBy=itemValue&type=GENDAR
* </p>
* @return
* @throws Exception
*/
@GetMapping("/listVo")
public JsonResult getCustomVOList(HttpServletRequest request) throws Exception{
QueryWrapper<Organization> queryWrapper = buildQuery(request);
// 查询当前页的数据
List entityList = organizationService.getEntityList(queryWrapper);
List voList = organizationService.getViewObjectList(entityList, OrganizationVO.class);
// 返回结果
return new JsonResult(Status.OK, voList);
}
@GetMapping("/kv")
public JsonResult getKVPairList(HttpServletRequest request){
Wrapper wrapper = new QueryWrapper<Organization>().lambda()
.select(Organization::getName, Organization::getId);
List<KeyValue> list = organizationService.getKeyValueList(wrapper);
return new JsonResult(list);
}
/***
* 创建Entity
* @return
* @throws Exception
*/
@PostMapping("/")
public JsonResult createEntity(@ModelAttribute OrganizationVO viewObject, BindingResult result, HttpServletRequest request, ModelMap modelMap)
throws Exception{
// 转换
Organization entity = BeanUtils.convert(viewObject, Organization.class);
// 创建
return super.createEntity(entity, result, modelMap);
}
/***
* 查询Entity
* @param id ID
* @return
* @throws Exception
*/
@GetMapping("/{id}")
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request, ModelMap modelMap)
throws Exception{
OrganizationVO vo = organizationService.getViewObject(id, OrganizationVO.class);
return new JsonResult(vo);
}
/***
* 更新Entity
* @param id ID
* @return
* @throws Exception
*/
@PutMapping("/{id}")
public JsonResult updateModel(@PathVariable("id")Long id, @ModelAttribute Organization entity, BindingResult result,
HttpServletRequest request, ModelMap modelMap) throws Exception{
return super.updateEntity(entity, result, modelMap);
}
/***
* 删除用户
* @param id 用户ID
* @return
* @throws Exception
*/
@DeleteMapping("/{id}")
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
return super.deleteEntity(id);
}
@Override
protected BaseService getService() {
return organizationService;
}
}

View File

@ -1,34 +0,0 @@
package com.diboot.example.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.diboot.core.entity.BaseEntity;
import lombok.Data;
import java.util.Date;
/**
* 员工Entity
* @author Mazhicheng
* @version v2.0
* @date 2019/1/30
*/
@Data
public class Employee extends BaseEntity {
private static final long serialVersionUID = 8980226078305249367L;
@TableField
private Long departmentId;
@TableField
private String realname;
@TableField
private Date birthdate;
@TableField
private String gender;
@TableField
private String status;
}

View File

@ -1,12 +1,17 @@
package com.diboot.example.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.diboot.core.entity.BaseEntity;
import lombok.Data;
import java.util.Date;
/**
* @author Mazhicheng
* @version v2.0
* @date 2019/1/30
*/
@Data
public class Role extends BaseEntity {
private static final long serialVersionUID = 3701095453152116088L;
@ -14,4 +19,6 @@ public class Role extends BaseEntity {
private String code;
@JSONField(serialize = false)
public Date createTime;
}

View File

@ -13,6 +13,9 @@ import lombok.Data;
public class User extends BaseEntity {
private static final long serialVersionUID = 3050761344045195972L;
@TableField
private Long departmentId;
@TableField
private String username;

View File

@ -1,15 +0,0 @@
package com.diboot.example.mapper;
import com.diboot.core.mapper.BaseCrudMapper;
import com.diboot.example.entity.Employee;
/**
* 员工Mapper
* @author Mazhicheng
* @version 2018/12/22
* Copyright © www.dibo.ltd
*/
public interface EmployeeMapper extends BaseCrudMapper<Employee> {
}

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
<mapper namespace="com.diboot.example.mapper.EmployeeMapper">
</mapper>

View File

@ -1,20 +0,0 @@
package com.diboot.example.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.diboot.core.service.BaseService;
import com.diboot.example.entity.Employee;
import java.util.List;
import java.util.Map;
/**
* 员工相关Service
* @author Mazhicheng
* @version v2.0
* @date 2019/1/5
*/
public interface EmployeeService extends BaseService<Employee> {
List<Map<String, Object>> testCustomQueryWrapper(QueryWrapper wrapper);
}

View File

@ -1,28 +0,0 @@
package com.diboot.example.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.diboot.core.service.impl.BaseServiceImpl;
import com.diboot.example.entity.Employee;
import com.diboot.example.mapper.EmployeeMapper;
import com.diboot.example.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* 员工相关Service
* @author Mazhicheng
* @version 2018/12/23
* Copyright © www.dibo.ltd
*/
@Service
@Slf4j
public class EmployeeServiceImpl extends BaseServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
@Override
public List<Map<String, Object>> testCustomQueryWrapper(QueryWrapper wrapper){
return getBaseMapper().selectMaps(wrapper);
}
}

View File

@ -1,5 +1,6 @@
package com.diboot.example.vo;
import com.diboot.core.binding.annotation.BindEntity;
import com.diboot.core.binding.annotation.BindEntityList;
import com.diboot.core.binding.annotation.BindField;
import com.diboot.example.entity.Department;
@ -20,9 +21,13 @@ public class DepartmentVO extends Department {
@BindField(entity = Organization.class, field = "name", condition = "org_id=id")
private String orgName;
@BindEntity(entity = Organization.class, condition="this.org_id=id")
private Organization organization;
@BindField(entity = Department.class, field = "name", condition = "parent_id=id")
private String parentName;
//TODO 该绑定未生效待检查
@BindEntityList(entity = Department.class, condition = "id=parent_id")
private List<Department> children;

View File

@ -1,32 +0,0 @@
package com.diboot.example.vo;
import com.diboot.core.binding.annotation.BindEntity;
import com.diboot.core.binding.annotation.BindField;
import com.diboot.core.binding.annotation.BindMetadata;
import com.diboot.example.entity.Department;
import com.diboot.example.entity.Employee;
import com.diboot.example.entity.Organization;
import lombok.Data;
/**
* @author Mazhicheng
* @version v2.0
* @date 2019/1/5
*/
@Data
public class EmployeeVO extends Employee {
private static final long serialVersionUID = 2956966168209358800L;
@BindEntity(entity = Department.class, condition="department_id=id")
private Department department;
@BindMetadata(type="GENDER", field="gender")
private String genderLabel;
@BindField(entity=Department.class, field="name", condition="this.department_id=id AND code IS NOT NULL")
private String deptName;
// 通过中间表关联
@BindEntity(entity = Organization.class, condition = "this.department_id=department.id AND department.org_id=id AND department.deleted=0") // AND deleted=0
private Organization organization;
}

View File

@ -1,25 +0,0 @@
package com.diboot.example.vo;
import com.diboot.core.binding.annotation.BindEntityList;
import com.diboot.core.binding.annotation.BindField;
import com.diboot.example.entity.Organization;
import lombok.Data;
import java.util.List;
/**
* @author Mazhicheng
* @version v2.0
* @date 2019/1/5
*/
@Data
public class OrganizationVO extends Organization {
private static final long serialVersionUID = 9056449207962546696L;
@BindField(entity = Organization.class, field = "name", condition = "this.parentId=id")
private String parentName;
@BindEntityList(entity = Organization.class, condition = "this.id=parentId")
private List<Organization> children;
}

View File

@ -4,6 +4,7 @@ import com.diboot.core.binding.annotation.BindEntity;
import com.diboot.core.binding.annotation.BindEntityList;
import com.diboot.core.binding.annotation.BindField;
import com.diboot.core.binding.annotation.BindMetadata;
import com.diboot.example.entity.Department;
import com.diboot.example.entity.Organization;
import com.diboot.example.entity.Role;
import com.diboot.example.entity.User;
@ -23,12 +24,22 @@ public class UserVO extends User {
@BindMetadata(type="GENDER", field = "gender")
private String genderLabel;
@BindField(entity=Department.class, field="name", condition="department_id=id AND code IS NOT NULL")
private String deptName;
@BindEntity(entity = Department.class, condition="department_id=id")
private Department department;
// 支持级联字段关联
//@BindField(entity = Organization.class, field="name", condition="this.departmentId=Department.id AND Department.orgId=id")
private String orgName;
// 通过中间表关联
@BindEntity(entity = Organization.class, condition = "this.department_id=department.id AND department.org_id=id AND department.deleted=0") // AND deleted=0
private Organization organization;
// 支持多-多Entity实体关联
//@BindEntityList(entity = Role.class, condition="this.id=user_role.user_id AND user_role.role_id=id")
@BindEntityList(entity = Role.class, condition="this.id=user_role.user_id AND user_role.role_id=id")
private List<Role> roleList;
}

View File

@ -0,0 +1,90 @@
-- create schema diboot_example collate utf8_general_ci;
-- 初始化表
create table department
(
id bigint unsigned not null comment 'ID'
primary key,
parent_id bigint default 0 not null comment '上级部门ID',
org_id bigint not null comment '单位ID',
name varchar(50) not null comment '名称',
code varchar(20) null comment '编码',
extdata varchar(100) null comment '扩展字段',
deleted tinyint(1) default 0 not null comment '已删除',
create_time timestamp default CURRENT_TIMESTAMP not null comment '创建时间'
)
comment '组织单位' charset=utf8mb4;
create table metadata
(
id int unsigned auto_increment comment 'ID'
primary key,
parent_id int unsigned not null comment '父ID',
type varchar(50) not null comment '元数据类型',
item_name varchar(100) not null comment '元数据项显示名',
item_value varchar(100) null comment '元数据项存储值',
comment varchar(200) null comment '备注',
extdata varchar(200) null comment '扩展属性',
sort_id smallint(6) default 99 not null comment '排序号',
`system` tinyint(1) default 0 not null comment '是否是系统预置',
editable tinyint(1) default 1 not null comment '是否可编辑',
deleted tinyint(1) default 0 not null comment '已删除',
create_time timestamp default CURRENT_TIMESTAMP not null comment '创建时间'
);
create table organization
(
id int auto_increment comment 'ID'
primary key,
parent_id int default 0 not null comment '上级单位ID',
name varchar(100) not null comment '名称',
telphone varchar(20) null comment '电话',
address varchar(255) null comment '地址',
deleted tinyint(1) default 0 not null comment '是否有效',
create_time timestamp default CURRENT_TIMESTAMP not null comment '创建时间'
)
comment '组织单位' charset=utf8mb4;
create table role
(
id int auto_increment comment 'ID'
primary key,
name varchar(20) null,
code varchar(20) null,
deleted tinyint(1) default 0 null,
create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间'
);
create table user
(
id int auto_increment comment 'ID'
primary key,
department_id int default 0 not null,
username varchar(20) null,
gender varchar(20) null,
deleted tinyint(1) default 0 null,
create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间'
);
create table user_role
(
user_id int not null comment '用户ID',
role_id int not null comment '角色ID',
primary key (user_id, role_id)
);
-- 初始化样例数据
INSERT INTO department (id, parent_id, org_id, name, code)
VALUES (10001, 0, 100001, '研发部', 'DEV'), (10002, 10001, 100001, '开发组', 'DEVT'), (10003, 10001, 100001, '测试组', 'TST');
INSERT INTO metadata (id, parent_id, type, item_name, item_value, comment, extdata, sort_id, `system`, editable)
VALUES (1, 0, 'GENDER', '性别', null, '', null, 99, 1, 1), (2, 1, 'GENDER', '', 'M', null, null, 99, 1, 0), (3, 1, 'GENDER', '', 'F', null, null, 99, 1, 0);
INSERT INTO organization (id, parent_id, name, telphone, address)
VALUES (100000, 0, '帝博集团', '0512-12345678', '江苏苏州'), (100001, 100000, '苏州帝博', '0512-62988949', '江苏苏州');
INSERT INTO role (id, name, code) VALUES (101, '管理员', 'ADMIN'), (102, '操作员', 'OPERATOR'), (103, '只读用户', 'READ'), (104, '项目经理', 'PM');
INSERT INTO user (id, department_id, username, gender)
VALUES (1001, 10002, '张三', 'M'), (1002, 10002, '李四', 'F'), (1003, 10003, '王五', 'M'), (1004, 10001, '马六', 'M');
INSERT INTO user_role (user_id, role_id) VALUES (1001, 101),(1001, 102),(1003, 102),(1003, 103);