每次登录load菜单列表,登录加载时间长,将每种角色菜单列表缓存到redis中
思路:redis菜单列表每次登录查询当前登录的角色是否存入redis
如果存入直接取redis数据,如果redis没有,则登录获取菜单list,并存入redis
,首次登录慢加载list,以后登录直接从redis获取
当菜单删除时候将key删除掉,当重新授权时候将redis的key删掉,这样便控制了redis缓存的菜单信息是最新的
package com.shijie.box.admin.web;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.subject.Subject;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
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.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.shijie.box.admin.util.SerializeUtils;
import com.shijie.box.db.dto.ApiResult;
import com.shijie.box.db.dto.admin.MenuVo;
import com.shijie.box.db.dto.admin.RoleInfo;
import com.shijie.box.db.entity.BaseUser;
import com.shijie.box.db.service.BaseMenuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@RestController
@RequestMapping("/admin/auth")
@Validated
@Api("登录及权限相关api")
public class AdminAuthController {
private final Log logger = LogFactory.getLog(AdminAuthController.class);
@Autowired
private BaseMenuService baseMenuService;
@Autowired
private StringRedisTemplate redisTemplate;
@RequiresAuthentication
@GetMapping("/info")
@ApiOperation("获取菜单权限 api")
@ResponseBody
public ApiResult<RoleInfo> info() {
ApiResult<RoleInfo> rest= new ApiResult<RoleInfo>();
Subject currentUser = SecurityUtils.getSubject();
BaseUser admin = (BaseUser) currentUser.getPrincipal();
RoleInfo info=new RoleInfo();
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("userId", admin.getId());
String roleIds = admin.getUserrole();
// ShoppingUserRole shoppingUserRole=shoppingUserRoleServiceImpl.listBy(paramMap);
// Set<String> roles = null;//roleService.queryByIds(roleIds);
List<MenuVo> listmentVo;
List<String> roleperms;
//判断当前roleId的key是否存在,存在直接从redis取,不存在查询数据库并存放redis
Boolean flag = redisTemplate.opsForHash().hasKey(roleIds, "listmentVobyte");
logger.info("判断redis是否存在当前角色,角色:"+roleIds+",是否存在:"+flag);
if(flag) {
logger.info("进入从redis获取菜单等数据信息");
//redis取数据
String strlistmentVo = (String)redisTemplate.opsForHash().get(roleIds, "listmentVobyte");
String strroleperms = (String)redisTemplate.opsForHash().get(roleIds, "rolepermsbyte");
listmentVo=(List<MenuVo>)SerializeUtils.deSerialize(Base64.decodeBase64(strlistmentVo));
roleperms=(List<String>)SerializeUtils.deSerialize(Base64.decodeBase64(strroleperms));
}else {
logger.info("首次存角色,并查询数据库:"+roleIds);
listmentVo=baseMenuService.listMenuByRoleByParentId(roleIds,0L);
roleperms=baseMenuService.listAllUrlByRole(roleIds);
// //数据存入redis
byte[] listmentVobyte = SerializeUtils.serialize(listmentVo);
byte[] rolepermsbyte = SerializeUtils.serialize(roleperms);
logger.info("存数据到redis");
redisTemplate.opsForHash().put(roleIds, "listmentVobyte", Base64.encodeBase64String(listmentVobyte));
redisTemplate.opsForHash().put(roleIds, "rolepermsbyte", Base64.encodeBase64String(rolepermsbyte));
}
// listmentVo =this.recursion(listmentVo);
List<String> rolesList= new ArrayList<String>();
rolesList.add(roleIds);
info.setRoles(rolesList);
info.setAvatar(admin.getWxPhoto());
info.setName(admin.getUsername());
info.setPerms(listmentVo);
info.setRoleperms(roleperms);
rest.setData(info);
return rest;
}
}
序列化utils类
package com.shijie.box.admin.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializeUtils {
public static byte[] serialize(Object obj) {
byte[] bytes = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
;
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
bytes = baos.toByteArray();
baos.close();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
public static Object deSerialize(byte[] bytes) {
Object obj = null;
try {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
obj = ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}
以上开始思路是将获取菜单列表的list使用json格式化,然后保存格式化后的json文本保存redis,然后再redis读出来,由于MenuVo这个对象里面有个属性,如下:children,是list格式的,在反json成对象时候会出现错误,于是,使用对象序列化解决问题,在上面先得到对象序列化后的byte,然后使用base64转成字符串,保存入redis,开始直接保存byte[]类型到redis,在反学序列化时候出错,可能通过redis存取,byte[]数据有些许变化,所有转成字符串,用redis读出来后在转成byte[],然后在反序列化,解决问题.
public class MenuVo implements Serializable{
private String id;
private String parentId;
private String path;
private String component;
private String redirect;
private String alwaysShow;
private String name;
private String role;
private Map<String,Object> meta;
private List<MenuVo> children ;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}