OA的学习--第五天的内容--优化和权限模块的初步功能
2015-03-20 11:00
417 查看
第五天的学习,是从35集到41集,这7集的内容,改进了Service和Dao,去掉了Dao层,将Service层改为Service+Dao层.并且实现了用户的一些功能,以及对密码的MD5摘要处理,这个主要是引入一个jar包commons-codec.jar,调用里面的DigestUtils.md5Hex("字符串")就可以了.还有就是进行了权限的设计,包括分析功能,设计类和写完类的映射文件,以及权限数据和超级用户数据的初始化.
首先是,他们的合并的原因,从下图中可以看到这样的调用关系,在RoleAction中调用RoleServiceImpl,而RoleServiceImpl又调用RoleDaoImpl,但是对于简单的增删改查来说,DaoImpl并没有写任何代码,而中间的Service的实现也就是调用了Dao的实现,并没有加什么业务.所以在这种情况下,可以直接让Service中调用Dao,从而去掉现在Dao层,省掉一个接口和一个实现类.
可以理解成这样的修改,从原来的View + Service + Dao,改为了View + Service(原Service + 原Dao).这样,三层就变两层了,中小型的项目可以这样做,但是大型项目还是需要严格的三层来做.毕竟三层的本来目的是为了解耦和,面对接口编程,灵活应对变化,这样后期维护也会容易些,而且据说三层比二层更稳定,更安全,
所以将所有的Dao和DaoImpl都用@Deprecated,做过期注解.而调用Dao和DaoImpl的Service层,这样修改.将原来Dao和DaoImpl继承的BaseDao接口和BaseDaoImpl类,修改名为DaoSupport接口和DaoSupportImpl实现类.(不改名也行,只要不要搞错.)然后让Service的接口和Service的实现分别继承DaoSupport和DaoSupportImpl,这样Service中对于基本的增删改查就不用处理了,只需要处理一些其他的方法了.如DepartmentService,部门Service接口,基础了DaoSupport,不用些findAll()等等方法了,因为DaoSupport中都提供了.只需要写上自己的findTopList()这样的方法
,写到DaoSupportImpl中,这样DaoSupportImpl就在事务中,而它所有的的子类也是在事务中的.所以现在就是这样了.
而现在的结构就是这样的.MyAction继承了BaseAction,而BaseAction又继承了ActionSupport,并且BaseAction提取了公共代码,实例化Service,以及注入model实体.而MyAction通过调用Service的接口,而调用了Service的实现类,并且这两个都提取了一些公共代码,方便公用.DaoSupport是增删改查的基本方法的接口,而DaoSupportImpl则是实现了的增删改查方法.
首先写userAction,继承BaseAction,并且写上注解@Controller和@Scope("prototype") 分别表示userAction交由容器管理,以及是多例的.每调用一次,生成一个userAction对象.然后由于userAction需要调用Service,所以创建userAction的userService接口和实现类.并且该Impl实现类中需要继承DaoSupportImpl和实现Service接口,以及写上注解@Service,表示将该Service放到容器中.若实现类中有方法不是基本的增删改查,则需要在Service的实现中,注入sessionFactory,写新方法用它来完成功能.举例,如
然后在BaseAction中将该Service注入.
再在struts.xml文件中写上新的Action配置
最后,只要写Action的方法,以及JSP页面就可以了.普通的增删改查就直接调用,Service方法就可以,但是对于跳转到页面,往往需要准备数据;以及添加数据的时候,页面传递过来的是id或者id数组,但是该属性为实体或者实体集合,所以还需要单独处理.
如添加页面需要准备树状部门列表和岗位列表
其中由于要求设置用户名初始化密码为"1234",但是存储明文在数据库中一看就知道密码了,所以需要对密码加密,引入commons-codec.jar,调用它的md5Hex()方法就可以,将1234加密,变成一段看不懂的内容.
在数据库中就是这样,其中81dc9bdb52d04dc20036dbd8313ed055就是1234的md5加密之后的结果.
设定权限模型就是这样的,有用户和角色,以及权限.其中用户和角色是多对多的关系,一个用户可以有多个角色,一个角色可以包含多个用户;角色和权限也是多对多的关系,一个角色有多个权限,一个权限属于多个角色. 用户的权限就是该用户所有角色的权限的合集,并且判断一个功能是否能被某用户使用,只需要通过判断用户权限是否有这个功能的使用许可就可以了.
所有建立用户和角色和权限的实体和实体的映射文件.用户和角色都已经建立,只需要建立权限,以及修改一下角色,因为角色和权限还有关系,所以要加一个权限的属性;他们的类图就是这样
在Role(可以翻译为角色或者岗位)中添加privileges 角色集合属性.
其中,Role中的权限是多对多的关系.注释是关系是多对多,并且权限类型是set集合,所以用set,并且要有table第三张表,而key对应的是该映射文件的主键,它作为权限的外键存在.写好之后,如"roleId",拷到和他一对的manytomany标签的column属性中.
按照注释,属性填到name中,类填到class中.table的名字,一对的要一样.key是当前的映射实体(权限)说明的id要叫的名字,所以在Role映射文件中的manytmany标签的column的属性中写上privilegeId,而manytomany的column是Role类对应的实体主键.其中table,key的column和manytomany的column一对的都是要互相对应着的.
还有就是权限类中的树形结构的自关联.manytoone和onetomany也是一对.manytoone和manytoone会在多的一端加上一的一端的主键,所以一端说明关联字段为parentId,多端把这个作为外键放在表中.
其中总结下,对于多对一和一对多,是根据本类与该属性的关系来判断的,本类与该属性为一对多的关系,就用onetomany.并且多端和一端都是需要写name,class和column的属性的,只是多端需要设置外键,所以column写在了key标签中.而多对多是需要再加一张第三表的,两个表的id合起来才是一个主键,所以除了在key中写外键列column,还需要在manytomany中写主键列column.
最后,写完之后,不要忘了添加到hibernate.cfg.xml中.
权限数据的初始化
对于权限来说,有一些数据是初始化在数据库中的,你可以采用写slq脚本的方式,insert数据到数据库中,但是由于数据库的差异性,sql脚本可能不通用,需要为不同的数据库写不同的脚本,所以为了解决这个问题.就写代码,用程序来生成初始化数据,这样只要hibernate支持的数据库,我们都能插入数据.
做法就是写一个叫Installer的工具类.
Application就可以了.但是不启动tomcat,容器对象在监听器中创建,现在就不能创建了,怎么获取到容器中的Installer对象?所以直接读取配置文件applicationContext.xml,让它实例化一个Installer对象,我们再来用.
以上就是我第五天的学习,主要学习到的就是MD5的加密,以及action项目的流程,还有实体映射文件的写法的再次巩固,还有用main不启动tomcat,如何获取容器中的对象.应该再有4天就差不多学完了,加油哦!
Service层与Dao层合并
首先,介绍Service与Dao层的合并.首先是,他们的合并的原因,从下图中可以看到这样的调用关系,在RoleAction中调用RoleServiceImpl,而RoleServiceImpl又调用RoleDaoImpl,但是对于简单的增删改查来说,DaoImpl并没有写任何代码,而中间的Service的实现也就是调用了Dao的实现,并没有加什么业务.所以在这种情况下,可以直接让Service中调用Dao,从而去掉现在Dao层,省掉一个接口和一个实现类.
可以理解成这样的修改,从原来的View + Service + Dao,改为了View + Service(原Service + 原Dao).这样,三层就变两层了,中小型的项目可以这样做,但是大型项目还是需要严格的三层来做.毕竟三层的本来目的是为了解耦和,面对接口编程,灵活应对变化,这样后期维护也会容易些,而且据说三层比二层更稳定,更安全,
所以将所有的Dao和DaoImpl都用@Deprecated,做过期注解.而调用Dao和DaoImpl的Service层,这样修改.将原来Dao和DaoImpl继承的BaseDao接口和BaseDaoImpl类,修改名为DaoSupport接口和DaoSupportImpl实现类.(不改名也行,只要不要搞错.)然后让Service的接口和Service的实现分别继承DaoSupport和DaoSupportImpl,这样Service中对于基本的增删改查就不用处理了,只需要处理一些其他的方法了.如DepartmentService,部门Service接口,基础了DaoSupport,不用些findAll()等等方法了,因为DaoSupport中都提供了.只需要写上自己的findTopList()这样的方法
public interface DepartmentService extends DaoSupport<Department> { /* 查询 */ // List<Department> findAll(); // /* 删除 */ // void delete(Long id); // /* 添加 */ // void add(Department model); // /* 根据Id查询实体 */ // Department getById(Long id); // /* 更新 */ // void update(Department department); //找到所有顶级部门 List<Department> findTopList(); //查找该部门下的所有子部门 List<Department> findChildren(Long parentId); }这样,做完之后,若再新建Action,只需要写一个Service接口和Service的实现类就可以了,不用再写Dao和Dao的实现了.但是这样还是会有问题,在删除的时候,删除需要在事务中,但是@Transactional注解,只在Service实现类上才有,而真正的删除是在Dao中,注解是可以继承的,但是继承只是对子类有效,对父类无效,所以在DaoSupportImpl中的真正的删除是不在事务中的,所以无法删除.解决的做法就是将@Transactional
,写到DaoSupportImpl中,这样DaoSupportImpl就在事务中,而它所有的的子类也是在事务中的.所以现在就是这样了.
而现在的结构就是这样的.MyAction继承了BaseAction,而BaseAction又继承了ActionSupport,并且BaseAction提取了公共代码,实例化Service,以及注入model实体.而MyAction通过调用Service的接口,而调用了Service的实现类,并且这两个都提取了一些公共代码,方便公用.DaoSupport是增删改查的基本方法的接口,而DaoSupportImpl则是实现了的增删改查方法.
用户管理的实现以及MD5的密码实现
接下来是用户管理的实现,并且将流程做了一个总结.下面的图片就是总结的实现流程首先写userAction,继承BaseAction,并且写上注解@Controller和@Scope("prototype") 分别表示userAction交由容器管理,以及是多例的.每调用一次,生成一个userAction对象.然后由于userAction需要调用Service,所以创建userAction的userService接口和实现类.并且该Impl实现类中需要继承DaoSupportImpl和实现Service接口,以及写上注解@Service,表示将该Service放到容器中.若实现类中有方法不是基本的增删改查,则需要在Service的实现中,注入sessionFactory,写新方法用它来完成功能.举例,如
@Service @Transactional @SuppressWarnings("unchecked") public class DepartmentServiceImpl extends DaoSupportImpl<Department> implements DepartmentService { @Resource private SessionFactory sessionFactory; public List<Department> findTopList() { return sessionFactory.getCurrentSession().createQuery(// "FROM Department d WHERE d.parent IS NULL")// .list(); } public List<Department> findChildren(Long parentId) { return sessionFactory.getCurrentSession().createQuery(// "FROM Department d WHERE d.parent.id = ?")// .setParameter(0, parentId)// .list(); } }
然后在BaseAction中将该Service注入.
@Resource protected UserService userService;
再在struts.xml文件中写上新的Action配置
<!-- 用户管理 --> <action name="user_*" class="userAction" method="{1}"> <result name="list">/WEB-INF/jsp/userAction/list.jsp</result> <result name="saveUI">/WEB-INF/jsp/userAction/saveUI.jsp</result> <result name="toList" type="redirectAction">user_list?parentId=${parentId}</result> </action>
最后,只要写Action的方法,以及JSP页面就可以了.普通的增删改查就直接调用,Service方法就可以,但是对于跳转到页面,往往需要准备数据;以及添加数据的时候,页面传递过来的是id或者id数组,但是该属性为实体或者实体集合,所以还需要单独处理.
如添加页面需要准备树状部门列表和岗位列表
/** * 添加页面 * @return * @throws Exception */ public String addUI() throws Exception { //准备树状部门列表 List<Department> topList = departmentService.findTopList(); List<Department> departmentList = DepartmentUtils.getAllDepartments(topList); ActionContext.getContext().put("departmentList", departmentList); //准备岗位列表 List<Role> roleList = roleService.findAll(); ActionContext.getContext().put("roleList",roleList); return "saveUI"; } 以及添加的时候需要根据传递的departmentId和roleIds来获取部门实体和岗位集合. /** * 添加 * @return * @throws Exception */ public String add() throws Exception { //设置所有部门 model.setDepartment(departmentService.getById(departmentId)); //设置关联的岗位 List<Role> roleList = roleService.getByIds(roleIds); model.setRoles(new HashSet<Role>(roleList)); //设置默认密码为1234 String md5Digest = DigestUtils.md5Hex("1234"); model.setPassword(md5Digest); // model.setPassword("1234"); userService.save(model); return "toList"; }
其中由于要求设置用户名初始化密码为"1234",但是存储明文在数据库中一看就知道密码了,所以需要对密码加密,引入commons-codec.jar,调用它的md5Hex()方法就可以,将1234加密,变成一段看不懂的内容.
在数据库中就是这样,其中81dc9bdb52d04dc20036dbd8313ed055就是1234的md5加密之后的结果.
权限的设计
权限的设计,分析权限.所谓权限就是通过对url的访问控制,来达到对某些角色,某些功能可用,某些功能不可用的作用.设定权限模型就是这样的,有用户和角色,以及权限.其中用户和角色是多对多的关系,一个用户可以有多个角色,一个角色可以包含多个用户;角色和权限也是多对多的关系,一个角色有多个权限,一个权限属于多个角色. 用户的权限就是该用户所有角色的权限的合集,并且判断一个功能是否能被某用户使用,只需要通过判断用户权限是否有这个功能的使用许可就可以了.
所有建立用户和角色和权限的实体和实体的映射文件.用户和角色都已经建立,只需要建立权限,以及修改一下角色,因为角色和权限还有关系,所以要加一个权限的属性;他们的类图就是这样
在Role(可以翻译为角色或者岗位)中添加privileges 角色集合属性.
//角色和权限的关系(多对多) private Set<Privilege> privileges = new HashSet<Privilege>();新建的权限实体,是树形结构,本类和parent(上级)是多对1,而本类对children(下级)是1对多.
/** * 权限类 * @author liu * */ public class Privilege { //主键 private Long id; //角色集合 private Set<Role> roles = new HashSet<Role>(); private String url;//路径 private String name;//权限名称 //权限是树形结构, //上级 private Privilege parent; //下级 private Set<Privilege> children = new HashSet<Privilege>(); public Privilege() {}; public Privilege( String name,String url,Privilege parent) { this.url = url; this.name = name; this.parent = parent; } //getter,setter方法省略 }建立映射文件,就是之前说的填空的方式.先写注释,然后再按注释填空,将属性填到name中,将类填到class中,并且多对多,一对多/多对一两两为1对,对着填就好了.由于用户和角色的关系已经写好了,不用在写映射文件了,所以只用修改Role的映射文件以及添加一个权限privilege的映射文件.
其中,Role中的权限是多对多的关系.注释是关系是多对多,并且权限类型是set集合,所以用set,并且要有table第三张表,而key对应的是该映射文件的主键,它作为权限的外键存在.写好之后,如"roleId",拷到和他一对的manytomany标签的column属性中.
<!-- privileges属性,本类与Privilege的多对多 --> <set name="privileges" table="itcast_role_privilege"> <key column="roleId"></key> <many-to-many class="Privilege" column="privilegeId"></many-to-many> </set>这个和在Privilege权限类中的roles属性是一对.
按照注释,属性填到name中,类填到class中.table的名字,一对的要一样.key是当前的映射实体(权限)说明的id要叫的名字,所以在Role映射文件中的manytmany标签的column的属性中写上privilegeId,而manytomany的column是Role类对应的实体主键.其中table,key的column和manytomany的column一对的都是要互相对应着的.
<!-- roles属性,本类与Role的多对多 --> <set name="roles" table="itcast_role_privilege"> <key column="privilegeId"></key> <many-to-many class="Role" column="roleId"></many-to-many> </set>
还有就是权限类中的树形结构的自关联.manytoone和onetomany也是一对.manytoone和manytoone会在多的一端加上一的一端的主键,所以一端说明关联字段为parentId,多端把这个作为外键放在表中.
<!-- parent属性,本类与Privilege(上级)的多对一 --> <many-to-one name="parent" class="Privilege" column="parentId" ></many-to-one> <!-- children属性,本类与Privilege(下级)的一对多 --> <set name="children" cascade="delete" order-by="id ASC" > <key column="parentId"></key> <one-to-many class="Privilege"/> </set>
其中总结下,对于多对一和一对多,是根据本类与该属性的关系来判断的,本类与该属性为一对多的关系,就用onetomany.并且多端和一端都是需要写name,class和column的属性的,只是多端需要设置外键,所以column写在了key标签中.而多对多是需要再加一张第三表的,两个表的id合起来才是一个主键,所以除了在key中写外键列column,还需要在manytomany中写主键列column.
最后,写完之后,不要忘了添加到hibernate.cfg.xml中.
权限数据的初始化
对于权限来说,有一些数据是初始化在数据库中的,你可以采用写slq脚本的方式,insert数据到数据库中,但是由于数据库的差异性,sql脚本可能不通用,需要为不同的数据库写不同的脚本,所以为了解决这个问题.就写代码,用程序来生成初始化数据,这样只要hibernate支持的数据库,我们都能插入数据.
做法就是写一个叫Installer的工具类.
@Component //放在容器中 public class Installer { @Resource //注入SessionFactory private SessionFactory sessionFactory; @Transactional //需要事务 public void install() { Session session = sessionFactory.getCurrentSession(); //================================================================= //保存超级管理员用户 User user = new User(); user.setLoginName("admin"); user.setName("超级管理员"); user.setPassword(DigestUtils.md5Hex("admin")); session.save(user); //保存 //====================================================================== //保存权限数据 Privilege menu,menu1,menu2,menu3,menu4,menu5; //顶级菜单,作用:对二级菜单分类,没有url menu = new Privilege("系统管理",null,null); menu1 = new Privilege("岗位管理","/role_list",menu); menu2 = new Privilege("部门管理","/department_list",menu); menu3 = new Privilege("用户管理","/user_list",menu); //menu4 = new Privilege("岗位管理","/ItcastOA/role_list.action",parent); session.save(menu); session.save(menu1); session.save(menu2); session.save(menu3); session.save(new Privilege("岗位列表","/role_list",menu1)); session.save(new Privilege("岗位删除","/role_delete",menu1)); session.save(new Privilege("岗位添加","/role_add",menu1)); session.save(new Privilege("岗位修改","/role_edit",menu1)); session.save(new Privilege("部门列表","/department_list",menu2)); session.save(new Privilege("部门删除","/department_delete",menu2)); session.save(new Privilege("部门添加","/department_add",menu2)); session.save(new Privilege("部门修改","/department_edit",menu2)); session.save(new Privilege("用户管理","/user_list",menu3)); session.save(new Privilege("用户删除","/user_delete",menu3)); session.save(new Privilege("用户添加","/user_add",menu3)); session.save(new Privilege("用户修改","/user_edit",menu3)); session.save(new Privilege("初始化密码","/user_initPassword",menu3)); //-------------------------------- menu = new Privilege("网上交流",null,null); menu1 = new Privilege("论坛管理","/forumManage_list",menu); menu2 = new Privilege("论坛","/forum_list",menu); session.save(menu); session.save(menu1); session.save(menu2); //------------------------------------------ menu = new Privilege("审批流转",null,null); menu1 = new Privilege("审批流程管理","/processDefinition_list",menu); menu2 = new Privilege("申请模板管理","/template_list",menu); menu3 = new Privilege("起草管理","/flow_templateList",menu); menu4 = new Privilege("待我审批","/flow_myTaskList",menu); menu5 = new Privilege("我的申请查询","/flow_myApplicationList",menu); session.save(menu); session.save(menu1); session.save(menu2); session.save(menu3); session.save(menu4); session.save(menu5); } public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); Installer installer = (Installer)ac.getBean("installer"); installer.install(); } }其中,install()方法用来初始化数据,由于需要将数据写入数据库中,所以需要session和事务.将该类写上注解@Component,表示放入容器中,让容器来管理事务.而session,则通过注入sessionFactory,然后获取当前的session来获得.需要初始化两部分数据,一是一个超级管理员;2.是一对的权限数据,写到是不难,只是数据有些多.最后,就是要执行该方法,由于执行该方法写在main中,所以可以不用启动tomcat,直接执行java
Application就可以了.但是不启动tomcat,容器对象在监听器中创建,现在就不能创建了,怎么获取到容器中的Installer对象?所以直接读取配置文件applicationContext.xml,让它实例化一个Installer对象,我们再来用.
以上就是我第五天的学习,主要学习到的就是MD5的加密,以及action项目的流程,还有实体映射文件的写法的再次巩固,还有用main不启动tomcat,如何获取容器中的对象.应该再有4天就差不多学完了,加油哦!
相关文章推荐
- OA的学习--第六天的内容--权限模块和论坛模块
- OA的学习--第四天的内容--优化功能和页面
- OA的学习--第七天的内容--论坛模块
- OA的学习--第七天的内容--论坛模块
- OA(权限管理初步模块)
- 微软企业库4.1学习笔记(四)主要的功能模块简介
- [学习笔记]小型论坛功能——初步论坛形式[终]
- 标准功能模块组件 -- 名片管理组件,C\S 版本的标准用例程序,可以参考权限实现方法
- 标准功能模块组件 -- 名片管理组件,C/S 版本的标准用例程序,可以参考权限实现方法
- jsp常用功能模块-JSP实例学习教程
- 微软企业库4.1学习笔记(四)主要的功能模块简介
- 传智播客--OA的岗位管理功能模块的实现总结
- jsp常用功能模块-JSP实例学习教程
- RDIFramework.NET ━ .NET快速信息化系统开发框架 - 4.9 操作(功能)权限管理模块
- 标准功能模块组件 -- 名片管理组件,C\S 版本的标准用例程序,可以参考权限实现方法
- 标准功能模块组件 -- 名片管理组件,C\S 版本的标准用例程序,可以参考权限实现方法
- 微软企业库4.1学习笔记(四)主要的功能模块简介
- jsp常用功能模块-JSP实例学习教程
- 微软企业库4.1学习笔记(四)主要的功能模块简介
- 优化了碰撞检测与回复模块,增加了Sleep功能.