This commit is contained in:
cuijiawang
2025-09-18 09:51:47 +08:00
parent 895ae7383a
commit 023d35fecd
11 changed files with 204 additions and 11 deletions

View File

@@ -40,6 +40,7 @@ public class SaTokenMvcConfiguration implements WebMvcConfigurer {
public SaServletFilter getGlobleSaServletFilter() {
return new SaServletFilter()
.addInclude("/**").addExclude("/favicon.ico")
.addExclude("/auth/getConfig", "/captcha/code")
.setAuth(obj -> {
SaRouter.match("/**", "/auth/login", StpUtil::checkLogin);
})

View File

@@ -135,6 +135,11 @@ public class LoginUser implements Serializable {
*/
private String deviceType;
/**
* 是否是超级管理员
*/
private Integer isAdmin;
/**
* 获取登录id
*/

View File

@@ -3,6 +3,7 @@ package com.agileboot.system.menu.service;
import cn.hutool.core.lang.tree.Tree;
import com.agileboot.common.satoken.pojo.LoginUser;
import com.agileboot.system.menu.dto.*;
import com.agileboot.system.menu.vo.RouterVO;
import java.util.List;
@@ -20,4 +21,6 @@ public interface ISysMenuService {
void remove(Long menuId);
List<Long> getMenuIdsByRoleId(Long roleId);
List<RouterVO> getRouterTree(LoginUser loginUser);
}

View File

@@ -1,9 +1,11 @@
package com.agileboot.system.menu.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.agileboot.common.core.enums.common.MenuTypeEnum;
import com.agileboot.common.core.enums.common.StatusEnum;
import com.agileboot.common.core.exception.BizException;
import com.agileboot.common.core.exception.error.ErrorCode;
import com.agileboot.common.core.utils.jackson.JacksonUtil;
@@ -12,12 +14,14 @@ import com.agileboot.system.menu.dto.*;
import com.agileboot.system.menu.entity.SysMenu;
import com.agileboot.system.menu.mapper.SysMenuMapper;
import com.agileboot.system.menu.service.ISysMenuService;
import com.agileboot.system.menu.vo.RouterVO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -114,13 +118,68 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
return this.baseMapper.selectMenuIdsByRoleId(roleId);
}
@Override
public List<RouterVO> getRouterTree(LoginUser loginUser) {
List<Tree<Long>> trees = buildMenuEntityTree(loginUser);
return buildRouterTree(trees);
}
public List<Tree<Long>> buildMenuEntityTree(LoginUser loginUser) {
List<SysMenu> allMenus;
if (loginUser.getIsAdmin() == 1) {
allMenus = super.list();
} else {
allMenus = this.baseMapper.selectMenuListByUserId(loginUser.getUserId());
}
// 传给前端的路由排除掉按钮和停用的菜单
List<SysMenu> noButtonMenus = allMenus.stream()
.filter(menu -> !menu.getIsButton())
.filter(menu-> StatusEnum.ENABLE.getValue().equals(menu.getStatus()))
.collect(Collectors.toList());
TreeNodeConfig config = new TreeNodeConfig();
// 默认为id 可以不设置
config.setIdKey("menuId");
return TreeUtil.build(noButtonMenus, 0L, config, (menu, tree) -> {
// 也可以使用 tree.setId(dept.getId());等一些默认值
tree.setId(menu.getMenuId());
tree.setParentId(menu.getParentId());
// TODO 可以取meta中的rank来排序
// tree.setWeight(menu.getRank());
tree.putExtra("entity", menu);
});
}
public List<RouterVO> buildRouterTree(List<Tree<Long>> trees) {
List<RouterVO> routers = new LinkedList<>();
if (CollUtil.isNotEmpty(trees)) {
for (Tree<Long> tree : trees) {
Object entity = tree.get("entity");
if (entity != null) {
RouterVO routerDTO = new RouterVO((SysMenu) entity);
List<Tree<Long>> children = tree.getChildren();
if (CollUtil.isNotEmpty(children)) {
routerDTO.setChildren(buildRouterTree(children));
}
routers.add(routerDTO);
}
}
}
return routers;
}
/**
* 构建前端所需要树结构
*
* @param menus 菜单列表
* @return 树结构列表
*/
public List<Tree<Long>> buildMenuTreeSelect(List<SysMenu> menus) {
private List<Tree<Long>> buildMenuTreeSelect(List<SysMenu> menus) {
TreeNodeConfig config = new TreeNodeConfig();
//默认为id可以不设置
config.setIdKey("menuId");

View File

@@ -44,6 +44,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
loginUser.setUsername(sysUser.getUsername());
loginUser.setNickname(sysUser.getNickname());
loginUser.setPassword(sysUser.getPassword());
loginUser.setIsAdmin(sysUser.getIsAdmin());
return loginUser;
}

View File

@@ -2,25 +2,30 @@ package com.agileboot.auth.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.agileboot.auth.pojo.dto.LoginBody;
import com.agileboot.auth.pojo.dto.RegisterBody;
import com.agileboot.auth.pojo.vo.ConfigVO;
import com.agileboot.auth.pojo.vo.LoginVO;
import com.agileboot.auth.service.IAuthStrategy;
import com.agileboot.auth.service.SysLoginService;
import com.agileboot.common.core.constant.Constants;
import com.agileboot.common.core.core.R;
import com.agileboot.common.core.utils.ValidatorUtils;
import com.agileboot.common.satoken.pojo.LoginUser;
import com.agileboot.common.satoken.utils.LoginHelper;
import com.agileboot.system.client.service.ISysClientService;
import com.agileboot.system.client.vo.SysClientVO;
import com.agileboot.system.menu.service.ISysMenuService;
import com.agileboot.system.menu.vo.RouterVO;
import com.alibaba.fastjson2.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
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 org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 认证
@@ -36,6 +41,7 @@ public class AuthController {
private final SysLoginService loginService;
private final ISysClientService sysClientService;
private final ISysMenuService sysMenuService;
/**
* 登录方法
@@ -63,6 +69,20 @@ public class AuthController {
return R.ok(loginVo);
}
/**
* 获取系统的内置配置
*
* @return 配置信息
*/
@GetMapping("/getConfig")
public R<ConfigVO> getConfig() {
// ConfigVO vo = loginService.getConfig();
ConfigVO configVO = new ConfigVO();
String property = SpringUtil.getProperty("security.captcha.enabled");
configVO.setIsCaptchaOn(Boolean.parseBoolean(property));
return R.ok(configVO);
}
/**
* 退出登录
*/
@@ -80,4 +100,16 @@ public class AuthController {
loginService.register(user);
return R.ok();
}
/**
* 获取用户对应的菜单路由 用于动态生成路由
* TODO 如果要在前端开启路由缓存的话 需要在ServerConfig.json 中 设置CachingAsyncRoutes=true 避免一直重复请求路由接口
* @return 路由信息
*/
@GetMapping("/getRouters")
public R<List<RouterVO>> getRouters() {
LoginUser loginUser = LoginHelper.getLoginUser();
List<RouterVO> routerTree = sysMenuService.getRouterTree(loginUser);
return R.ok(routerTree);
}
}

View File

@@ -1,5 +1,6 @@
package com.agileboot.auth.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
@@ -21,6 +22,7 @@ import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
@@ -32,8 +34,10 @@ import java.time.Duration;
*/
@Slf4j
@Validated
@SaIgnore
@RequiredArgsConstructor
@RestController("/captcha")
@RestController
@RequestMapping("/captcha")
public class CaptchaController {
private final CaptchaProperties captchaProperties;
@@ -47,11 +51,11 @@ public class CaptchaController {
CaptchaVO captchaVo = new CaptchaVO();
boolean captchaEnabled = captchaProperties.getEnabled();
if (!captchaEnabled) {
captchaVo.setCaptchaEnabled(false);
captchaVo.setIsCaptchaOn(false);
return R.ok(captchaVo);
}
CaptchaController proxy = (CaptchaController) AopContext.currentProxy();
return R.ok(proxy.getCodeImpl());
// CaptchaController proxy = (CaptchaController) AopContext.currentProxy();
return R.ok(this.getCodeImpl());
}
/**

View File

@@ -26,7 +26,7 @@ public class PasswordLoginBody extends LoginBody {
* 用户密码
*/
@NotBlank(message = "Password cannot be empty")
@Length(min = 5, max = 30, message = "user.password.length.valid")
// @Length(min = 5, max = 30, message = "user.password.length.valid")
private String password;
}

View File

@@ -13,7 +13,7 @@ public class CaptchaVO {
/**
* 是否开启验证码
*/
private Boolean captchaEnabled = true;
private Boolean isCaptchaOn = true;
private String uuid;

View File

@@ -0,0 +1,8 @@
package com.agileboot.auth.pojo.vo;
import lombok.Data;
@Data
public class ConfigVO {
private Boolean isCaptchaOn;
}

View File

@@ -0,0 +1,80 @@
package com.agileboot.system.menu.vo;
import com.agileboot.common.core.utils.jackson.JacksonUtil;
import com.agileboot.system.menu.dto.MetaDTO;
import com.agileboot.system.menu.entity.SysMenu;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.google.common.collect.Lists;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 动态路由信息
* 必须加上@JsonInclude(Include.NON_NULL)的注解 否则传null值给Vue动态路由渲染时会出错
*
* @author valarchie
*/
@JsonInclude(Include.NON_NULL)
@Data
@NoArgsConstructor
public class RouterVO {
public RouterVO(SysMenu entity) {
if (entity != null) {
this.name = entity.getRouterName();
this.path = entity.getPath();
// 暂时不需要component
// this.component = entity.getComponent();
// this.rank = entity.getRank();
// this.redirect = entity.getRedirect();
if (JacksonUtil.isJson(entity.getMetaInfo())) {
this.meta = JacksonUtil.from(entity.getMetaInfo(), MetaDTO.class);
} else {
this.meta = new MetaDTO();
}
this.meta.setAuths(Lists.newArrayList(entity.getPermission()));
}
}
/**
* 路由名字 根据前端的要求 必须唯一
* 并按照前端项目的推荐 这个Name最好和组件的Name一样 使用菜单表中的router_name
* TODO 这里后端需要加校验
*/
private String name;
/**
* 路由路径地址
*/
private String path;
/**
* 路由重定向
*/
private String redirect;
/**
* 组件地址
*/
private String component;
/**
* 一级菜单排序值(排序仅支持一级菜单)
*/
private Integer rank;
/**
* 其他元素
*/
private MetaDTO meta;
/**
* 子路由
*/
private List<RouterVO> children;
}