Просмотр исходного кода

功能管理模块-新增获取功能列表、新增菜单功能

songxinlu 3 лет назад
Родитель
Сommit
4189150f0d

+ 80 - 0
common/src/main/java/com/lantone/common/dto/MenuDTO.java

@@ -0,0 +1,80 @@
+package com.lantone.common.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * 菜单功能DTO
+ * </p>
+ */
+@Data
+@ApiModel(value = "MenuDTO对象", description = "菜单功能DTO")
+public class MenuDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "编号")
+    private Long id;
+
+    @ApiModelProperty(value = "父级编号")
+    private Long parentId;
+    @ApiModelProperty(value = "资源权限编号")
+    private Long resourceId;
+
+    @ApiModelProperty(value = "服务id")
+    private Long serviceId;
+
+    @ApiModelProperty(value = "功能名称")
+    private String name;
+
+    @ApiModelProperty(value = "类型:0:目录,1菜单,2按钮,3:超链接")
+    private String type;
+
+    @ApiModelProperty(value = "页面路由")
+    private String url;
+
+    @ApiModelProperty(value = "资源权限")
+    private String permission;
+
+    @ApiModelProperty(value = "图标")
+    private String icon;
+
+    @ApiModelProperty(value = "排序")
+    private String orderNo;
+
+    @ApiModelProperty(value = "状态 0:禁用,1:启用")
+    private String status;
+
+    @ApiModelProperty(value = "描述")
+    private String menuDescribe;
+
+    @ApiModelProperty(value = "是否删除,N:未删除,Y:删除")
+    private String isDeleted;
+
+    @ApiModelProperty(value = "记录创建时间")
+    private Date gmtCreate;
+
+    @ApiModelProperty(value = "记录修改时间,如果时间是1970年则表示纪录未修改")
+    private Date gmtModified;
+
+    @ApiModelProperty(value = "创建人,0表示无创建人值")
+    private String creator;
+
+    @ApiModelProperty(value = "修改人,如果为0则表示纪录未修改")
+    private String modifier;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty(value = "子集")
+    private List<MenuDTO> sonMenu;
+
+
+
+}

+ 441 - 0
common/src/main/java/com/lantone/common/util/EntityUtil.java

@@ -0,0 +1,441 @@
+package com.lantone.common.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.lang3.reflect.FieldUtils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @Description: 实体对象工具类
+ * @author: gaodm
+ * @time: 2018/9/13 20:12
+ */
+@Slf4j
+public class EntityUtil {
+
+    private static final String DATE_CLASS_NAME = Date.class.getName();
+
+    /**
+     * 将list中元素的某一成员组装成list返回。注意:会去重!
+     *
+     * @param list      元素列表
+     * @param fieldName 成员变量的field
+     * @param <T>       元素类型
+     * @return 返回该字段组成的list
+     */
+    public static <T> List makeListByFieldName(List<T> list, String fieldName) {
+        List returnList = new LinkedList();
+        if (list.isEmpty()) {
+            return returnList;
+        }
+        Object firstObj = list.get(0);
+        Field field = FieldUtils.getField(firstObj.getClass(), fieldName, true);
+        if (field == null) {
+            throw new RuntimeException(firstObj.getClass().getName() + "不存在" + fieldName);
+        }
+        try {
+            for (T o : list) {
+                if (!returnList.contains(field.get(o))) {
+                    returnList.add(field.get(o));
+                }
+            }
+        } catch (IllegalAccessException e) {
+            //懒得在外面try catch, 直接ignore
+            throw new RuntimeException(e);
+        }
+        return returnList;
+    }
+
+    /**
+     * 将Collection中元素的某一成员组装成Set返回
+     *
+     * @param collection 元素列表
+     * @param fieldName  成员变量的field
+     * @param <T>        元素类型
+     * @return 返回该字段组成的LinkedHashSet。若元素中不存在名为fieldName的成员变量,则返回EmptySet
+     */
+    public static <T> LinkedHashSet makeLinkedSetByFieldName(Collection<T> collection, String fieldName) {
+        LinkedHashSet returnLinkedSet = new LinkedHashSet<>();
+        Iterator<T> it = collection.iterator();
+        boolean isFirst = true;
+        Field field = null;
+        while (it.hasNext()) {
+            T o = it.next();
+            if (isFirst) {
+                field = FieldUtils.getField(o.getClass(), fieldName, true);
+                if (field == null) {
+                    throw new RuntimeException(o.getClass().getName() + "不存在" + fieldName);
+                }
+                isFirst = false;
+            }
+            try {
+                returnLinkedSet.add(field.get(o));
+            } catch (IllegalAccessException e) {
+                //ignore
+                throw new RuntimeException(e);
+            }
+        }
+        return returnLinkedSet;
+    }
+
+    /**
+     * 将list中的元素放到Map<M, N>以建立 key - value 索引<p>
+     * modified from com.tqmall.saint.biz.util.EntityUtil#makeEntityMap(java.util.List, java.lang.String)
+     *
+     * @param collection     Collection<V> 元素列表
+     * @param keyFieldName   String 元素的属性名称, 该属性的值作为Map的key
+     * @param valueFieldName String 元素的属性名称, 该属性的值作为Map的value
+     * @param <M>            key类型
+     * @param <N>            value类型
+     * @param <V>            列表元素类型
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <M, N, V> Map<M, N> makeMapWithKeyValue(Collection<V> collection, String keyFieldName, String valueFieldName) {
+        Map<M, N> map = new HashMap<>();
+        if (collection == null || collection.isEmpty()) {
+            return map;
+        }
+        Iterator<V> it = collection.iterator();
+        boolean isFirst = true;
+        Method keyGetter = null;
+        Method valueGetter = null;
+        try {
+            while (it.hasNext()) {
+                V o = it.next();
+                if (isFirst) {
+                    keyGetter = getMethod(o.getClass(), keyFieldName, "get");
+                    valueGetter = getMethod(o.getClass(), valueFieldName, "get");
+                    isFirst = false;
+                }
+                map.put((M) keyGetter.invoke(o), (N) valueGetter.invoke(o));
+            }
+        } catch (Exception e) {
+            log.error("makeEntityMap error list is " + collection, e);
+            return map;
+        }
+        return map;
+    }
+
+    /**
+     * 将list中的元素放到Map<K, V>以建立 key - value 索引<p>
+     *
+     * @param list         List<V> 元素列表
+     * @param keyFieldName String 元素的属性名称, 该属性的值作为索引key
+     * @param <K>          key类型
+     * @param <V>          value类型
+     * @return Map<K   ,       V> key - value 索引
+     */
+    @SuppressWarnings("unchecked")
+    public static <K, V> Map<K, V> makeEntityMap(List<V> list, String keyFieldName) {
+        Map<K, V> map = new HashMap<>();
+        if (list == null || list.size() == 0) {
+            return map;
+        }
+        try {
+            Method getter = getMethod(list.get(0).getClass(), keyFieldName, "get");
+            for (V item : list) {
+                map.put((K) getter.invoke(item), item);
+            }
+        } catch (Exception e) {
+            log.error("makeEntityMap error list is " + list, e);
+            return map;
+        }
+        return map;
+    }
+
+    /**
+     * 将list中的元素放到Map<String, V>以建立 key - value 索引<p>
+     *
+     * @param list          List<V> 元素列表
+     * @param splitVar      属性之间间隔
+     * @param keyFieldNames String 元素的属性名称动态数组, 依次循环该属性的值作为索引key
+     * @param <V>           value类型
+     * @return Map<String   ,       V> key - value 索引
+     */
+
+    @SuppressWarnings("unchecked")
+    public static <V> Map<String, V> makeEntityMapByKeys(List<V> list, String splitVar, String... keyFieldNames) {
+        Map<String, V> map = new HashMap<>();
+        if (list == null || list.size() == 0 || keyFieldNames == null || keyFieldNames.length == 0 || StringUtil.isEmpty(splitVar)) {
+            return map;
+        }
+        try {
+            List<Method> getterList = new ArrayList<>();
+            for (String key : keyFieldNames) {
+                getterList.add(getMethod(list.get(0).getClass(), key, "get"));
+            }
+            for (V item : list) {
+                StringBuffer keys = new StringBuffer("");
+                for (int i = 0; i < getterList.size(); i++) {
+                    keys.append(getterList.get(i).invoke(item));
+                    if (i < getterList.size() - 1) {
+                        keys.append(splitVar);
+                    }
+                }
+                map.put(keys.toString(), item);
+            }
+        } catch (Exception e) {
+            log.error("makeEntityMap error list is " + list, e);
+            return map;
+        }
+        return map;
+    }
+
+    /**
+     * 将list中的元素放到Map<K, List<V>> 以建立 key - List<value> 索引<p>
+     *
+     * @param list         List<V> 元素列表
+     * @param keyFieldName String 元素的属性名称, 该属性的值作为索引key
+     * @param <K>          key类型
+     * @param <V>          value类型
+     * @return Map<K   ,       V> key - value 索引
+     */
+    public static <K, V> Map<K, List<V>> makeEntityListMap(List<V> list, String keyFieldName) {
+        Map<K, List<V>> map = new LinkedHashMap<>();
+        if (list == null || list.size() == 0) {
+            return map;
+        }
+        try {
+            Method getter = getMethod(list.get(0).getClass(), keyFieldName, "get");
+            for (V item : list) {
+                @SuppressWarnings("unchecked")
+                K key = (K) getter.invoke(item);
+                List<V> groupList = map.get(key);
+                if (groupList == null) {
+                    groupList = new ArrayList<>();
+                    map.put(key, groupList);
+                }
+                groupList.add(item);
+            }
+        } catch (Exception e) {
+            log.error("makeEntityListMap error list is " + list, e);
+            return map;
+        }
+        return map;
+    }
+
+    /**
+     * 获取getter或setter
+     */
+    @SuppressWarnings("unchecked")
+    private static Method getMethod(@SuppressWarnings("rawtypes") Class clazz, String fieldName,
+                                    String methodPrefix) throws NoSuchMethodException {
+        String first = fieldName.substring(0, 1);
+        String getterName = methodPrefix + fieldName.replaceFirst(first, first.toUpperCase());
+        return clazz.getMethod(getterName);
+    }
+
+    /**
+     * 比较两个对象改变了的属性值,然后以string拼接返回
+     *
+     * @param oldObj 对象1
+     * @param newObj 对象2
+     * @return 改变的属性值拼接的字符串
+     */
+    public static <T> String compareToObjProperty(T oldObj, T newObj) {
+        String modifiedStr = "";
+        Field[] fields = oldObj.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            try {
+                if (!Modifier.isStatic(field.getModifiers())) {
+                    String tempFieldType = field.getType().getName();
+                    Method tempMethod = getMethod(oldObj.getClass(), field.getName(), "get");
+                    if (field.getName().equals("ATTRIBUTE_ORDER_SN")) {
+                        System.out.println("aa");
+                    }
+                    if (tempMethod != null) {
+                        Object tempOld = tempMethod.invoke(oldObj);
+                        Object tempNew = tempMethod.invoke(newObj);
+                        if (findDifference(tempOld, tempNew)) {
+                            if (tempFieldType.equals("java.util.Date")) {
+                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd mm:HH:ss");
+                                modifiedStr += field.getName() + "[" + (tempOld == null ? null : sdf.format(tempOld)) + "," +
+                                        (tempNew == null ? null : sdf.format(tempNew)) + "],";
+                            } else {
+                                modifiedStr += field.getName() + "[" + tempOld + "," + tempNew + "],";
+                            }
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                log.error("compareTo error", e);
+            }
+        }
+        return modifiedStr;
+    }
+
+    /**
+     * 获取所有field,不包含field,修改自FieldUtils的getAllFieldsList方法
+     *
+     * @param cls         类
+     * @param forceAccess 是否包含private的field
+     * @return
+     */
+    private static List<Field> getFieldsList(Class<?> cls, final boolean forceAccess) {
+        Validate.isTrue(cls != null, "The class must not be null");
+        final List<Field> allFields = new ArrayList<Field>();
+        Class<?> currentClass = cls;
+        final Field[] declaredFields = currentClass.getDeclaredFields();
+        for (Field field : declaredFields) {
+            if (!Modifier.isPublic(field.getModifiers())) {
+                if (forceAccess) {
+                    field.setAccessible(true);
+                } else {
+                    continue;
+                }
+            }
+            allFields.add(field);
+        }
+        return allFields;
+    }
+
+    /**
+     * 获取所有field,包含所有父类,来自FieldUtils的getAllFieldsList方法
+     *
+     * @param cls         类
+     * @param forceAccess 是否包含private的field
+     * @return
+     */
+    private static List<Field> getAllFieldsList(Class<?> cls, final boolean forceAccess) {
+        Validate.isTrue(cls != null, "The class must not be null");
+        final List<Field> allFields = new ArrayList<Field>();
+        Class<?> currentClass = cls;
+        while (currentClass != null) {
+            final Field[] declaredFields = currentClass.getDeclaredFields();
+            for (Field field : declaredFields) {
+                if (!Modifier.isPublic(field.getModifiers())) {
+                    if (forceAccess) {
+                        field.setAccessible(true);
+                    } else {
+                        continue;
+                    }
+                }
+                allFields.add(field);
+            }
+            currentClass = currentClass.getSuperclass();
+        }
+        return allFields;
+    }
+
+    /**
+     * 获取类型的field
+     *
+     * @param cls         类型
+     * @param checkSupers 是否要获取父类的field
+     * @param forceAccess 是否包含private的field
+     * @return
+     */
+    private static List<Field> getFieldsList(Class<?> cls, final boolean checkSupers, final boolean forceAccess) {
+        if (checkSupers) {
+            return getAllFieldsList(cls, forceAccess);
+        } else {
+            return getFieldsList(cls, forceAccess);
+        }
+    }
+
+    /**
+     * 比较两个对象改变了的属性值,然后以string拼接返回
+     *
+     * @param oldObj      对象1
+     * @param newObj      对象2
+     * @param formatter   格式(默认为%s[%s,%s],第一个%s对应fieldname,第二个%对应对象1的fieldname的值,第三个%s对应对象2的fieldname的值)
+     * @param checkSupers 是否需要比较所有父类(无视继承的接口)
+     * @param forceAccess 是否需要比较private成员变量
+     * @param <T>         要比较的对象类型
+     * @return
+     */
+    public static <T> String compareToObjProperty(T oldObj, T newObj, String formatter, final boolean checkSupers, final boolean forceAccess) {
+        StringBuilder builder = new StringBuilder();
+        if (oldObj == newObj) {
+            return builder.toString();
+        }
+        if (StringUtils.isEmpty(formatter)) {
+            formatter = "%s[%s,%s]";
+        }
+        List<Field> fields = getFieldsList(oldObj.getClass(), checkSupers, forceAccess);
+        for (Field field : fields) {
+            try {
+                Object tmpOld = field.get(oldObj);
+                Object tmpNew = field.get(newObj);
+                if (findDifference(tmpOld, tmpNew)) {
+                    if (field.getType().getName().equals(DATE_CLASS_NAME)) {
+                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd mm:HH:ss");
+                        String strOld = tmpOld == null ? null : sdf.format(tmpOld);
+                        String strNew = tmpNew == null ? null : sdf.format(tmpNew);
+                        builder.append(String.format(formatter, field.getName(), strOld, strNew));
+                        builder.append(",");
+                    } else {
+                        builder.append(String.format(formatter, field.getName(), tmpOld, tmpNew));
+                        builder.append(",");
+                    }
+                }
+            } catch (Exception e) {
+                log.error("compareTo error", e);
+            }
+        }
+        return builder.toString();
+    }
+
+    /**
+     * 比较两个对象的值是否不同
+     *
+     * @param obj1 对象1
+     * @param obj2 对象2
+     * @param <T>  object
+     * @return 若俩对象的值不相同则为true,反之为false
+     */
+    public static <T> Boolean findDifference(T obj1, T obj2) {
+        if (obj1 == null && obj2 == null) {
+            return false;
+        }
+        if (obj1 == null || obj2 == null) {
+            return true;
+        }
+        if (obj1 instanceof BigDecimal) {
+            return ((BigDecimal) obj1).compareTo((BigDecimal) obj2) != 0;
+        } else {
+            return !obj1.equals(obj2);
+        }
+    }
+
+    public static <V, K> Map<V, K> makeEntityMapNew(List<Map<String, Object>> hashMap, String keyFieldName) {
+        Map<V, K> map = new HashMap<>();
+        if (hashMap == null || hashMap.size() == 0) {
+            return map;
+        }
+        try {
+            for (Map linkedHashMap : hashMap) {
+                map.put((V) linkedHashMap.get(keyFieldName).toString(), (K) linkedHashMap);
+            }
+        } catch (Exception e) {
+            log.error("makeEntityListMap error list is " + hashMap, e);
+            return map;
+        }
+        return map;
+    }
+
+
+    public static Map<Integer, Map> makeEntityMapSpecial(List<Map> hashMap, String keyFieldName) {
+        Map<Integer, Map> map = new HashMap<>();
+        if (hashMap == null || hashMap.size() == 0) {
+            return map;
+        }
+        try {
+            for (Map linkedHashMap : hashMap) {
+                map.put(Integer.valueOf(linkedHashMap.get(keyFieldName).toString()), linkedHashMap);
+            }
+        } catch (Exception e) {
+            log.error("makeEntityListMap error list is " + hashMap, e);
+            return map;
+        }
+        return map;
+    }
+}

+ 80 - 0
common/src/main/java/com/lantone/common/vo/MenuVO.java

@@ -0,0 +1,80 @@
+package com.lantone.common.vo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * 菜单功能VO
+ * </p>
+ */
+@Data
+@ApiModel(value="MenuVO对象", description="菜单功能VO")
+public class MenuVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "编号")
+    private Long id;
+
+    @ApiModelProperty(value = "父级编号")
+    private Long parentId;
+
+    @ApiModelProperty(value = "服务id列表")
+    private List<Long> services;
+
+    @ApiModelProperty(value = "功能名称")
+    private String name;
+
+    @ApiModelProperty(value = "权限标识")
+    private List<String> permissions;
+
+    @ApiModelProperty(value = "类型:0:目录,1菜单,2按钮,3:超链接")
+    private String type;
+
+    @ApiModelProperty(value = "页面路由")
+    private String url;
+
+    @ApiModelProperty(value = "图标")
+    private String icon;
+
+    @ApiModelProperty(value = "排序")
+    private String orderNo;
+
+    @ApiModelProperty(value = "状态 0:禁用,1:启用")
+    private String status;
+
+    @ApiModelProperty(value = "描述")
+    private String menuDescribe;
+
+    @ApiModelProperty(value = "是否删除,N:未删除,Y:删除")
+    private String isDeleted;
+
+    @ApiModelProperty(value = "记录创建时间")
+    private Date gmtCreate;
+
+    @ApiModelProperty(value = "记录修改时间,如果时间是1970年则表示纪录未修改")
+    private Date gmtModified;
+
+    @ApiModelProperty(value = "创建人,0表示无创建人值")
+    private String creator;
+
+    @ApiModelProperty(value = "修改人,如果为0则表示纪录未修改")
+    private String modifier;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty("操作码 1:新增;2:修改 ;3:删除;5:启用禁用")
+    private int  opeType;
+
+}

+ 30 - 0
common/src/main/java/com/lantone/common/vo/RoleServiceMenuVo.java

@@ -0,0 +1,30 @@
+package com.lantone.common.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * <p>
+ * 角色系统功能菜单VO
+ * </p>
+ */
+@Data
+public class RoleServiceMenuVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+
+    @ApiModelProperty(value = "角色id列表")
+    private List<Long> roles;
+
+    @ApiModelProperty(value = "服务id")
+    private Long serviceId;
+
+    @ApiModelProperty(value = "是否删除,N:未删除,Y:删除")
+    private String isDeleted;
+
+
+}

+ 7 - 11
dblayer-mbg/src/main/java/com/lantone/dblayermbg/entity/Menu.java

@@ -13,29 +13,25 @@ import java.util.Date;
 
 /**
  * <p>
- * 菜单功能
+ * 功能菜单表
  * </p>
  */
 @Data
 @TableName("sys_menu")
-@ApiModel(value="Menu对象", description="菜单功能表")
+@ApiModel(value="Menu对象", description="功能菜单表")
 public class Menu implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-    @ApiModelProperty(value = "编号")
+    @ApiModelProperty(value = "主键")
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;
 
-    @ApiModelProperty(value = "父级编号")
+    @ApiModelProperty(value = "父级功能菜单ID")
     @TableField("parent_id")
     private Long parentId;
 
-    @ApiModelProperty(value = "服务id")
-    @TableField("service_id")
-    private Long serviceId;
-
-    @ApiModelProperty(value = "功能名称")
+    @ApiModelProperty(value = "功能菜单名称")
     @TableField("name")
     private String name;
 
@@ -60,8 +56,8 @@ public class Menu implements Serializable {
     private String status;
 
     @ApiModelProperty(value = "描述")
-    @TableField("describe")
-    private String describe;
+    @TableField("menu_describe")
+    private String menuDescribe;
 
     @ApiModelProperty(value = "是否删除,N:未删除,Y:删除")
     @TableField("is_deleted")

+ 5 - 5
dblayer-mbg/src/main/java/com/lantone/dblayermbg/entity/MenuResource.java

@@ -13,25 +13,25 @@ import java.util.Date;
 
 /**
  * <p>
- * 菜单资源关联表
+ * 功能菜单与URL资源关联表
  * </p>
  */
 @Data
 @TableName("sys_menu_resource")
-@ApiModel(value="MenuResource对象", description="菜单资源关联表")
+@ApiModel(value="MenuResource对象", description="功能菜单与URL资源关联表")
 public class MenuResource implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-    @ApiModelProperty(value = "编号")
+    @ApiModelProperty(value = "主键")
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;
 
-    @ApiModelProperty(value = "菜单ID")
+    @ApiModelProperty(value = "功能菜单ID")
     @TableField("menu_id")
     private Long menuId;
 
-    @ApiModelProperty(value = "资源ID")
+    @ApiModelProperty(value = "URL资源ID")
     @TableField("resource_id")
     private Long resourceId;
 

+ 4 - 8
dblayer-mbg/src/main/java/com/lantone/dblayermbg/entity/Resource.java

@@ -13,25 +13,21 @@ import java.util.Date;
 
 /**
  * <p>
- * 系统资源表
+ * URL资源表
  * </p>
  */
 @Data
 @TableName("sys_resource")
-@ApiModel(value="Resource对象", description="系统资源表")
+@ApiModel(value="Resource对象", description="URL资源表")
 public class Resource implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-    @ApiModelProperty(value = "编号")
+    @ApiModelProperty(value = "主键")
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;
 
-    @ApiModelProperty(value = "系统id")
-    @TableField("service_id")
-    private Long serviceId;
-
-    @ApiModelProperty(value = "资源名称")
+    @ApiModelProperty(value = "URL资源名称")
     @TableField("name")
     private String name;
 

+ 5 - 5
dblayer-mbg/src/main/java/com/lantone/dblayermbg/entity/ServiceMenu.java

@@ -13,25 +13,25 @@ import java.util.Date;
 
 /**
  * <p>
- * 系统菜单功能关联表
+ * 系统服务功能菜单关联表
  * </p>
  */
 @Data
 @TableName("sys_service_menu")
-@ApiModel(value="ServiceMenu对象", description="系统菜单功能关联表")
+@ApiModel(value="ServiceMenu对象", description="系统服务功能菜单关联表")
 public class ServiceMenu implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-    @ApiModelProperty(value = "编号")
+    @ApiModelProperty(value = "主键")
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;
 
-    @ApiModelProperty(value = "系统编号")
+    @ApiModelProperty(value = "系统服务ID")
     @TableField("service_id")
     private Long serviceId;
 
-    @ApiModelProperty(value = "菜单功能编号")
+    @ApiModelProperty(value = "功能菜单ID")
     @TableField("menu_id")
     private Long menuId;
 

+ 15 - 1
dblayer-mbg/src/main/java/com/lantone/dblayermbg/mapper/RoleServiceMenuMapper.java

@@ -1,7 +1,12 @@
 package com.lantone.dblayermbg.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.lantone.common.dto.MenuDTO;
+import com.lantone.common.vo.RoleServiceMenuVo;
 import com.lantone.dblayermbg.entity.RoleServiceMenu;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * <p>
@@ -9,6 +14,15 @@ import com.lantone.dblayermbg.entity.RoleServiceMenu;
  * </p>
  */
 public interface RoleServiceMenuMapper extends BaseMapper<RoleServiceMenu> {
-
+    /**
+     * @Method getMenus
+     * @Author songxl
+     * @Version  1.0
+     * @Description普通用户获取对应系统的菜单列表
+     * @param roleServiceMenuVo
+     * @Return java.util.List<com.lantone.common.dto.MenuDTO>
+     * @Date 2021/7/28
+     */
+    List<MenuDTO> getMenus(@Param("roleServiceMenuVo") RoleServiceMenuVo roleServiceMenuVo);
 }
 

+ 38 - 0
dblayer-mbg/src/main/resources/mapper/RoleServiceMenuMapper.xml

@@ -2,4 +2,42 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.lantone.dblayermbg.mapper.RoleServiceMenuMapper">
 
+    <select id="getMenus" resultType="com.lantone.common.dto.MenuDTO">
+        SELECT
+         m.id,
+         m.`name`,
+         m.parent_id,
+         m.`describe`,
+         m.`status`,
+         m.order_no,
+         m.remark,
+         m.type,
+         m.url url,
+         r.id resourceId,
+         r.url permission
+        FROM
+            sys_service_menu sm,
+            sys_role_service_menu rsm,
+            sys_menu m
+        LEFT JOIN sys_menu_resource mr ON m.id = mr.menu_id
+        AND mr.is_deleted = 'N'
+        LEFT JOIN sys_resource r ON mr.resource_id = r.id
+        AND r.is_deleted = 'N'
+        WHERE m.id = sm.menu_id
+        AND sm.id = rsm.service_menu_id
+        <if test="roleServiceMenuVo.serviceId != null and roleServiceMenuVo.serviceId !=''">
+            AND sm.service_id = #{roleServiceMenuVo.serviceId}
+        </if>
+        <if test="roleServiceMenuVo.roles !=null and roleServiceMenuVo.roles.size!=0">
+            AND rsm.role_id IN
+            <foreach collection="roleServiceMenuVo.roles" item="id" open="(" close=")" separator=",">
+                #{id}
+            </foreach>
+        </if>
+        AND m.is_deleted = 'N'
+        ORDER BY
+        m.gmt_create,
+        m.order_no DESC
+    </select>
+
 </mapper>

+ 1 - 2
dblayer-mbg/src/main/resources/mapper/base/BaseMenuMapper.xml

@@ -6,14 +6,13 @@
     <resultMap id="BaseResultMap" type="com.lantone.dblayermbg.entity.Menu">
         <id column="id" property="id"/>
         <result column="parent_id" property="parentId"/>
-        <result column="service_id" property="serviceId"/>
         <result column="name" property="name"/>
         <result column="type" property="type"/>
         <result column="url" property="url"/>
         <result column="icon" property="icon"/>
         <result column="order_no" property="orderNo"/>
         <result column="status" property="status"/>
-        <result column="describe" property="describe"/>
+        <result column="menu_describe" property="menuDescribe"/>
         <result column="is_deleted" property="isDeleted"/>
         <result column="gmt_create" property="gmtCreate"/>
         <result column="gmt_modified" property="gmtModified"/>

+ 0 - 1
dblayer-mbg/src/main/resources/mapper/base/BaseResourceMapper.xml

@@ -5,7 +5,6 @@
     <!-- 通用查询映射结果 -->
     <resultMap id="BaseResultMap" type="com.lantone.dblayermbg.entity.Resource">
         <id column="id" property="id"/>
-        <result column="service_id" property="serviceId"/>
         <result column="name" property="name"/>
         <result column="url" property="url"/>
         <result column="order_no" property="orderNo"/>

+ 6 - 1
gateway-service/src/main/resources/bootstrap.yml

@@ -91,4 +91,9 @@ secure:
       - "/security-center/data/auth/disableAuth"
       - "/security-center/data/auth/deleteAuth"
       - "/security-center/data/auth/getDoctorPage"
-      - "/security-center/data/auth/getDataAuthPage"
+      - "/security-center/data/auth/getDataAuthPage"
+      - "/security-center/func/management/getMenus"
+      - "/security-center/func/management/addMenu"
+      - "/security-center/func/management/updateMenu"
+      - "/security-center/func/management/deleteMenu"
+      - "/security-center/func/management/disableMenu"

+ 1 - 14
security-center/src/main/java/com/lantone/security/facade/DataAuthHandleFacade.java

@@ -347,23 +347,10 @@ public class DataAuthHandleFacade extends DataAuthServiceImpl {
                     Asserts.fail("系统对应数据权限明细未选择");
                 }
                 break;
-            case 3:
-                if (serviceDataAuthVO.getDataAuthVO().getId() == null) {
-                    Asserts.fail("数据权限ID为空");
-                }
-                break;
-            case 4:
-                if (serviceDataAuthVO.getDataAuthVO().getId() == null) {
-                    Asserts.fail("数据权限ID为空");
-                }
-                break;
-            case 5:
+            default:
                 if (serviceDataAuthVO.getDataAuthVO().getId() == null) {
                     Asserts.fail("数据权限ID为空");
                 }
-                break;
-            default:
-
                 break;
         }
 

+ 351 - 0
security-center/src/main/java/com/lantone/security/facade/FuncManagementFacade.java

@@ -0,0 +1,351 @@
+package com.lantone.security.facade;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.lantone.common.dto.MenuDTO;
+import com.lantone.common.exception.Asserts;
+import com.lantone.common.util.DateUtil;
+import com.lantone.common.util.EntityUtil;
+import com.lantone.common.util.ListUtil;
+import com.lantone.common.util.StringUtil;
+import com.lantone.common.vo.MenuVO;
+import com.lantone.common.vo.RoleServiceMenuVo;
+import com.lantone.dblayermbg.entity.*;
+import com.lantone.dblayermbg.facade.*;
+import com.lantone.security.enums.CRUDEnum;
+import com.lantone.security.enums.IsDeleteEnum;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName: FuncManagementFacade
+ * @Description: 功能管理API
+ * @Author songxl
+ * @Date 2021/7/28
+ * @Version 1.0
+ */
+@Component
+public class FuncManagementFacade {
+    @Autowired
+    private RoleServiceMenuFacade roleServiceMenuFacade;
+    @Autowired
+    private MenuFacade menuFacade;
+    @Autowired
+    private ResourceFacade resourceFacade;
+    @Autowired
+    private MenuResourceFacade menuResourceFacade;
+    @Autowired
+    private ServiceMenuFacade serviceMenuFacade;
+
+    /**
+     * @param roleServiceMenuVo
+     * @Method getMenus
+     * @Author songxl
+     * @Version 1.0
+     * @Description获取功能菜单树
+     * @Return java.util.List<com.lantone.common.dto.MenuDTO>
+     * @Date 2021/7/28
+     */
+    public List<MenuDTO> getMenusTree(RoleServiceMenuVo roleServiceMenuVo) {
+
+        //1.入参校验
+        inputParamCheck(roleServiceMenuVo);
+        List<MenuDTO> menuList = null;
+        //2.1获取菜单列表
+        menuList = roleServiceMenuFacade.getBaseMapper().getMenus(roleServiceMenuVo);
+        //3.整理菜单
+        if (ListUtil.isNotEmpty(menuList)) {
+            Map<Long, List<MenuDTO>> menuMap = EntityUtil.makeEntityListMap(menuList, "parentId");
+            List<MenuDTO> menuRes = menuMap.get(0L);
+            for (MenuDTO bean : menuRes) {
+                getSonMenu(bean, menuMap);
+            }
+            return menuRes;
+        } else {
+            Asserts.fail("菜单列表为空");
+        }
+        return null;
+    }
+
+    /**
+     * @param roleServiceMenuVo
+     * @Method inputParamCheck
+     * @Author songxl
+     * @Version 1.0
+     * @Description入参校验
+     * @Return void
+     * @Date 2021/7/28
+     */
+    private void inputParamCheck(RoleServiceMenuVo roleServiceMenuVo) {
+        if (roleServiceMenuVo == null) {
+            Asserts.fail("入参为空");
+        }
+        if (ListUtil.isEmpty(roleServiceMenuVo.getRoles())) {
+            Asserts.fail("角色列表为空");
+        }
+        if (roleServiceMenuVo.getServiceId() == null) {
+            Asserts.fail("服务id为空");
+        }
+    }
+
+    /**
+     * @param menuVO
+     * @Method inputParamCheck
+     * @Author songxl
+     * @Version 1.0
+     * @Description入参校验
+     * @Return void
+     * @Date 2021/7/28
+     */
+    private void inputParamCheck(MenuVO menuVO) {
+        if (menuVO == null) {
+            Asserts.fail("入参为空");
+        }
+        if (menuVO.getOpeType() == 0) {
+            Asserts.fail("操作码为空");
+        }
+        switch (menuVO.getOpeType()) {
+            case 1:
+                if (StringUtil.isEmpty(menuVO.getName())) {
+                    Asserts.fail("功能菜单名称为空");
+                }
+                if (menuVO.getParentId() == null) {
+                    Asserts.fail("功能菜单父级ID为空");
+                }
+                if (ListUtil.isEmpty(menuVO.getServices())) {
+                    Asserts.fail("功能菜单所属服务ID列表为空");
+                }
+                if (menuVO.getType() == null) {
+                    Asserts.fail("功能菜单类型为空");
+                }
+                break;
+            case 2:
+                if (menuVO.getId() == null) {
+                    Asserts.fail("功能菜单ID为空");
+                }
+                if (StringUtil.isEmpty(menuVO.getName())) {
+                    Asserts.fail("功能菜单名称为空");
+                }
+                if (menuVO.getParentId() == null) {
+                    Asserts.fail("功能菜单父级ID为空");
+                }
+                if (ListUtil.isEmpty(menuVO.getServices())) {
+                    Asserts.fail("功能菜单所属服务ID列表为空");
+                }
+                if (menuVO.getType() == null) {
+                    Asserts.fail("功能菜单类型为空");
+                }
+                break;
+            default:
+                if (menuVO.getId() == null) {
+                    Asserts.fail("功能菜单ID为空");
+                }
+                break;
+        }
+    }
+
+
+    /**
+     * 递归获取菜单结构
+     *
+     * @param menu    当前菜单
+     * @param menuMap 菜单集
+     * @return 菜单结构
+     */
+    public List<MenuDTO> getSonMenu(MenuDTO menu, Map<Long, List<MenuDTO>> menuMap) {
+        List<MenuDTO> sonMenu = new ArrayList<>();
+        List<MenuDTO> menuList = menuMap.get(menu.getId());
+        if (ListUtil.isNotEmpty(menuList)) {
+            menu.setSonMenu(menuList);
+            for (MenuDTO bean : menuList) {
+                getSonMenu(bean, menuMap);
+            }
+        }
+        return sonMenu;
+    }
+
+    /**
+     * @param menuVO
+     * @Method addMenu
+     * @Author songxl
+     * @Version 1.0
+     * @Description添加功能菜单
+     * @Return java.lang.Boolean
+     * @Date 2021/7/28
+     */
+    private Boolean addMenu(MenuVO menuVO) {
+        //1.入参校验
+        inputParamCheck(menuVO);
+        //2.插入sys_menu、sys_resource、sys_menu_resource
+        return saveMenuResource(menuVO);
+    }
+
+    /**
+     * @param menuVO
+     * @Method saveMenuResource
+     * @Author songxl
+     * @Version 1.0
+     * @Description
+     * @Return void
+     * @Date 2021/7/28
+     */
+    private boolean saveMenuResource(MenuVO menuVO) {
+        //2.1插入sys_menu
+        Menu menu = new Menu();
+        BeanUtils.copyProperties(menuVO, menu);
+        menu.setGmtCreate(DateUtil.now());
+        //2.2插入成功获取 menuID
+        if (menuFacade.save(menu)) {
+            menuVO.getServices().stream().forEach(serviceId -> {
+                Long menuID = menuFacade.list(new QueryWrapper<Menu>()
+                        .eq("parent_id", menu.getParentId())
+                        .eq("name", menu.getName())
+                        .eq("type", menu.getType())
+                        .eq("is_deleted", IsDeleteEnum.N.getKey())).get(0).getId();
+                //2.3 判断该功能菜单是否有对应权限
+                if (ListUtil.isNotEmpty(menuVO.getPermissions())) {
+                    menuVO.getPermissions().stream().forEach(permission -> {
+                        //2.4 有权限 则插入sys_resource
+                        Resource resource = new Resource();
+                        resource.setUrl(permission);
+                        resource.setGmtCreate(DateUtil.now());
+                        if (resourceFacade.save(resource)) {
+                            //2.5 插入成功获取对应的 resourceID
+                            Long resourceID = resourceFacade.list(new QueryWrapper<Resource>()
+                                    .eq("url", resource.getUrl())
+                                    .eq("is_deleted", IsDeleteEnum.N.getKey())).get(0).getId();
+                            //2.6 插入菜单和功能对应关系
+                            MenuResource menuResource = new MenuResource();
+                            menuResource.setMenuId(menuID);
+                            menuResource.setResourceId(resourceID);
+                            if (menuResourceFacade.save(menuResource)) {
+                            } else {
+                                Asserts.fail("菜单与资源权限插入失败");
+                            }
+                        } else {
+                            Asserts.fail("资源权限插入失败");
+                        }
+                    });
+                }
+                //3.插入超级管理员对应系统 sys_service_menu和sys_role_service_menu
+                savaRoleServiceMenu(menuID, serviceId, 1l);
+            });
+        } else {
+            Asserts.fail("菜单详情插入失败");
+        }
+        return true;
+    }
+
+    /**
+     * @param menuID
+     * @param serviceId
+     * @param roleID
+     * @Method savaRoleServiceMenu
+     * @Author songxl
+     * @Version 1.0
+     * @Description插入超级管理员对应系统 sys_service_menu和sys_role_service_menu
+     * @Return void
+     * @Date 2021/7/28
+     */
+    private void savaRoleServiceMenu(Long menuID, Long serviceId, Long roleID) {
+        ServiceMenu serviceMenu = new ServiceMenu();
+        serviceMenu.setMenuId(menuID);
+        serviceMenu.setServiceId(serviceId);
+        if (serviceMenuFacade.save(serviceMenu)) {
+            Long serviceMenuId = serviceMenuFacade.list(new QueryWrapper<ServiceMenu>()
+                    .eq("service_id", serviceMenu.getServiceId())
+                    .eq("menu_id", serviceMenu.getMenuId())
+                    .eq("is_deleted", IsDeleteEnum.N.getKey())).get(0).getId();
+            RoleServiceMenu roleServiceMenu = new RoleServiceMenu();
+            roleServiceMenu.setRoleId(roleID);
+            roleServiceMenu.setServiceMenuId(serviceMenuId);
+            if (roleServiceMenuFacade.save(roleServiceMenu)) {
+
+            } else {
+                Asserts.fail("角色与服务菜单关系插入失败");
+            }
+        } else {
+            Asserts.fail("服务与菜单对应关系插入失败");
+        }
+    }
+
+    /**
+     * @param menuVO
+     * @Method CRUDOperation
+     * @Author songxl
+     * @Version 1.0
+     * @Description功能菜单CRUD方法
+     * @Return java.lang.Boolean
+     * @Date 2021/7/28
+     */
+    public Boolean CRUDOperation(MenuVO menuVO) {
+
+        try {
+            //1.入参校验
+            inputParamCheck(menuVO);
+            //2.执行操作
+            if (CRUDEnum.ADD.getKey() == menuVO.getOpeType()) {                 //添加
+                return addMenu(menuVO);
+            } else if (CRUDEnum.UPDATE.getKey() == menuVO.getOpeType()) {       //修改
+                return updateDataAuth(menuVO);
+            } else if (CRUDEnum.DELETE.getKey() == menuVO.getOpeType()) {       //删除
+                return deleteDataAuth(menuVO);
+            } else if (CRUDEnum.DISBALE.getKey() == menuVO.getOpeType()) {       //启用禁用
+                return disableDataAuth(menuVO);
+            } else {
+                Asserts.fail("操作码错误");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            Asserts.fail(e.toString());
+        }
+        return false;
+    }
+
+    /**
+     * @param menuVO
+     * @Method disableDataAuth
+     * @Author songxl
+     * @Version 1.0
+     * @Description启用禁用功能菜单
+     * @Return java.lang.Boolean
+     * @Date 2021/7/28
+     */
+    private Boolean disableDataAuth(MenuVO menuVO) {
+
+        return false;
+    }
+
+    /**
+     * @param menuVO
+     * @Method deleteDataAuth
+     * @Author songxl
+     * @Version 1.0
+     * @Description删除功能菜单
+     * @Return java.lang.Boolean
+     * @Date 2021/7/28
+     */
+    private Boolean deleteDataAuth(MenuVO menuVO) {
+
+        return false;
+    }
+
+    /**
+     * @param menuVO
+     * @Method updateDataAuth
+     * @Author songxl
+     * @Version 1.0
+     * @Description修改功能菜单
+     * @Return java.lang.Boolean
+     * @Date 2021/7/28
+     */
+    private Boolean updateDataAuth(MenuVO menuVO) {
+
+        return false;
+    }
+}

+ 75 - 0
security-center/src/main/java/com/lantone/security/web/FuncManagementController.java

@@ -0,0 +1,75 @@
+package com.lantone.security.web;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.lantone.common.api.CommonResult;
+import com.lantone.common.dto.DataAuthDTO;
+import com.lantone.common.dto.DoctorDTO;
+import com.lantone.common.dto.MenuDTO;
+import com.lantone.common.vo.*;
+import com.lantone.security.facade.DataAuthHandleFacade;
+import com.lantone.security.facade.FuncManagementFacade;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * @ClassName: FuncManagementController
+ * @Description: 功能管理API
+ * @Author songxl
+ * @Date 2021/7/27
+ * @Version 1.0
+ */
+@RestController
+@Api(value = "功能管理API", tags = "FuncManagementController")
+@RequestMapping("/func/management")
+public class FuncManagementController {
+    @Autowired
+    private FuncManagementFacade funcManagementFacade;
+
+    @ApiOperation(value = "获取功能菜单列表 [by:songxl]",
+            notes = "RoleServiceMenuVo:角色系统功能菜单对象,必填<br>" +
+                    "roles:角色列表,必填<br>" +
+                    "serviceId:服务id ,必填<br>")
+    @PostMapping("/getMenus")
+    public CommonResult<List<MenuDTO>> getMenus(@RequestBody RoleServiceMenuVo roleServiceMenuVo) {
+        return CommonResult.success(funcManagementFacade.getMenusTree(roleServiceMenuVo));
+    }
+
+    @ApiOperation(value = "添加功能菜单 [by:songxl]",
+            notes = "menuVO:功能菜单对象,必填<br>" +
+                    "opeType:操作码 1:新增;2:修改 ;3:删除;5:启用禁用")
+    @PostMapping("/addMenu")
+    @Transactional
+    public CommonResult<Boolean> addMenu(@RequestBody MenuVO menuVO) {
+        return CommonResult.success(funcManagementFacade.CRUDOperation(menuVO));
+    }
+    @ApiOperation(value = "修改功能菜单 [by:songxl]",
+            notes = "menuVO:功能菜单对象,必填<br>" +
+                    "opeType:操作码 1:新增;2:修改 ;3:删除;5:启用禁用")
+    @PostMapping("/updateMenu")
+    public CommonResult<Boolean> updateMenu(@RequestBody MenuVO menuVO) {
+        return CommonResult.success(funcManagementFacade.CRUDOperation(menuVO));
+    }
+    @ApiOperation(value = "删除功能菜单 [by:songxl]",
+            notes = "menuVO:功能菜单对象,必填<br>" +
+                    "opeType:操作码 1:新增;2:修改 ;3:删除;5:启用禁用")
+    @PostMapping("/deleteMenu")
+    public CommonResult<Boolean> deleteMenu(@RequestBody MenuVO menuVO) {
+        return CommonResult.success(funcManagementFacade.CRUDOperation(menuVO));
+    }
+    @ApiOperation(value = "启用禁用功能菜单 [by:songxl]",
+            notes = "menuVO:功能菜单对象,必填<br>" +
+                    "opeType:操作码 1:新增;2:修改 ;3:删除;5:启用禁用")
+    @PostMapping("/disableMenu")
+    public CommonResult<Boolean> disableMenu(@RequestBody MenuVO menuVO) {
+        return CommonResult.success(funcManagementFacade.CRUDOperation(menuVO));
+    }
+
+}