之前SQL初始化数据中,也包含了部分菜单权限数据。
这边我们后端先把菜单的数据初始化到Redis中存放,提供API供前端调用,
然后再调整下前端测试。
后端将用户菜单数据初始化到Redis
dao模块中,先增加个常量:
public interface RedisConstant {
...
String USER_MENUS = "userMenu-";
}
定义个类用于返回菜单数据格式的对象:
public class Menu {
private String path;
private String name;
private String icon;
private List<Menu> children;
...
}
初始化Redis的类中,用json格式存放用户菜单:
@Component
public class InitRedisData implements CommandLineRunner {
private static Logger logger = LoggerFactory.getLogger(InitRedisData.class);
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private SysUserRepository userRepository;
@Autowired
private SysRoleRepository roleRepository;
@Autowired
private SysUserDataSourceRepository sysUserDataSourceRepository;
@Autowired
private SysPermRepository sysPermRepository;
@Override
public void run(String... args) throws Exception {
logger.info("开始初始化Redis数据.");
try {
List<SysUser> userList = userRepository.findAll();
for (SysUser user: userList) {
String userName = user.getUserName();
...
//用户的菜单列表
String menus = getUserMenus(userName);
stringRedisTemplate.opsForValue().set(RedisConstant.USER_MENUS + userName, menus,
RedisConstant.TIME_LONG, RedisConstant.TIME_UNIT);
}
...
}catch (Exception e){
logger.error("初始化Redis数据失败:" + e.getMessage());
throw e;
}
logger.info("结束初始化Redis数据.");
}
private String changeToString(List<SysRole> sysRoles){
String roles = "";
if (sysRoles != null && sysRoles.size()>0){
StringBuilder sb = new StringBuilder();
for (SysRole role: sysRoles) {
sb.append(role.getRoleCode());
sb.append(",");
}
roles = sb.toString().substring(0, sb.toString().length()-1);
}
return roles;
}
/**
* 根据用户名获取菜单列表
* @param userName
* @return String (json)
*/
private String getUserMenus(String userName){
String result = "[]";
List<SysPerm> sysPerms = sysPermRepository.findPermOfUser(userName);
if (sysPerms != null && sysPerms.size()>0){
List<Menu> menus = new ArrayList<>();
for(SysPerm perm: sysPerms){
if(perm.getPid() == -1){
Menu menu = new Menu();
menu.setPath(perm.getPermCode());
menu.setName(perm.getPermName());
menu.setIcon(perm.getIcon());
addChildMenu(menu, perm, sysPerms);
menus.add(menu);
}
}
result = JSON.toJSONString(menus);
}
return result;
}
public void addChildMenu(Menu parent, SysPerm sysPerm, List<SysPerm> list) {
List<Menu> childList = new ArrayList<>();
parent.setChildren(childList);
for (SysPerm child : list) {
if (child.getPid() == sysPerm.getId()) {
Menu menu = new Menu();
menu.setPath(child.getPermCode());
menu.setName(child.getPermName());
menu.setIcon(child.getIcon());
childList.add(menu);
// 递归调用
addChildMenu(menu, child, list);
}
}
}
}
Redis的仓库提供方法供调用:
@Repository
public class SystemInfoRedis {
@Autowired
private StringRedisTemplate stringRedisTemplate;
...
/**
* 根据用户名获取菜单
* @param userName
* @return []
*/
public String getMenusByUserName(String userName){
String menus = stringRedisTemplate.opsForValue().get(RedisConstant.USER_MENUS + userName);
return menus == null ? "[]": menus;
}
}
service模块写个方法供controller调用:
这边我将json又转换成list对象,比较绕。
因为controller使用@ResponseBody, API返回的对象会再转成JSON写入response,
直接用json赋值返回对象的话, 会再次被转化为JSON, “ 会就会被转义成 /” 。
应该有更好的方式,不用这样在service中再转成List对象,待研究。
@Service
public class UserService {
@Autowired
private SystemInfoRedis systemInfoRedis;
...
/**
* 获取用户菜单列表
* @param userName
* @return
*/
public List<Menu> getUserMenus(String userName){
List<Menu> menus = new ArrayList<>();
String jsonMenu = systemInfoRedis.getMenusByUserName(userName);
if (jsonMenu != null && !"".equals(jsonMenu)){
menus = (List<Menu>)JSON.parse(jsonMenu);
}
return menus;
}
}
最后Contoller:
请求拦截器的时候已经将解析完的用户信息放入currentUser对象中,这边直接使用来获取当前发起请求的用户。
@RestController
public class LoginController {
@Autowired
private UserService userService;
...
@GetMapping(value = "api/currentMenu")
@ResponseBody
public JsonResult getUserMenus(HttpServletRequest request){
CurrentUser currentUser = (CurrentUser)request.getAttribute("currentUser");
List<Menu> menus = userService.getUserMenus(currentUser.getUserName());
return JsonResult.success("成功", menus);
}
}
使用Postman测试下,get请求带header token访问 localhost:8080/api/currentMenu ,
可以看到返回正确的数据了。
{
"msg": "成功",
"code": 1,
"data": [
{
"path": "/welcome",
"children": [],
"icon": "",
"name": "欢迎"
},
{
"path": "/sysMange",
"children": [
{
"path": "/sysMange/permManage",
"children": [],
"icon": "",
"name": "菜单权限"
},
{
"path": "/sysMange/userManage",
"children": [],
"icon": "",
"name": "用户管理"
}
],
"icon": "",
"name": "系统管理"
}
]
}
接下来调整下前端
首先config中配置下路由:
这里permManage和userManage具体功能还没开发,先借用下./Admin做显示。
{
path: '/',
component: '../layouts/BasicLayout',
authority: ['admin', 'user'],
routes: [
{
path: '/',
redirect: '/welcome',
},
{
path: '/welcome',
name: 'welcome',
icon: 'smile',
component: './Welcome',
},
{
path: '/sysMange/permManage',
name: 'permManage',
icon: 'crown',
component: './Admin',
},
{
path: '/sysMange/userManage',
name: 'userManage',
icon: 'crown',
component: './Admin',
},
{
component: './404',
},
],
},
关闭下菜单的国际化:
该功能暂时用不上,在defaultSettings中将menu.locale设置成false
menu: {
locale: false,
},
最后更改下发起请求:
/services/user.js
export async function queryCurrentMenu() {
return request('/server/api/currentMenu');
}
开启前后端服务,测试一下,OK。
剩下的就是实现下系统管理和业务层面的功能了,具体实现应该就不会再写了。
Bye~