1. //FunVO.java
    2. package com.duyi.qxgl07.vo;
    3. import java.util.List;
    4. //当前对象中存储的数据,是给视图使用的
    5. public class FunVO {
    6. private String title ; // fun.fname->vo.title
    7. private Integer id ; // fun.fid -> vo.id
    8. private List<FunVO> children ;// 装载当前菜单的子菜单 children[0].用户管理 fname->vo1.title
    9. public String getTitle() {
    10. return title;
    11. }
    12. public void setTitle(String title) {
    13. this.title = title;
    14. }
    15. public Integer getId() {
    16. return id;
    17. }
    18. public void setId(Integer id) {
    19. this.id = id;
    20. }
    21. public List<FunVO> getChildren() {
    22. return children;
    23. }
    24. public void setChildren(List<FunVO> children) {
    25. this.children = children;
    26. }
    27. public FunVO(String title, Integer id, List<FunVO> children) {
    28. this.title = title;
    29. this.id = id;
    30. this.children = children;
    31. }
    32. public FunVO() {}
    33. }
    1. //UserService.java
    2. package com.duyi.qxgl07.service;
    3. import com.duyi.qxgl07.dao.FunDao;
    4. import com.duyi.qxgl07.dao.RoleDao;
    5. import com.duyi.qxgl07.dao.UserDao;
    6. import com.duyi.qxgl07.domain.Fun;
    7. import com.duyi.qxgl07.domain.PageInfo;
    8. import com.duyi.qxgl07.domain.SetRoleInfo;
    9. import com.duyi.qxgl07.domain.User;
    10. import com.duyi.qxgl07.vo.FunVO;
    11. import orm.SqlSession;
    12. import java.util.*;
    13. public class UserService {
    14. UserDao dao = new UserDao();
    15. RoleDao roleDao = new SqlSession().getMapper(RoleDao.class);
    16. FunDao funDao = new SqlSession().getMapper(FunDao.class);
    17. /**
    18. *
    19. * @param uname
    20. * @param upass
    21. * @return user object(找到了) or null (没找到)
    22. */
    23. public User checkLogin(String uname , String upass){
    24. //数据都在数据库中,需要从数据库找数据
    25. //谁负责与数据库交互呢 -> dao (jdbc技术)
    26. return dao.findUserByNameAndPass(uname,upass) ;
    27. }
    28. public PageInfo findUserByPage(int page , int rows){
    29. //先做一个判断,确保页码是有效的
    30. //下限判断
    31. if(page < 1){
    32. page = 1;
    33. }
    34. //上限判断
    35. //先知道最大是多少页 总记录数/rows
    36. //从数据库查询总记录数
    37. int total =dao.total();
    38. int max = total%rows==0?(total/rows):(total/rows + 1) ; // 101/10 = 10 + 1 . 0/10==0
    39. max = max==0?1:max ;
    40. if(page > max){
    41. page = max ;
    42. }
    43. //确保page一定是正确的
    44. //就可以查询这一页的数据了
    45. //需要从数据库查询这一页的数据
    46. //数据库的分页,使用limit关键字,需要的是start和length
    47. /*
    48. ------mysql-----
    49. 第1页 从0开始 取10条
    50. 第2页 从10开始 取10条
    51. 第3页 从20开始 取10条
    52. ...
    53. 第n页 从(n-1)*10开始 取10条
    54. -----oracle-----
    55. 第1页 从1开始 取到10
    56. 第2页 从11开始 取到20
    57. 。。。
    58. */
    59. /*
    60. 分页有两种情况:
    61. 真分页 : 每页数据都需要从数据中获取,优点,每次只取部分数据,速度快。但多次分页需要多次与数据库交互
    62. 假分页 : 从数据库取出所有记录,每页显示不同部分。单次速度慢,多次分页缓存区,效率高。不利于频繁读写
    63. */
    64. int start = (page-1)*rows ;
    65. int length = rows ;
    66. List<User> users = dao.findUserByPage(start,length);
    67. return new PageInfo(page , rows,total,max,start,(start+rows-1) , users) ;
    68. }
    69. public void save(User user){
    70. dao.save(user);
    71. }
    72. //查询所有的角色信息List + uid这个用户上一次分配的信息List
    73. //角色信息携带到网页后,需要展示,需要所有的信息 List<Role>
    74. //上一次分配的角色信息携带到网页后,需要根据信息默认勾选,List<rid>
    75. //可以将上述两个集合中的数据合成一个List
    76. //List中每一个条件,既有角色所有信息+这个角色是否勾选的信息
    77. public List<Map> findRoleAllByUser(int uid){
    78. return roleDao.findAllByUser(uid);
    79. }
    80. public void setRolesForUser(int uid , String rids){
    81. //先判断这个了uid是否正确
    82. long count = dao.assertUser(uid) ;
    83. if(count == 0){
    84. //无效的账号
    85. throw new RuntimeException("无效的操作") ;
    86. }
    87. roleDao.removeRelationship(uid);
    88. if(rids != null && !"".equals(rids)){
    89. //分配了角色
    90. String[] ridArray = rids.split(",");
    91. Map<String,Integer> param = new HashMap<String,Integer>();
    92. param.put("uid",uid);
    93. for(String rid : ridArray){
    94. param.put("rid",Integer.parseInt(rid)) ;
    95. roleDao.addRelationship(param);
    96. }
    97. }
    98. }
    99. public Map<String,Object> findUserAuth(int uid){
    100. List<Fun> funs = funDao.findFunByUser(uid);
    101. /*
    102. funs中装载着所有的权限功能
    103. 我们需要对其进行的一个处理
    104. 将一个完整的拆成2个
    105. 1) 只装有菜单的列表
    106. 菜单列表最终会使用layui-tree组件展示
    107. layui-tree组件要求子父功能是包含关系
    108. List<Fun> -> 递归 -> List<Map> 包含子父关系
    109. 2) 只装有权限范围的列表 List<Fun> -> List<String> -> Set<String>
    110. */
    111. //组装权限范围
    112. Set<String> auths = new HashSet<>();
    113. for(Fun fun : funs){
    114. auths.add( fun.getAuth() ) ;
    115. }
    116. //组装layui-tree所需要的数据结构
    117. //List<Fun>{权限管理,用户管理} -> List<FunVO>{权限管理->用户管理}
    118. List<FunVO> menus = reload(funs,-1); //-1 为父级菜单
    119. Map<String,Object> map = new HashMap<String,Object>();
    120. map.put("auths",auths);
    121. map.put("menus",menus);
    122. return map ;
    123. }
    124. //在所有的功能菜单中,逐层组装,理论上从第一层
    125. private List<FunVO> reload(List<Fun> funs , int level){
    126. List<FunVO> vos = new ArrayList<>(); //装载本层组装后的菜单
    127. for(Fun fun : funs){
    128. // 是不是当前这个菜单
    129. if(fun.getFtype().equals(1) && fun.getPid().equals(level)){
    130. //找到了一个属于当前层级的菜单
    131. //重新组装Fun->FunVO
    132. FunVO vo = new FunVO();
    133. if(fun.getFhref() != null && !"".equals(fun.getFhref())){
    134. //当前菜单点击后需要发送请求
    135. vo.setTitle("<a href='"+fun.getFhref()+"' target='content'>"+fun.getFname()+"</a>");
    136. }else{
    137. vo.setTitle(fun.getFname());
    138. }
    139. vo.setId(fun.getFid());
    140. //找到当前fun的子级,当前这个父级菜单的子级菜单,就是父级pid = 当前菜单的fid
    141. // (递归) 没有子级或者没有菜单的时候,递归结束
    142. List<FunVO> children = reload(funs,fun.getFid());
    143. vo.setChildren(children);
    144. vos.add(vo);
    145. }
    146. }
    147. return vos ;
    148. }
    149. }
    • 登录时查询登录权限
      1) 将所有的权限范围组成Set集合,方便查找
      2) 将所有的菜单组成新的List集合,通过递归,符合layui-tree组件的数据结构
      3) 将信息装入session

    • 通过权限控制菜单 ```java <— main.jsp —>

      1. <title>主页面</title>
      2. <meta charset="utf-8" />
      3. <link rel="stylesheet" type="text/css" href="layui/css/layui.css" />
      4. <script src="layui/layui.js"></script>
      5. <script>
      6. //使用layui-tree组件
      7. layui.use(['tree'], function(){
      8. var tree = layui.tree;
      9. var $ = layui.jquery ;
      10. //需要获得session中存储的权限菜单的信息
      11. //使用ajax访问
      12. $.ajax({
      13. type:'get',
      14. url:'findUserMenus',
      15. data:{},
      16. success:function(menus){
      17. //通过一个前端js的json反序列化处理,menus就变成了js语法的集合/数组
      18. //常规用法
      19. tree.render({
      20. elem: '#myTree' //使用标签的id,表示将菜单的数据显示在指定的标签中
      21. ,data: menus
      22. });
      23. },
      24. dataType:'json'
      25. });
      26. });
      27. function logout(){
      28. //浏览器显示一个询问框(确定,取消)
      29. //根据点击的按钮返回true、false
      30. var f = confirm('是否确认退出');
      31. if(f){
      32. location.href = 'logout' ;
      33. }
      34. }
      35. </script>

    ```

    • 通过权限控制按钮
      服务端权限认证
      每次处理请求之前,需要先验证一下,当前用户是否具备此次请求的处理的权限
      当前用户允许/支持的权限,存在session{loginAuth{auths}}中
      如何得知此次请求所需要的权限?
      自定义注解
      注解可以作用在controller的方法上
      注解中指定要想让当前方法处理请求,所需要的权限范围
      这个权限认证需要在请求之前执行
      同时又不是此次请求的一个目的
      符合AOP编程中切面的特点
      tomcat提供了一个AOP实现:Filter
      但这个过滤器不能用在我们的程序中
      因为当我们访问controller的方法时,会有mvc框架调用
      所以这个切面需要由mvc框架提供和调用。
      image.png
      image.png
      image.png
      三个切面之间是独立的
      image.png