1. 显示图标
-
参考文档
与icon属性有关;在Permission类中增加icon属性;数据库中t_permission表增加icon字段,添加bootstrap的字体图标
-
在页面异步加载许可树时进行setting设置
-
测试时无法显示图标
4.数据库中t_permission表增加icon字段,添加bootstrap的字体图标
2. 许可 - 新增
-
增加链接 permission/index.jsp
-
跳转到添加页面
-
添加页面
-
添加表单处理
- Hanler
- service
- dao
- Hanler
-
添加后效果
-
注意事项
3. 许可 - 修改
- 添加链接 : permission/index.jsp
- 跳转修改页面
- 页面表单回显: permission/edit.jsp
- 提交表单修改数据
- Handler
- service
- dao
- Handler
4. 许可 - 删除
- 前台代码
- 后台代码
注意:异步操作树时,返回的结果必须是集合,不能返回AjaxResult对象,否则页面无法加载许可数据,同步操作没有要求
3. 注意事项
5 . 改善handler代码-ThreadLocal
6. 给角色分配权限 - 显示分配许可树
- 给按钮绑定点击事件,点击跳转至添加页面
- 页面异步加载许可树。并带有复选框
7. 给角色分配权限 - 分配许可权限
- 给分配许可按钮增加事件处理:给角色分配许可权限
- 后台代码
8. 回显功能
-
角色许可(已分配的角色许可,应该被选中)
原理:
-
查看角色的许可权限
9. 登录用户的权限许可菜单
//登录后进行许可校验并只显示拥有的许可
@RequestMapping("/main")
public String main(HttpSession session){
//加载当前登录用户的所拥有的许可权限
User user = (User)session.getAttribute(Const.LOGIN_USER);
List<Permission> myPermissions = userService.queryPermissionByUserid(user.getId());
Permission permissionRoot = null;
for (Permission permission : myPermissions){
//通过子查找父
Permission child = permission; //假设为子菜单
if (child.getPid() == null) {
permissionRoot = permission;
} else {
for (Permission innerpermission : myPermissions) {
if (child.getPid() == innerpermission.getId()) {
Permission parent = innerpermission;
parent.getChildren().add(child);
break; //跳出内层循环,如果跳出外层循环,需要使用标签跳出
}
}
}
}
session.setAttribute("permissionRoot",permissionRoot);
return "main";
}
采用多表联查,sql如下:
<select id="queryPermissionByUserid" parameterType="int" resultType="Permission">
select distinct t_permission.id, t_permission.pid, t_permission.name,t_permission.icon,t_permission.url
from t_permission,t_role_permission,t_role,t_user_role,t_user
where
t_permission.id = t_role_permission.`permissionid`
and t_role_permission.`roleid` = t_role.id
and t_role.`id`=t_user_role.`roleid`
and t_user_role.`userid` = t_user.`id`
and t_user.id=#{userid} order by t_permission.id
</select>
10. 登录权限拦截器
-
未登录用户可通过相关网址进行访问,通过设置登录权限拦截器只允许登录用户访问。
-
设置登录权限拦截器
(1)定义登录拦截器/* 定义登录权限拦截器,如果未登录状态对未在白名单的页面进行访问则不允许放行,并转发到登录页面 注意: 要使拦截器起效,必须在SpringMVC配置文件中对其进行配置 */ public class LoginInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 第一步,定义不需要被拦截的路径(白名单) Set<String> uri = new HashSet<>(); uri.add("/user/reg.do"); uri.add("/user/reg.htm"); uri.add("/login.htm"); uri.add("/doLogin.do"); uri.add("/logout.do"); //获取请求路径 String servletPath = request.getServletPath(); //判断 if(uri.contains(servletPath)){ return true; } //第二步,判断用户是否登录 // 获取session对象,并从session域中取的user对象 HttpSession session = request.getSession(); User user = (User) session.getAttribute(Const.LOGIN_USER); // 进行判断,如果user对象存在,则说明登录,放行。 // 如果不存在,不放行,并转发到登录页面 if(user!=null){ return true; }else{ //使用request.getContextPath()获取项目的根路径,也就是本项目定义的 APP_PATH response.sendRedirect(request.getContextPath()+"/login.htm"); return false; } } }
(2) 声明拦截器。注意: 要使拦截器起效,必须在SpringMVC配置文件中对其进行配置
11. 访问权限拦截器
-
登录用户未拥有相关权限也不能对其进行访问。
-
访问权限拦截器
(1) 定义拦截器public class AuthInterceptor extends HandlerInterceptorAdapter { @Autowired private PermissionService permissionService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 1.查询所有许可 // // List<Permission> permissions = permissionService.queryAllPermission(); // // Set<String> allUris = new HashSet<>(); // // 将permission中的uri循环遍历放到allUris中 // for(Permission permission : permissions){ // allUris.add("/"+permission.getUrl()); // } // 如果每次都拦截都查询数据库,则效率比较低 // // 改进:通过监听器 // 在服务器启动时加载所有许可路径,并存放在applicaiton域中 Set<String> allUris = (Set<String>)request.getSession().getServletContext().getAttribute(Const.ALL_PERMISSION_URI); // 2.判断请求请求路径是否在所有许可范围 String servletPath = request.getServletPath(); if(allUris.contains(servletPath)){ // 定义一个set获取session域中的uris Set<String> myURIs = (Set<String>)request.getSession().getAttribute(Const.MY_URIS); // 当前路径包括在许可权限的路径,放行 if(myURIs.contains(servletPath)){ return true; }else{ //当前路径不包括在许可权限的路径,不放行,并转发到登录页面 response.sendRedirect(request.getContextPath()+"/login.htm"); return false; } }else{ // 不在拦截的范围内,放行 return true; } } }
(2) 在SpingMVC配置文件中声明
(3) 修改登录方法,让其在登录跳转到main页面时就进行判定
@ResponseBody
@RequestMapping("/doLogin")
public Object doLogin(String loginacct, String userpswd, String type, HttpSession session){
AjaxResult result = new AjaxResult();
try {
Map<String,Object> map = new HashMap<>();
map.put("loginacct",loginacct);
map.put("userpswd", MD5Util.digest(userpswd));
map.put("type",type);
User user = userService.queryUserlogin(map);
session.setAttribute(Const.LOGIN_USER,user);
// 虚线内为添加的拦截----------------------------------------------------------------------------------------------------
//通过Id 查询当前user所拥有的的许可权限
List<Permission> myPermissions = userService.queryPermissionByUserid(user.getId());
//定义根许可
Permission permissionRoot = null;
// 用于拦截器拦截许可权限
Set<String> myUris = new HashSet<>();
for (Permission permission : myPermissions){
//通过子查找父
Permission child = permission; //假设为子菜单
//将拥有的许可权限放到myUris中
myUris.add("/"+child.getUrl());
if (child.getPid() == null) {
permissionRoot = permission;
} else {
for (Permission innerpermission : myPermissions) {
if (child.getPid() == innerpermission.getId()) {
Permission parent = innerpermission;
parent.getChildren().add(child);
break; //跳出内层循环,如果跳出外层循环,需要使用标签跳出
}
}
}
}
session.setAttribute(Const.MY_URIS,myUris);
session.setAttribute("permissionRoot",permissionRoot);
//-------------------------------------------------------------------------------------------------------------
result.setSuccess(true);
} catch (Exception e) {
e.printStackTrace();
result.setMessage("登录失败");
result.setSuccess(false);
}
return result;
}
(4)注意事项:所有角色都应该拥有对[控制面板:main.htm] 访问权限.
12. 访问权限拦截器 - 改善(监听器)
-
原因:每次都拦截都会查询数据库,效率比较低。
改进:使用监听器,在服务器一启动时,将所有的许可信息存放到application域/二级缓存中,提供给拦截器使用
-
添加监听器