前言
前面我们做的小项目都是一个表的,业务代码也相对简单。现在我们来做一个权限管理系统,体验一下多表的业务逻辑,顺便巩固一下过滤器的知识。!
目的
现在我有一个管理商品、订单的页面。当用户点击某个超链接时,过滤器会检测该用户是否有权限!
需求分析
按照面向对象的思想,我们至少应该有权限(privilege)和用户(user)实体。两个实体足够了吗?细想一下,如果我们有多个用户,多个用户也有多个权限,当要为用户授权的时候,这样子就会非常麻烦!所以我们应该引入角色(role)这个实体!
引入角色(role)这个实体方便在哪呢??把权限赋给角色(比如:把删除、修改的权限给管理员这个角色),管理员这个角色再赋给用户,那么该用户就有了修改、删除的权限了!
权限和角色是多对多的关系,角色和用户也是多对多的关系!
开发实体
用户和角色、角色和权限都是多对多的关系,这是毋庸置疑的!我们也按照面向对象的方法来设计,用集合来记住另一方的数据!
但是呢,我们想想:
在权限的dao中,在查看权限的时候,有必要列出相对应的角色吗??
在角色的dao中,在查看角色的时候,有必要列出相对应的用户吗??
答案是没有的,一般我们都不会显示出来。所以,权限的实体没必要使用set集合来记住角色,角色实体没必要使用set集合来记住用户!
在数据库中建表
注意:user和role的关系表、role和privilege的关系都有role_id作为外键,外键的名称是不能一样的!
开发dao
为了测试方便,添加有参构造函数到privilege对象中
上面的仅仅是单表的dao功能,user和role表是多对多的关系,role和privilege表也是多对多的关系。
前面已经分析了
在user对象中,需要一个set集合来记住role的关系。【显示用户的时候,应该把所有角色显示出来】
在role对象中,需要一个set集合来记住privilege的关系【显示角色的时候,应该把所有权限显示很出来】。
所以应该在userdao有获取某用户所有的角色的方法:
在roledao有获取所有权限的方法:
我们既然能获取得到用户所有的角色了,获取得到角色所有的权限了。那自然我们就应该有修改用户的角色功能,修改角色的权限的功能啦!
我们先来分析一下它怎么写:要修改用户所拥有的角色,应该知道修改用户是哪一个,所以需要用户的id或者user对象!修改的角色是什么,需要role对象或者装载role对象的集合!
在userdao有修改某用户角色的方法,我们是想把所有的角色都删除了,再添加新的角色
在roledao有修改角色权限的方法,和上面是类似的。
刚才又思考了一下:
- 其实我们并不需要在user类用使用集合来维护role,在role中使用集合来维护privilege。在原本的做法我们已经看到了,我们完全是不需要这两个变量也能完成效果的。
- 那么,现在问题就来了。什么时候我们才需要在实体中使用变量来维护多的一方的关系呢???我觉得是这样的:当我们在查询一方数据的时候,另一方的数据也同时需要展示。那么此时我们就应该使用集合来维护多的一方数据了。
- 基于上面一个例子,就比如:订单与订单项。当我们查看订单的时候,同时一定会把所有的订单项都列举出来。
- 再比如:当我们查看购物车的时候,就需要把所有的购物项都列举出来。
- 而我们使用展示用户的时候,并不需要第一时间就把角色列举出来,而是通过超链接来查看用户下的角色,基于这种情况,我觉得我们是不用使用集合变量来维护多的一方的数据的。
这就跟hibernate的懒加载差不多。用到关联关系的数据的时候才加载,没有用到的时候就先不查询数据库。
ps:我不知道在这我理解得对不对,如果有错的地方希望能指出!
开发businessservice
开发web
提供页面界面的servlet
显示页面的jsp
处理表单数据的servlet
效果:
显示页面jsp
在显示用户的基础上,应该添加为用户授权角色的超链接。
处理显示授权页面的servlet
授权页面jsp
处理表单数据并为用户添加角色的servlet
提供添加角色页面的servlet
处理表单数据并添加角色的servlet
提供页面的servlet
效果
与上面是类似的,我们要在查看角色的时候,添加授权的功能!
提供显示权利页面的servlet
处理表单数据并添加角色权利的servlet
提供添加权限页面的servlet
处理表单数据,并添加权限的servlet
显示权限页面的jsp
head页面
left页面
body页面是空白的!
index页面:
过滤器
过滤器主要的工作就是:点击超链接时,过滤器会检测该点击者是否有权限进入页面进行操作(curd)。
这里我们是这样子做的:uri作为key,权限作为value,构成一个map集合。当用户请求资源的时候,判断该资源是否需要权限,如果需要权限,就判断该用户是否登陆了,如果登陆了,就判断该用户有没有权限去访问该资源!
在userdao和userservice中需要添加login方法:
登陆界面的jsp
处理登陆的servlet
完整代码:
总结要点
①:用户和权限的关系,由于添加用户的权限和修改用户权限的不足【在权限很多的情况下,这种情况是不好处理的】,所以我们引入了角色这个概念
②:用户与角色,角色与权限都是多对多的关系
③:按照数据库范式,我们会创建5张实体表,其中两张是代表着:用户与角色、角色与权限的关系表。角色这个字段在外键中,不能同名!
④:无论是角色、用户、权限都有这三个方法:得到所有的权限(角色、用户)、添加权限(角色、用户)、权限的id得到权限(角色、用户)对象
⑤:根据id得到具体的对象方法的意义:在web显示层只能通过id来标识着这个对象,然而在后端常常使用的是对象,于是就有了这个方法。
⑥:多对多之间的关系,在程序中并不是都要在其类上定义一个集合来记住对方。当显示用户时,需要显示角色,但是显示角色时,一般我们是不需要显示用户的信息的。因此在角色上,并不需要维护一个集合来记住所有的用户
⑦:得到用户的所有角色:传入的参数必定有具体的用户或角色,所以id必须是外界传递进来的。【得到角色的所有权限是同理】
⑧:修改用户的角色:我们先把用户的角色全部删除了,再通过外界勾选的角色进行添加(这是一个折中的办法)【修改角色的权限是同理】
⑨:在添加用户角色的时候,要把用户的id通过隐藏域传递进去给服务器端,不然是不知道要修改的是哪一个用户的角色的。【修改角色的权限是同理】
⑩:frameset和frame来实现前台的分帧,target指定在哪里显示具体的数据
①①:在init()方法中用一个map集合,以uri作为key,以具体的权限作为值来实现过滤
①②:如果uri不需要权限,直接放行。需要权限,那么判断该用户是否登录了。没有登录就让用户去登录
①③:如果登录了,就得到用户所有的权限,权限用一个set集合装载,遍历set集合,使用contains()方法就可以查看出有没有对应的权限了。
①④:使用contains()方法需要在权限类上重写hashcode()和equals()方法的。因为我们比较的是字符串。
如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,想要获取更多的java资源的同学,可以关注微信公众号:java3y