package com.oying.modules.system.service.impl;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.oying.modules.system.domain.Menu;
|
import com.oying.modules.system.domain.Role;
|
import com.oying.modules.system.domain.User;
|
import com.oying.modules.system.domain.dto.MenuMetaVo;
|
import com.oying.modules.system.domain.dto.MenuQueryCriteria;
|
import com.oying.modules.system.domain.dto.MenuVo;
|
import com.oying.modules.system.mapper.MenuMapper;
|
import com.oying.modules.system.mapper.RoleMenuMapper;
|
import com.oying.modules.system.mapper.UserMapper;
|
import com.oying.modules.system.service.MenuService;
|
import com.oying.modules.system.service.RoleService;
|
import lombok.RequiredArgsConstructor;
|
import com.oying.utils.CacheKey;
|
import com.oying.utils.FileUtil;
|
import com.oying.utils.RedisUtils;
|
import com.oying.utils.StringUtils;
|
import com.oying.exception.BadRequestException;
|
import com.oying.exception.EntityExistException;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import javax.servlet.http.HttpServletResponse;
|
import java.io.IOException;
|
import java.lang.reflect.Field;
|
import java.util.*;
|
import java.util.concurrent.TimeUnit;
|
import java.util.stream.Collectors;
|
|
/**
|
* @author Z
|
*/
|
@Service
|
@RequiredArgsConstructor
|
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
|
|
private final MenuMapper menuMapper;
|
private final RoleMenuMapper roleMenuMapper;
|
private final UserMapper userMapper;
|
private final RoleService roleService;
|
private final RedisUtils redisUtils;
|
|
private static final String HTTP_PRE = "http://";
|
private static final String HTTPS_PRE = "https://";
|
private static final String YES_STR = "是";
|
private static final String NO_STR = "否";
|
private static final String BAD_REQUEST = "外链必须以http://或者https://开头";
|
|
@Override
|
public List<Menu> queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception {
|
if(Boolean.TRUE.equals(isQuery)){
|
criteria.setPidIsNull(true);
|
List<Field> fields = StringUtils.getAllFields(criteria.getClass(), new ArrayList<>());
|
for (Field field : fields) {
|
//设置对象的访问权限,保证对private的属性的访问
|
field.setAccessible(true);
|
Object val = field.get(criteria);
|
if("pidIsNull".equals(field.getName())){
|
continue;
|
}
|
// 如果有查询条件,则不指定pidIsNull
|
if (ObjectUtil.isNotNull(val)) {
|
criteria.setPidIsNull(null);
|
break;
|
}
|
}
|
}
|
return menuMapper.findAll(criteria);
|
}
|
|
@Override
|
public Menu findById(long id) {
|
String key = CacheKey.MENU_ID + id;
|
Menu menu = redisUtils.get(key, Menu.class);
|
if(menu == null){
|
menu = getById(id);
|
redisUtils.set(key, menu, 1, TimeUnit.DAYS);
|
}
|
return menu;
|
}
|
|
/**
|
* 用户角色改变时需清理缓存
|
* @param currentUserId /
|
* @return /
|
*/
|
@Override
|
public List<Menu> findByUser(Long currentUserId) {
|
String key = CacheKey.MENU_USER + currentUserId;
|
List<Menu> menus = redisUtils.getList(key, Menu.class);
|
if (CollUtil.isEmpty(menus)){
|
List<Role> roles = roleService.findByUsersId(currentUserId);
|
Set<Long> roleIds = roles.stream().map(Role::getId).collect(Collectors.toSet());
|
menus = new ArrayList<>(menuMapper.findByRoleIdsAndTypeNot(roleIds, 2));
|
redisUtils.set(key, menus, 1, TimeUnit.DAYS);
|
}
|
return menus;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void create(Menu resources) {
|
if(menuMapper.findByTitle(resources.getTitle()) != null){
|
throw new EntityExistException(Menu.class,"title",resources.getTitle());
|
}
|
if(StringUtils.isNotBlank(resources.getComponentName())){
|
if(menuMapper.findByComponentName(resources.getComponentName()) != null){
|
throw new EntityExistException(Menu.class,"componentName",resources.getComponentName());
|
}
|
}
|
if (Long.valueOf(0L).equals(resources.getPid())) {
|
resources.setPid(null);
|
}
|
if(resources.getIFrame()){
|
if (!(resources.getPath().toLowerCase().startsWith(HTTP_PRE)||resources.getPath().toLowerCase().startsWith(HTTPS_PRE))) {
|
throw new BadRequestException(BAD_REQUEST);
|
}
|
}
|
save(resources);
|
// 计算子节点数目
|
resources.setSubCount(0);
|
// 更新父节点菜单数目
|
updateSubCnt(resources.getPid());
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void update(Menu resources) {
|
if(resources.getId().equals(resources.getPid())) {
|
throw new BadRequestException("上级不能为自己");
|
}
|
Menu menu = getById(resources.getId());
|
if(resources.getIFrame()){
|
if (!(resources.getPath().toLowerCase().startsWith(HTTP_PRE)||resources.getPath().toLowerCase().startsWith(HTTPS_PRE))) {
|
throw new BadRequestException(BAD_REQUEST);
|
}
|
}
|
Menu menu1 = menuMapper.findByTitle(resources.getTitle());
|
|
if(menu1 != null && !menu1.getId().equals(menu.getId())){
|
throw new EntityExistException(Menu.class,"title",resources.getTitle());
|
}
|
|
if(resources.getPid().equals(0L)){
|
resources.setPid(null);
|
}
|
|
// 记录的父节点ID
|
Long oldPid = menu.getPid();
|
Long newPid = resources.getPid();
|
|
if(StringUtils.isNotBlank(resources.getComponentName())){
|
menu1 = menuMapper.findByComponentName(resources.getComponentName());
|
if(menu1 != null && !menu1.getId().equals(menu.getId())){
|
throw new EntityExistException(Menu.class,"componentName",resources.getComponentName());
|
}
|
}
|
menu.setTitle(resources.getTitle());
|
menu.setComponent(resources.getComponent());
|
menu.setPath(resources.getPath());
|
menu.setIcon(resources.getIcon());
|
menu.setIFrame(resources.getIFrame());
|
menu.setPid(resources.getPid());
|
menu.setMenuSort(resources.getMenuSort());
|
menu.setCache(resources.getCache());
|
menu.setHidden(resources.getHidden());
|
menu.setComponentName(resources.getComponentName());
|
menu.setPermission(resources.getPermission());
|
menu.setType(resources.getType());
|
saveOrUpdate(menu);
|
// 计算父级菜单节点数目
|
updateSubCnt(oldPid);
|
updateSubCnt(newPid);
|
// 清理缓存
|
delCaches(resources.getId());
|
}
|
|
@Override
|
public Set<Menu> getChildMenus(List<Menu> menuList, Set<Menu> menuSet) {
|
for (Menu menu : menuList) {
|
menuSet.add(menu);
|
List<Menu> menus = menuMapper.findByPidOrderByMenuSort(menu.getId());
|
if(CollUtil.isNotEmpty(menus)){
|
getChildMenus(menus, menuSet);
|
}
|
}
|
return menuSet;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void delete(Set<Menu> menuSet) {
|
for (Menu menu : menuSet) {
|
// 清理缓存
|
delCaches(menu.getId());
|
roleMenuMapper.deleteByMenuId(menu.getId());
|
menuMapper.deleteById(menu.getId());
|
updateSubCnt(menu.getPid());
|
}
|
}
|
|
@Override
|
public List<Menu> getMenus(Long pid) {
|
List<Menu> menus;
|
if(pid != null && !pid.equals(0L)){
|
menus = menuMapper.findByPidOrderByMenuSort(pid);
|
} else {
|
menus = menuMapper.findByPidIsNullOrderByMenuSort();
|
}
|
return menus;
|
}
|
|
@Override
|
public List<Menu> getSuperior(Menu menu, List<Menu> menus) {
|
if(menu.getPid() == null){
|
menus.addAll(menuMapper.findByPidIsNullOrderByMenuSort());
|
return menus;
|
}
|
menus.addAll(menuMapper.findByPidOrderByMenuSort(menu.getPid()));
|
return getSuperior(findById(menu.getPid()), menus);
|
}
|
|
@Override
|
public List<Menu> buildTree(List<Menu> menus) {
|
List<Menu> trees = new ArrayList<>();
|
Set<Long> ids = new HashSet<>();
|
for (Menu menu : menus) {
|
if (menu.getPid() == null) {
|
trees.add(menu);
|
}
|
for (Menu it : menus) {
|
if (menu.getId().equals(it.getPid())) {
|
if (menu.getChildren() == null) {
|
menu.setChildren(new ArrayList<>());
|
}
|
menu.getChildren().add(it);
|
ids.add(it.getId());
|
}
|
}
|
}
|
if(CollUtil.isNotEmpty(trees)){
|
trees = menus.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList());
|
}
|
return trees;
|
}
|
|
@Override
|
public List<MenuVo> buildMenus(List<Menu> menus) {
|
List<MenuVo> list = new LinkedList<>();
|
menus.forEach(menu -> {
|
if (menu!=null){
|
List<Menu> menuList = menu.getChildren();
|
MenuVo menuVo = new MenuVo();
|
menuVo.setName(ObjectUtil.isNotEmpty(menu.getComponentName()) ? menu.getComponentName() : menu.getTitle());
|
// 一级目录需要加斜杠,不然会报警告
|
menuVo.setPath(menu.getPid() == null ? "/" + menu.getPath() :menu.getPath());
|
menuVo.setHidden(menu.getHidden());
|
// 如果不是外链
|
if(!menu.getIFrame()){
|
if(menu.getPid() == null){
|
menuVo.setComponent(StringUtils.isEmpty(menu.getComponent())?"Layout":menu.getComponent());
|
// 如果不是一级菜单,并且菜单类型为目录,则代表是多级菜单
|
}else if(menu.getType() == 0){
|
menuVo.setComponent(StringUtils.isEmpty(menu.getComponent())?"ParentView":menu.getComponent());
|
}else if(StringUtils.isNoneBlank(menu.getComponent())){
|
menuVo.setComponent(menu.getComponent());
|
}
|
}
|
menuVo.setMeta(new MenuMetaVo(menu.getTitle(),menu.getIcon(),!menu.getCache()));
|
if(CollectionUtil.isNotEmpty(menuList)){
|
menuVo.setAlwaysShow(true);
|
menuVo.setRedirect("noredirect");
|
menuVo.setChildren(buildMenus(menuList));
|
// 处理是一级菜单并且没有子菜单的情况
|
} else if(menu.getPid() == null){
|
MenuVo menuVo1 = getMenuVo(menu, menuVo);
|
menuVo.setName(null);
|
menuVo.setMeta(null);
|
menuVo.setComponent("Layout");
|
List<MenuVo> list1 = new ArrayList<>();
|
list1.add(menuVo1);
|
menuVo.setChildren(list1);
|
}
|
list.add(menuVo);
|
}
|
}
|
);
|
return list;
|
}
|
|
@Override
|
public void download(List<Menu> menus, HttpServletResponse response) throws IOException {
|
List<Map<String, Object>> list = new ArrayList<>();
|
for (Menu menu : menus) {
|
Map<String,Object> map = new LinkedHashMap<>();
|
map.put("菜单标题", menu.getTitle());
|
map.put("菜单类型", menu.getType() == null ? "目录" : menu.getType() == 1 ? "菜单" : "按钮");
|
map.put("权限标识", menu.getPermission());
|
map.put("外链菜单", menu.getIFrame() ? YES_STR : NO_STR);
|
map.put("菜单可见", menu.getHidden() ? NO_STR : YES_STR);
|
map.put("是否缓存", menu.getCache() ? YES_STR : NO_STR);
|
map.put("创建日期", menu.getCreateTime());
|
list.add(map);
|
}
|
FileUtil.downloadExcel(list, response);
|
}
|
|
private void updateSubCnt(Long menuId){
|
if(menuId != null){
|
int count = menuMapper.countByPid(menuId);
|
menuMapper.updateSubCntById(count, menuId);
|
}
|
}
|
|
/**
|
* 清理缓存
|
* @param id 菜单ID
|
*/
|
public void delCaches(Long id){
|
List<User> users = userMapper.findByMenuId(id);
|
redisUtils.del(CacheKey.MENU_ID + id);
|
redisUtils.delByKeys(CacheKey.MENU_USER, users.stream().map(User::getId).collect(Collectors.toSet()));
|
// 清除 Role 缓存
|
List<Role> roles = roleService.findByMenuId(id);
|
redisUtils.delByKeys(CacheKey.ROLE_ID, roles.stream().map(Role::getId).collect(Collectors.toSet()));
|
}
|
|
/**
|
* 获取 MenuVo
|
* @param menu /
|
* @param menuVo /
|
* @return /
|
*/
|
private static MenuVo getMenuVo(Menu menu, MenuVo menuVo) {
|
MenuVo menuVo1 = new MenuVo();
|
menuVo1.setMeta(menuVo.getMeta());
|
// 非外链
|
if(!menu.getIFrame()){
|
menuVo1.setPath("index");
|
menuVo1.setName(menuVo.getName());
|
menuVo1.setComponent(menuVo.getComponent());
|
} else {
|
menuVo1.setPath(menu.getPath());
|
}
|
return menuVo1;
|
}
|
}
|