//FunVO.javapackage com.duyi.qxgl07.vo;import java.util.List;//当前对象中存储的数据,是给视图使用的public class FunVO {private String title ; // fun.fname->vo.titleprivate Integer id ; // fun.fid -> vo.idprivate List<FunVO> children ;// 装载当前菜单的子菜单 children[0].用户管理 fname->vo1.titlepublic String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public List<FunVO> getChildren() {return children;}public void setChildren(List<FunVO> children) {this.children = children;}public FunVO(String title, Integer id, List<FunVO> children) {this.title = title;this.id = id;this.children = children;}public FunVO() {}}
//UserService.javapackage com.duyi.qxgl07.service;import com.duyi.qxgl07.dao.FunDao;import com.duyi.qxgl07.dao.RoleDao;import com.duyi.qxgl07.dao.UserDao;import com.duyi.qxgl07.domain.Fun;import com.duyi.qxgl07.domain.PageInfo;import com.duyi.qxgl07.domain.SetRoleInfo;import com.duyi.qxgl07.domain.User;import com.duyi.qxgl07.vo.FunVO;import orm.SqlSession;import java.util.*;public class UserService {UserDao dao = new UserDao();RoleDao roleDao = new SqlSession().getMapper(RoleDao.class);FunDao funDao = new SqlSession().getMapper(FunDao.class);/**** @param uname* @param upass* @return user object(找到了) or null (没找到)*/public User checkLogin(String uname , String upass){//数据都在数据库中,需要从数据库找数据//谁负责与数据库交互呢 -> dao (jdbc技术)return dao.findUserByNameAndPass(uname,upass) ;}public PageInfo findUserByPage(int page , int rows){//先做一个判断,确保页码是有效的//下限判断if(page < 1){page = 1;}//上限判断//先知道最大是多少页 总记录数/rows//从数据库查询总记录数int total =dao.total();int max = total%rows==0?(total/rows):(total/rows + 1) ; // 101/10 = 10 + 1 . 0/10==0max = max==0?1:max ;if(page > max){page = max ;}//确保page一定是正确的//就可以查询这一页的数据了//需要从数据库查询这一页的数据//数据库的分页,使用limit关键字,需要的是start和length/*------mysql-----第1页 从0开始 取10条第2页 从10开始 取10条第3页 从20开始 取10条...第n页 从(n-1)*10开始 取10条-----oracle-----第1页 从1开始 取到10第2页 从11开始 取到20。。。*//*分页有两种情况:真分页 : 每页数据都需要从数据中获取,优点,每次只取部分数据,速度快。但多次分页需要多次与数据库交互假分页 : 从数据库取出所有记录,每页显示不同部分。单次速度慢,多次分页缓存区,效率高。不利于频繁读写*/int start = (page-1)*rows ;int length = rows ;List<User> users = dao.findUserByPage(start,length);return new PageInfo(page , rows,total,max,start,(start+rows-1) , users) ;}public void save(User user){dao.save(user);}//查询所有的角色信息List + uid这个用户上一次分配的信息List//角色信息携带到网页后,需要展示,需要所有的信息 List<Role>//上一次分配的角色信息携带到网页后,需要根据信息默认勾选,List<rid>//可以将上述两个集合中的数据合成一个List//List中每一个条件,既有角色所有信息+这个角色是否勾选的信息public List<Map> findRoleAllByUser(int uid){return roleDao.findAllByUser(uid);}public void setRolesForUser(int uid , String rids){//先判断这个了uid是否正确long count = dao.assertUser(uid) ;if(count == 0){//无效的账号throw new RuntimeException("无效的操作") ;}roleDao.removeRelationship(uid);if(rids != null && !"".equals(rids)){//分配了角色String[] ridArray = rids.split(",");Map<String,Integer> param = new HashMap<String,Integer>();param.put("uid",uid);for(String rid : ridArray){param.put("rid",Integer.parseInt(rid)) ;roleDao.addRelationship(param);}}}public Map<String,Object> findUserAuth(int uid){List<Fun> funs = funDao.findFunByUser(uid);/*funs中装载着所有的权限功能我们需要对其进行的一个处理将一个完整的拆成2个1) 只装有菜单的列表菜单列表最终会使用layui-tree组件展示layui-tree组件要求子父功能是包含关系List<Fun> -> 递归 -> List<Map> 包含子父关系2) 只装有权限范围的列表 List<Fun> -> List<String> -> Set<String>*///组装权限范围Set<String> auths = new HashSet<>();for(Fun fun : funs){auths.add( fun.getAuth() ) ;}//组装layui-tree所需要的数据结构//List<Fun>{权限管理,用户管理} -> List<FunVO>{权限管理->用户管理}List<FunVO> menus = reload(funs,-1); //-1 为父级菜单Map<String,Object> map = new HashMap<String,Object>();map.put("auths",auths);map.put("menus",menus);return map ;}//在所有的功能菜单中,逐层组装,理论上从第一层private List<FunVO> reload(List<Fun> funs , int level){List<FunVO> vos = new ArrayList<>(); //装载本层组装后的菜单for(Fun fun : funs){// 是不是当前这个菜单if(fun.getFtype().equals(1) && fun.getPid().equals(level)){//找到了一个属于当前层级的菜单//重新组装Fun->FunVOFunVO vo = new FunVO();if(fun.getFhref() != null && !"".equals(fun.getFhref())){//当前菜单点击后需要发送请求vo.setTitle("<a href='"+fun.getFhref()+"' target='content'>"+fun.getFname()+"</a>");}else{vo.setTitle(fun.getFname());}vo.setId(fun.getFid());//找到当前fun的子级,当前这个父级菜单的子级菜单,就是父级pid = 当前菜单的fid// (递归) 没有子级或者没有菜单的时候,递归结束List<FunVO> children = reload(funs,fun.getFid());vo.setChildren(children);vos.add(vo);}}return vos ;}}
登录时查询登录权限
1) 将所有的权限范围组成Set集合,方便查找
2) 将所有的菜单组成新的List集合,通过递归,符合layui-tree组件的数据结构
3) 将信息装入session通过权限控制菜单 ```java <— main.jsp —>
<title>主页面</title><meta charset="utf-8" /><link rel="stylesheet" type="text/css" href="layui/css/layui.css" /><script src="layui/layui.js"></script><script>//使用layui-tree组件layui.use(['tree'], function(){var tree = layui.tree;var $ = layui.jquery ;//需要获得session中存储的权限菜单的信息//使用ajax访问$.ajax({type:'get',url:'findUserMenus',data:{},success:function(menus){//通过一个前端js的json反序列化处理,menus就变成了js语法的集合/数组//常规用法tree.render({elem: '#myTree' //使用标签的id,表示将菜单的数据显示在指定的标签中,data: menus});},dataType:'json'});});function logout(){//浏览器显示一个询问框(确定,取消)//根据点击的按钮返回true、falsevar f = confirm('是否确认退出');if(f){location.href = 'logout' ;}}</script>
```
- 通过权限控制按钮
服务端权限认证
每次处理请求之前,需要先验证一下,当前用户是否具备此次请求的处理的权限
当前用户允许/支持的权限,存在session{loginAuth{auths}}中
如何得知此次请求所需要的权限?
自定义注解
注解可以作用在controller的方法上
注解中指定要想让当前方法处理请求,所需要的权限范围
这个权限认证需要在请求之前执行
同时又不是此次请求的一个目的
符合AOP编程中切面的特点
tomcat提供了一个AOP实现:Filter
但这个过滤器不能用在我们的程序中
因为当我们访问controller的方法时,会有mvc框架调用
所以这个切面需要由mvc框架提供和调用。


三个切面之间是独立的

