删除ResultUtils类,Result类重命名为R并具有ResultUtils的所有功能,修复CustomUserCache获取当前用户为空,直接返回,现在是去数据库查,菜单相关功能基本完成,现在DataBaseUrl投票器,和LoginFilter改成方便调试,去掉验证码功能,和鉴权功能,

master
GPU is all you need 4 years ago
parent be0b14b7a1
commit 86b40e1fe5
  1. 5
      awardBE/src/main/java/edu/ncst/award/common/core/controller/BaseController.java
  2. 9
      awardBE/src/main/java/edu/ncst/award/config/security/CustomUserCache.java
  3. 120
      awardBE/src/main/java/edu/ncst/award/config/security/DataBaseUrlVoter.java
  4. 6
      awardBE/src/main/java/edu/ncst/award/config/security/SecurityConfig.java
  5. 5
      awardBE/src/main/java/edu/ncst/award/config/security/filter/AuthCheckFilter.java
  6. 23
      awardBE/src/main/java/edu/ncst/award/config/security/filter/LoginFilter.java
  7. 152
      awardBE/src/main/java/edu/ncst/award/controller/MenuController.java
  8. 34
      awardBE/src/main/java/edu/ncst/award/domain/RoleMenu.java
  9. 13
      awardBE/src/main/java/edu/ncst/award/mapper/MenuMapper.java
  10. 13
      awardBE/src/main/java/edu/ncst/award/mapper/RoleMenuMapper.java
  11. 13
      awardBE/src/main/java/edu/ncst/award/model/system/Menu.java
  12. 8
      awardBE/src/main/java/edu/ncst/award/model/system/Role.java
  13. 83
      awardBE/src/main/java/edu/ncst/award/service/IMenuService.java
  14. 137
      awardBE/src/main/java/edu/ncst/award/service/impl/system/MenuServiceImpl.java
  15. 2939
      awardBE/src/main/resources/5-12-interface.json
  16. 34
      awardBE/src/main/resources/mapper/MenuMapper.xml
  17. 32
      awardBE/src/test/java/edu/ncst/award/TestSystemMenuService.java

@ -1,6 +1,5 @@
package edu.ncst.award.common.core.controller;
import edu.ncst.award.utils.ResultUtils;
import edu.ncst.award.domain.vo.R;
/**
@ -17,7 +16,7 @@ public class BaseController {
* @return 操作结果
*/
protected R<Void> toAjax(int rows) {
return rows > 0 ? ResultUtils.ok() : ResultUtils.fail();
return rows > 0 ? R.ok() : R.fail();
}
/**
@ -27,7 +26,7 @@ public class BaseController {
* @return 操作结果
*/
protected R<Void> toAjax(boolean result) {
return result ? ResultUtils.ok() : ResultUtils.fail();
return result ? R.ok() : R.fail();
}
}

@ -2,9 +2,12 @@ package edu.ncst.award.config.security;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import edu.ncst.award.model.system.User;
import edu.ncst.award.domain.vo.result.UserInfoVO;
import edu.ncst.award.service.IUserService;
import edu.ncst.award.service.impl.system.UserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
@ -12,6 +15,8 @@ import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Slf4j
@Component
@ -87,6 +92,10 @@ public class CustomUserCache implements UserCache {
if (ObjectUtil.isNotNull(userInfoVO) && ObjectUtil.isNull(userInfoVO.getUsername())) {
currentUser = (User) getUserFromCache(userInfoVO.getUsername());
}
if (currentUser == null){
currentUser = (User) SpringUtil.getBean(UserServiceImpl.class).loadUserByUsername(userInfoVO.getUsername());
putUserInCache(currentUser);
}
return currentUser;
}
}

@ -38,65 +38,69 @@ public class DataBaseUrlVoter implements AccessDecisionVoter<FilterInvocation> {
@Override
public int vote(Authentication authentication, FilterInvocation fi, Collection<ConfigAttribute> attributes) {
if (authentication == null) {
return ACCESS_DENIED; // 反对票
}
String url = fi.getRequestUrl(); // 当前请求的URL
String urlWithoutQueryString = URLUtils.removeQueryString(url);
// Current User Info
Object details = authentication.getDetails();
if (details instanceof UserInfoVO) {
UserInfoVO userInfoVO = (UserInfoVO) details;
AntPathMatcher antPathMatcher = new AntPathMatcher();
//获取不限用户角色的资源
List<String> permitAllResourceURLs = resourceService.getPermitAllResourceURLs();
// Permit All Resource
for (String permitUrl : permitAllResourceURLs) {
boolean match = antPathMatcher.match(permitUrl, urlWithoutQueryString);
if (match) {
return ACCESS_GRANTED; // 赞同票
}
}
// 判断用户角色信息
// 反对票:1、没有角色信息 2、角色未绑定该资源
// 赞成票:用户是超级管理员
List<Role> roles = userInfoVO.getRoles();
if (roles == null || roles.isEmpty()) {
return ACCESS_DENIED; // 反对票
}
List<String> roleNames = roles.stream().map(Role::getName).collect(Collectors.toList());
// Super Admin User Always Pass
if (roleNames.contains("SUPER_ADMIN")) {
return ACCESS_GRANTED; // 赞同票
}
List<Resource> rolesResourceList = resourceService.getUserScopeResourceList(roleNames);//获取目标角色绑定的资源
// Role Resource
if (rolesResourceList == null || rolesResourceList.size() <=0) {
return ACCESS_DENIED; // 反对票
}
// 当方法和url都匹配上才匹配成功
for (Resource resource : rolesResourceList) {
boolean match = antPathMatcher.match(resource.getUrl(), urlWithoutQueryString)
&& fi.getHttpRequest().getMethod().equals(resource.getMethod());
if (match) {
return ACCESS_GRANTED; // 赞同票
}
}
}
return ACCESS_DENIED;
// 方便测试
return ACCESS_GRANTED;
// if (authentication == null) {
// return ACCESS_DENIED; // 反对票
// }
//
// String url = fi.getRequestUrl(); // 当前请求的URL
// String urlWithoutQueryString = URLUtils.removeQueryString(url);
//
// // Current User Info
// Object details = authentication.getDetails();
//
// if (details instanceof UserInfoVO) {
// UserInfoVO userInfoVO = (UserInfoVO) details;
// AntPathMatcher antPathMatcher = new AntPathMatcher();
//
// //获取不限用户角色的资源
// List<String> permitAllResourceURLs = resourceService.getPermitAllResourceURLs();
// // Permit All Resource
// for (String permitUrl : permitAllResourceURLs) {
// boolean match = antPathMatcher.match(permitUrl, urlWithoutQueryString);
// if (match) {
// return ACCESS_GRANTED; // 赞同票
// }
// }
//
// // 判断用户角色信息
// // 反对票:1、没有角色信息 2、角色未绑定该资源
// // 赞成票:用户是超级管理员
//
// List<Role> roles = userInfoVO.getRoles();
// if (roles == null || roles.isEmpty()) {
// return ACCESS_DENIED; // 反对票
// }
//
// List<String> roleNames = roles.stream().map(Role::getName).collect(Collectors.toList());
//
// // Super Admin User Always Pass
// if (roleNames.contains("SUPER_ADMIN")) {
// return ACCESS_GRANTED; // 赞同票
// }
//
// List<Resource> rolesResourceList = resourceService.getUserScopeResourceList(roleNames);//获取目标角色绑定的资源
//
//
// // Role Resource
// if (rolesResourceList == null || rolesResourceList.size() <=0) {
// return ACCESS_DENIED; // 反对票
// }
//
// // 当方法和url都匹配上才匹配成功
// for (Resource resource : rolesResourceList) {
// boolean match = antPathMatcher.match(resource.getUrl(), urlWithoutQueryString)
// && fi.getHttpRequest().getMethod().equals(resource.getMethod());
// if (match) {
// return ACCESS_GRANTED; // 赞同票
// }
// }
// }
//
// return ACCESS_DENIED;
}
Collection<? extends GrantedAuthority> extractAuthorities(

@ -3,10 +3,10 @@ package edu.ncst.award.config.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.ncst.award.config.security.filter.AuthCheckFilter;
import edu.ncst.award.config.security.filter.LoginFilter;
import edu.ncst.award.domain.vo.R;
import edu.ncst.award.exception.CodeMsg;
import edu.ncst.award.service.ILoginLogService;
import edu.ncst.award.service.impl.system.UserServiceImpl;
import edu.ncst.award.utils.ResultUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
@ -161,7 +161,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
out.write(new ObjectMapper().writeValueAsString(ResultUtils.fail(CodeMsg.USER_NEED_LOGIN)));
out.write(new ObjectMapper().writeValueAsString(R.fail(CodeMsg.USER_NEED_LOGIN)));
out.flush();
out.close();
}));
@ -173,7 +173,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
.logoutSuccessHandler(((request, response, authentication) -> {
PrintWriter out = response.getWriter();
response.setContentType("application/json");
out.write(new ObjectMapper().writeValueAsString(ResultUtils.ok("注销成功")));
out.write(new ObjectMapper().writeValueAsString(R.ok("注销成功")));
out.flush();
out.close();
}));

@ -5,7 +5,6 @@ import edu.ncst.award.config.security.token.JwtAuthenticationToken;
import edu.ncst.award.exception.CodeMsg;
import edu.ncst.award.model.system.Role;
import edu.ncst.award.utils.ResponseUtils;
import edu.ncst.award.utils.ResultUtils;
import edu.ncst.award.domain.vo.R;
import edu.ncst.award.domain.vo.result.UserInfoVO;
import io.jsonwebtoken.Claims;
@ -78,7 +77,7 @@ public class AuthCheckFilter extends OncePerRequestFilter {
if (jwtToken == null || "".equals(jwtToken)) {
log.error("鉴权TOKEN:未获取,用户需要登录");
R<Object> r = ResultUtils.fail(CodeMsg.USER_NEED_LOGIN);
R<Object> r = R.fail(CodeMsg.USER_NEED_LOGIN);
ResponseUtils.output(response, r);
} else {
log.info("鉴权TOKEN:" + "Bearer " + jwtToken);
@ -115,7 +114,7 @@ public class AuthCheckFilter extends OncePerRequestFilter {
JwtAuthenticationToken token = new JwtAuthenticationToken(userName, authorities, userInfoVO);
SecurityContextHolder.getContext().setAuthentication(token);
} catch (ExpiredJwtException e) {
R<Object> r = ResultUtils.fail(CodeMsg.USER_TOKEN_EXPIRED);// 用户凭证过期
R<Object> r = R.fail(CodeMsg.USER_TOKEN_EXPIRED);// 用户凭证过期
ResponseUtils.output(response, r);
} finally {
filterChain.doFilter(request, response);

@ -7,7 +7,6 @@ import edu.ncst.award.exception.CodeMsg;
import edu.ncst.award.model.system.Role;
import edu.ncst.award.model.system.User;
import edu.ncst.award.service.ILoginLogService;
import edu.ncst.award.utils.ResultUtils;
import edu.ncst.award.domain.vo.R;
import edu.ncst.award.domain.vo.param.UserLoginDTO;
import edu.ncst.award.domain.vo.result.UserInfoVO;
@ -162,7 +161,7 @@ public class LoginFilter extends AbstractAuthenticationProcessingFilter {//OnceP
loginLogService.addLoginLog(userInfoVO.getId(), true);
// 返回结果
R<String> result = ResultUtils.ok("登录成功", jwt);
R<String> result = R.ok("登录成功", jwt);
response.setContentType("application/json;charset=utf-8");
Cookie cookieToken = new Cookie("SYS_TOKEN", jwt);
cookieToken.setHttpOnly(true);
@ -218,37 +217,37 @@ public class LoginFilter extends AbstractAuthenticationProcessingFilter {//OnceP
R<?> r = new R<>();
log.debug("登录失败:" + failed);
if (failed instanceof LockedException) {
r = ResultUtils.fail(CodeMsg.USER_IS_LOCKED);
r = R.fail(CodeMsg.USER_IS_LOCKED);
} else if (failed instanceof CredentialsExpiredException) {
if (failed.getMessage() != null) {
r = ResultUtils.fail(failed.getMessage());
r = R.fail(failed.getMessage());
}
r = ResultUtils.fail(CodeMsg.USER_CREDENTIALS_EXPIRED);
r = R.fail(CodeMsg.USER_CREDENTIALS_EXPIRED);
} else if (failed instanceof AccountExpiredException) {
r = ResultUtils.fail(CodeMsg.USER_ACCOUNT_EXPIRED);
r = R.fail(CodeMsg.USER_ACCOUNT_EXPIRED);
} else if (failed instanceof DisabledException) {
r = ResultUtils.fail(CodeMsg.USER_IS_DISABLED);
r = R.fail(CodeMsg.USER_IS_DISABLED);
} else if (failed instanceof AuthenticationException) {
if (failed instanceof BusinessException) {
stringRedisTemplate.delete("captcha:" + tempToken);
BusinessException businessException = (BusinessException) failed;
r = ResultUtils.fail(businessException.getError());
r = R.fail(businessException.getError());
} else {
Throwable cause = failed.getCause();
if (cause instanceof BusinessException) {
BusinessException businessException = (BusinessException) cause;
r = ResultUtils.fail(businessException.getError());
r = R.fail(businessException.getError());
} else {
if (failed instanceof UsernameNotFoundException) {
r = ResultUtils.fail(failed.getMessage(), false);
r = R.fail(failed.getMessage(), false);
} else {
r = ResultUtils.fail(CodeMsg.USER_BAD_CREDENTIALS);
r = R.fail(CodeMsg.USER_BAD_CREDENTIALS);
}
}
}
} else {
r = ResultUtils.fail(CodeMsg.LOGIN_FAIL);
r = R.fail(CodeMsg.LOGIN_FAIL);
}
// 拦截后直接将错误信息反馈给前端,不经过全局异常处理器(GlobalExceptionHandler)处理

@ -1,18 +1,26 @@
package edu.ncst.award.controller;
import cn.hutool.core.lang.tree.Tree;
import edu.ncst.award.common.annotation.Log;
import edu.ncst.award.common.annotation.enums.BusinessType;
import edu.ncst.award.common.constant.UserConstants;
import edu.ncst.award.common.core.controller.BaseController;
import edu.ncst.award.domain.vo.R;
import edu.ncst.award.model.system.Menu;
import edu.ncst.award.service.IMenuService;
import edu.ncst.award.service.IUserService;
import edu.ncst.award.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -23,7 +31,7 @@ import java.util.List;
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/menu")
public class MenuController {
public class MenuController extends BaseController {
private final IMenuService menuService;
private final IUserService userService;
@ -38,25 +46,88 @@ public class MenuController {
return R.ok(menus);
}
//
// public MenuController(IMenuService menuService) {
// this.menuService = menuService;
// }
//
// @ApiOperation("获取菜单列表")
// @GetMapping("/list")
// public ResultVO<ListResultVO<Menu>> getMenuList(Query query) {
// ListResultVO<Menu> menuList = menuService.getMenuList(query);
//
// return ResultUtils.success("ok", menuList);
// }
//
// @ApiOperation("获取菜单树")
// @GetMapping("/tree")
// public ResultVO<List<Menu>> getMenuTree() {
// List<Menu> menuTree = menuService.getMenuTree();
// return ResultUtils.success("ok", menuTree);
// }
/**
* 根据菜单编号获取详细信息
*/
@ApiOperation("根据菜单编号获取详细信息")
@GetMapping(value = "/{menuId}")
public R<Menu> getInfo(@ApiParam("菜单ID") @PathVariable Long menuId) {
return R.ok(menuService.selectMenuById(menuId));
}
/**
* 获取菜单下拉树列表
*/
@ApiOperation("获取菜单下拉树列表")
@GetMapping("/treeSelect")
public R<List<Tree<Integer>>> treeSelect(Menu menu) {
List<Menu> menus = menuService.selectMenuList(menu, userService.getCurrentUser().getId());
return R.ok(menuService.buildMenuTreeSelect(menus));
}
/**
* 加载对应角色菜单列表树
*/
@ApiOperation("加载对应角色菜单列表树")
@GetMapping(value = "/roleMenuTreeSelect/{roleId}")
public R<Map<String, Object>> roleMenuTreeSelect(@ApiParam("角色ID") @PathVariable("roleId") Long roleId) {
List<Menu> menus = menuService.selectMenuList(userService.getCurrentUser().getId());
Map<String, Object> ajax = new HashMap<>();
ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
ajax.put("menus", menuService.buildMenuTreeSelect(menus));
return R.ok(ajax);
}
/**
* 新增菜单
*/
@ApiOperation("新增菜单")
@Log(title = "菜单管理", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody Menu menu) {
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) {
return R.fail("新增菜单'" + menu.getName() + "'失败,菜单名称已存在");
} else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getRoutePath())) {
return R.fail("新增菜单'" + menu.getName() + "'失败,地址必须以http(s)://开头");
}
return toAjax(menuService.insertMenu(menu));
}
/**
* 修改菜单
*/
@ApiOperation("修改菜单")
@Log(title = "菜单管理", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody Menu menu) {
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) {
return R.fail("修改菜单'" + menu.getName() + "'失败,菜单名称已存在");
} else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getRoutePath())) {
return R.fail("修改菜单'" + menu.getName() + "'失败,地址必须以http(s)://开头");
} else if (menu.getId().equals(menu.getParentId())) {
return R.fail("修改菜单'" + menu.getName() + "'失败,上级菜单不能选择自己");
}
return toAjax(menuService.updateMenu(menu));
}
/**
* 删除菜单
*/
@ApiOperation("删除菜单")
@Log(title = "菜单管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{menuId}")
public R<Void> remove(@ApiParam("菜单ID") @PathVariable("menuId") Long menuId) {
if (menuService.hasChildByMenuId(menuId)) {
return R.fail("存在子菜单,不允许删除");
}
if (menuService.checkMenuExistRole(menuId)) {
return R.fail("菜单已分配,不允许删除");
}
return toAjax(menuService.deleteMenuById(menuId));
}
//
// @ApiOperation("获取指定角色能够访问的菜单ID列表")
// @GetMapping("/ids/role")
@ -64,40 +135,7 @@ public class MenuController {
// List<Integer> menuIds = menuService.getRoleMenuIds(roleId,true);
// return ResultUtils.success("ok", menuIds);
// }
//
// @ApiOperation("获取菜单详情")
// @PostMapping("/detail")
// public ResultVO<Menu> getMenuDetail(@RequestParam Integer id) {
// Menu menuDetail = menuService.getMenuDetail(id);
//
// return ResultUtils.success("ok", menuDetail);
// }
//
// @ApiOperation("添加菜单")
// @PostMapping("/add")
// public ResultVO<Menu> addMenu(@RequestBody Menu menu) {
// log.info("将要添加的菜单:" + menu);
// Menu result = menuService.addMenu(menu);
//
// return ResultUtils.success("ok", result);
// }
//
// @ApiOperation("修改菜单")
// @PostMapping("/modify")
// public ResultVO<Menu> modifyMenu(@RequestBody Menu menu) {
// Menu result = menuService.modifyMenu(menu);
//
// return ResultUtils.success("ok", result);
// }
//
// @ApiOperation("删除菜单")
// @PostMapping("/delete")
// public ResultVO<Menu> deleteMenu(@RequestParam Integer id) {
// menuService.deleteMenu(id);
//
// return ResultUtils.success("ok", null);
// }
//
//
// @ApiOperation("获取指定用户可访问的菜单列表")
// @GetMapping("/user/{userId}")

@ -0,0 +1,34 @@
package edu.ncst.award.domain;
import com.baomidou.mybatisplus.annotation.IdType;
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;
/**
* 角色和菜单关联 sys_role_menu
*
* @author Lion Li
*/
@Data
@TableName("sys_role_menu")
@ApiModel("角色和菜单关联")
public class RoleMenu {
/**
* 角色ID
*/
@TableId(type = IdType.INPUT)
@ApiModelProperty(value = "角色ID")
private Long roleId;
/**
* 菜单ID
*/
@ApiModelProperty(value = "角色ID")
private Long menuId;
}

@ -21,9 +21,18 @@ public interface MenuMapper extends BaseMapper<Menu> {
List<Menu> getMenuTree(@Param("parentId") Integer parentId);
List<Menu> selectMenuByUserId(Integer userId);
List<Menu> selectMenuByUserId(@Param("userId") Integer userId);
List<Menu> selectMenuListByUserId(Menu menu, Long userId);
List<Menu> selectMenuListByUserId(@Param("menu") Menu menu, @Param("userId") Long userId);
/**
* 根据角色ID查询菜单树信息
*
* @param roleId 角色ID
* @param menuCheckStrictly 菜单树选择项是否关联显示
* @return 选中菜单列表
*/
List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
// // 清空菜单项
// int removeAllMenuItem();

@ -0,0 +1,13 @@
package edu.ncst.award.mapper;
import edu.ncst.award.common.mapper.BaseMapperPlus;
import edu.ncst.award.domain.RoleMenu;
/**
* 角色与菜单关联表 数据层
*
* @author Lion Li
*/
public interface RoleMenuMapper extends BaseMapperPlus<RoleMenuMapper, RoleMenu, RoleMenu> {
}

@ -62,7 +62,7 @@ public class Menu extends TreeNode implements Serializable {
@ApiModelProperty(value = "是否显示在菜单上")
private Boolean showInMenu = true;
@ApiModelProperty(value = "显示排序")
@ApiModelProperty(value = "排序权重")
private Integer sort = 0;
@ApiModelProperty(value = "备注")
@ -72,6 +72,17 @@ public class Menu extends TreeNode implements Serializable {
@TableLogic
private Date deleteTime;
@ApiModelProperty(value = "是否启用")
private Boolean status;
/**
* 是否为外链0是 1否
*/
@ApiModelProperty(value = "是否为外链(0是 1否)")
@TableField(exist = false)
private String isFrame;
@ApiModelProperty(value = "菜单树路径")
@TableField(exist = false)
private String treePath;

@ -32,6 +32,14 @@ public class Role extends BaseEntity {
@ApiModelProperty(value = "显示文本")
private String label;
/**
* 菜单树选择项是否关联显示 0父子不互相关联显示 1父子互相关联显示
*/
@ApiModelProperty(value = "菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示)")
@TableField(exist = false)
private boolean menuCheckStrictly;
@ApiModelProperty(value = "是否启用")
private Boolean enable;

@ -1,8 +1,9 @@
package edu.ncst.award.service;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.service.IService;
import edu.ncst.award.model.system.Menu;
import edu.ncst.award.domain.vo.RouterVo;
import edu.ncst.award.model.system.Menu;
import java.util.List;
@ -11,13 +12,14 @@ import java.util.List;
*/
public interface IMenuService extends IService<Menu> {
/**
* 根据用户查询系统菜单列表
*
* @param menu 菜单信息
* @param userId 用户ID
* @return 菜单列表
*/
List<Menu> selectMenuList(Menu menu);
List<Menu> selectMenuList(Long userId);
/**
* 根据用户查询系统菜单列表
@ -28,6 +30,80 @@ public interface IMenuService extends IService<Menu> {
*/
List<Menu> selectMenuList(Menu menu, Long userId);
/**
* 根据角色ID查询菜单树信息
*
* @param roleId 角色ID
* @return 选中菜单列表
*/
List<Long> selectMenuListByRoleId(Long roleId);
/**
* 根据菜单ID查询信息
*
* @param menuId 菜单ID
* @return 菜单信息
*/
Menu selectMenuById(Long menuId);
/**
* 构建前端所需要下拉树结构
*
* @param menus 菜单列表
* @return 下拉树结构列表
*/
List<Tree<Integer>> buildMenuTreeSelect(List<Menu> menus);
/**
* 校验菜单名称是否唯一
*
* @param menu 菜单信息
* @return 结果
*/
String checkMenuNameUnique(Menu menu);
/**
* 新增保存菜单信息
*
* @param menu 菜单信息
* @return 结果
*/
int insertMenu(Menu menu);
/**
* 修改菜单信息
*
* @param menu 菜单信息
* @return 结果
*/
int updateMenu(Menu menu);
/**
* 是否存在菜单子节点
*
* @param menuId 菜单ID
* @return 结果 true 存在 false 不存在
*/
boolean hasChildByMenuId(Long menuId);
/**
* 查询菜单是否存在角色
*
* @param menuId 菜单ID
* @return 结果 true 存在 false 不存在
*/
boolean checkMenuExistRole(Long menuId);
/**
* 删除菜单管理信息
*
* @param menuId 菜单ID
* @return 结果
*/
int deleteMenuById(Long menuId);
// // 获取菜单列表
// ListResultVO<Menu> getMenuList(Query query);
//
@ -76,6 +152,7 @@ public interface IMenuService extends IService<Menu> {
/**
* 获取当前用户能够访问的路由菜单列表
*
* @param userId 用户id
*/
List<Menu> selectMenuByUserId(Integer userId);

@ -1,16 +1,26 @@
package edu.ncst.award.service.impl.system;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.ncst.award.common.constant.UserConstants;
import edu.ncst.award.common.util.treeUtils.TreeUtils;
import edu.ncst.award.domain.RoleMenu;
import edu.ncst.award.domain.vo.RouterVo;
import edu.ncst.award.mapper.MenuMapper;
import edu.ncst.award.mapper.RoleMapper;
import edu.ncst.award.mapper.RoleMenuMapper;
import edu.ncst.award.model.system.Menu;
import edu.ncst.award.model.system.Role;
import edu.ncst.award.service.IMenuService;
import edu.ncst.award.domain.vo.RouterVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.List;
/**
* 菜单 服务实现类
@ -21,6 +31,8 @@ import java.util.*;
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IMenuService {
private final MenuMapper menuMapper;
private final RoleMapper roleMapper;
private final RoleMenuMapper roleMenuMapper;
/**
* 获取当前用户能够访问的路由菜单列表
@ -61,16 +73,33 @@ public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IM
return menuMapper.selectMenuByUserId(0);
}
/**
* 根据用户查询系统菜单列表
*
* @param menu 菜单信息
* @param userId 用户ID
* @return 菜单列表
*/
@Override
public List<Menu> selectMenuList(Menu menu) {
return null;
public List<Menu> selectMenuList(Long userId) {
return selectMenuList(new Menu(), userId);
}
/**
* 校验菜单名称是否唯一
*
* @param menu 菜单信息
* @return 结果
*/
@Override
public String checkMenuNameUnique(Menu menu) {
boolean exist = baseMapper.exists(new LambdaQueryWrapper<Menu>()
.eq(Menu::getName, menu.getName())
.eq(Menu::getParentId, menu.getParentId())
.ne(ObjectUtil.isNotNull(menu.getId()), Menu::getId, menu.getId()));
if (exist) {
return UserConstants.NOT_UNIQUE;
}
return UserConstants.UNIQUE;
}
/**
@ -85,5 +114,101 @@ public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IM
return baseMapper.selectMenuListByUserId(menu, userId);
}
/**
* 根据角色ID查询菜单树信息
*
* @param roleId 角色ID
* @return 选中菜单列表
*/
@Override
public List<Long> selectMenuListByRoleId(Long roleId) {
Role role = roleMapper.selectById(roleId);
return baseMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly());
}
/**
* 根据菜单ID查询信息
*
* @param menuId 菜单ID
* @return 菜单信息
*/
@Override
public Menu selectMenuById(Long menuId) {
return baseMapper.selectById(menuId);
}
/**
* 构建前端所需要下拉树结构
*
* @param menus 菜单列表
* @return 下拉树结构列表
*/
@Override
public List<Tree<Integer>> buildMenuTreeSelect(List<Menu> menus) {
if (CollUtil.isEmpty(menus)) {
return CollUtil.newArrayList();
}
return TreeUtil.build(menus, 0, (menu, tree) ->
tree.setId(menu.getId())
.setParentId(menu.getParentId())
.setName(menu.getName())
.setWeight(menu.getSort()));
}
/**
* 新增保存菜单信息
*
* @param menu 菜单信息
* @return 结果
*/
@Override
public int insertMenu(Menu menu) {
return baseMapper.insert(menu);
}
/**
* 修改菜单信息
*
* @param menu 菜单信息
* @return 结果
*/
@Override
public int updateMenu(Menu menu) {
return baseMapper.updateById(menu);
}
/**
* 是否存在菜单子节点
*
* @param menuId 菜单ID
* @return 结果 true 存在 false 不存在
*/
@Override
public boolean hasChildByMenuId(Long menuId) {
return baseMapper.exists(new LambdaQueryWrapper<Menu>().eq(Menu::getParentId, menuId));
}
/**
* 查询菜单是否存在角色
*
* @param menuId 菜单ID
* @return 结果 true 存在 false 不存在
*/
@Override
public boolean checkMenuExistRole(Long menuId) {
return roleMenuMapper.exists(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getMenuId, menuId));
}
/**
* 删除菜单管理信息
*
* @param menuId 菜单ID
* @return 结果
*/
@Override
public int deleteMenuById(Long menuId){
return baseMapper.deleteById(menuId);
}
}

File diff suppressed because it is too large Load Diff

@ -2,12 +2,6 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="edu.ncst.award.mapper.MenuMapper">
<select id="selectMenuByUserId" resultType="Menu">
# WITH RECURSIVE cte AS (
# SELECT *,CONCAT(id) as tree_path, 1 as level FROM sys_menu where parent_id = 0
# UNION ALL
# # CONCAT(c.name,'->',k.name)
# SELECT k.*,CONCAT(c.tree_path,',',k.id), level+1 FROM sys_menu k INNER JOIN cte c ON c.id = k.parent_id
# ) select * from cte
select distinct sm.*
from sys_menu sm
left join sys_user su on su.id = #{userId}
@ -16,6 +10,32 @@
order by parent_id
</select>
<select id="selectMenuListByUserId" resultType="edu.ncst.award.model.system.Menu">
select distinct m.*
from sys_menu m
left join sys_role_menu rm on m.id = rm.menu_id
left join sys_user_role ur on rm.role_id = ur.role_id
left join sys_role ro on ur.role_id = ro.id
where ur.user_id = #{userId}
<if test="menu.name != null and menu.name != ''">
AND m.name like concat('%', #{menu.name}, '%')
</if>
<if test="menu.showInMenu != null and menu.showInMenu != ''">
AND m.show_in_menu = #{menu.showInMenu}
</if>
<if test="menu.status != null and menu.status != ''">
AND m.status = #{menu.status}
</if>
order by m.parent_id, m.sort
</select>
<select id="selectMenuListByRoleId" resultType="Long">
select m.id
from sys_menu m
left join sys_role_menu rm on m.id = rm.menu_id
where rm.role_id = #{roleId}
<if test="menuCheckStrictly">
and m.id not in (select m.parent_id from sys_menu m inner join sys_role_menu rm on m.id =
rm.menu_id and rm.role_id = #{roleId})
</if>
order by m.parent_id, m.sort
</select>
</mapper>

@ -1,21 +1,11 @@
package edu.ncst.award;
import cn.hutool.json.JSONUtil;
import edu.ncst.award.common.util.treeUtils.TreeNode;
import edu.ncst.award.common.util.treeUtils.TreeNodeConfig;
import edu.ncst.award.common.util.treeUtils.TreeNodeMap;
import edu.ncst.award.common.util.treeUtils.TreeUtils;
import edu.ncst.award.model.system.Menu;
import edu.ncst.award.service.impl.system.MenuServiceImpl;
import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
public class TestSystemMenuService {
int i = 1;
@ -29,26 +19,4 @@ public class TestSystemMenuService {
SecurityContextHolder.getContext().getAuthentication().getDetails();
}
@Test
public void buildMenus() {
menuService.buildMenus(menuService.getAllMenusById(0));
}
@Test
public void buildByList() {
List<Menu> menus = menuService.getAllMenusById(0);
TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
treeNodeConfig.setIdKey("nihao");
// List<TreeNodeMap> treeNodes = TreeUtils.build(0, menus, (menu, treeNode) -> {
// treeNode.setId(menu.getId());
// treeNode.setParentId(menu.getParentId());
// treeNode.setName(menu.getName());
// treeNode.extra("nihao","woshi yly");
// });
// System.out.println(JSONUtil.formatJsonStr(JSONUtil.toJsonStr(treeNodes)));
System.out.println("你哦安徽");
}
}

Loading…
Cancel
Save