系统管理模块_部门管理_设计(映射)本模块中的所有实体并总结设计实体的技巧_懒加载异常问题_树状结构
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了系统管理模块_部门管理_设计(映射)本模块中的所有实体并总结设计实体的技巧_懒加载异常问题_树状结构相关的知识,希望对你有一定的参考价值。
系统管理模块_部门管理_设计本模块中的所有实体并总结设计实体的技巧
设计实体流程
1,有几个实体?
一般是一组增删改查对应一个实体。
2,实体之间有什么关系?
一般是页面引用了其他的实体时,就表示与这个实体有关联关系。
3,每个实体中都有什么属性?
1,主键。推荐使用代理主键
2,关联关系属性。在类图中,关联关系是一条线,有两端,每一端对应一个表达此关联关系的属性。有几个端指向本类,本类中就有几个关联关系属性。
3,一般属性。分析所有有关的页面,找出表单中要填写的或是在显示页面中要显示的信息等。
4,特殊属性:为解决某问题而设计的属性。比如要显示年龄,但不会设计一个int age字段,而是一个Date birthday字段,年龄是在显示时实时计算出来的。
完成
Department.Java
public class Department { private Long id; private String name; private String description; private Set<User> users = new HashSet<User>(); private Department parent; private Set<Department> children = new HashSet<Department>(); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } public Department getParent() { return parent; } public void setParent(Department parent) { this.parent = parent; } public Set<Department> getChildren() { return children; } public void setChildren(Set<Department> children) { this.children = children; } }
Role.java
public class Role { private Long id; private String name; private String description; private Set<User> users = new HashSet<User>(); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } }
User.java
public class User { private Long id; private Department department; private Set<Role> roles = new HashSet<Role>(); private String loginName; //登录名 private String password; //密码 private String name; //真实姓名 private String gender; //性别 private String phoneNumber; //电话号码 private String email; //电子邮件 private String description; //说明 public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } public Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
系统管理模块_部门管理_映射本模块中的所有实体并总结映射实体的技巧
设计实体、映射文件、建表
Hibernate实体映射流程
多对一 |
<many-to-one name=“” class=“” column=“”/> |
一对多 (Set) |
<set name=""> <key column=""></key> <one-to-many class=""/> </set> |
多对多 (Set)比一对多多一个table和column属性 |
<set name="" table=""> <key column=""></key> <many-to-many class="" column=""/> </set> |
1,写注释
格式为:?属性,表达的是本对象与?的?关系。
例:“department属性,本对象与Department的多对一”
2,拷模板:
一对多多对多模板
3,填空:
name属性:属性名(写注释中的第1问号)
class属性:关联的实体类型(写注释中的第2个问号)
column属性:
<many-to-one column="..">:一般可以写成属性名加Id后缀,如属性为department,则column值写成departmentId。
一对多中的<key column="..">:从关联的对方(对方是多对一)映射中把column值拷贝过来。
多对多中的<set name="users" table="">:table属性写两个表的连接,比如itcast_user_role
多对多中的<key column=“..”>:一般可以写成本对象的名加Id后缀,如本对象名为User,则写为userId。
多对多中的<many-to-many column=“..”>:一般可以写为关联对象的名称加Id后缀。
4,运行SpringTest.java中的testSessionFactory()测试方法无报错,成功建表即可完成
完成
Departmnet.hbm.xml
<hibernate-mapping package="cn.itcast.oa.domain"> <class name="Department" table="itcast_department"> <id name="id"> <generator class="native" /> </id> <property name="name"></property> <property name="description"></property> <!-- users属性,本类与User的一对多 --> <set name="users"> <key column="departmentId"></key> <one-to-many class="User"/> </set> <!-- parent属性,本类与Department(上级)的多对一 --> <!-- name属性名 、class关联的实体类型 、column外键 --> <many-to-one name="parent" class="Department" column="parentId"></many-to-one> <!-- children属性,本类与Department(下级)的一对多 --> <set name="children"> <key column="parentId"></key> <one-to-many class="Department"/> </set> </class> </hibernate-mapping>
Role.hbm.xml
<hibernate-mapping package="cn.itcast.oa.domain"> <class name="Role" table="itcast_role"> <id name="id"> <generator class="native" /> </id> <property name="name"></property> <property name="description"></property> <!-- users属性,本类与User的多对多 --> <set name="users" table="itcast_user_role"> <key column="roleId"></key> <many-to-many class="User" column="userId"></many-to-many> </set> </class> </hibernate-mapping>
User.hbm.xml
<hibernate-mapping package="cn.itcast.oa.domain"> <class name="User" table="itcast_user"> <id name="id"> <generator class="native" /> </id> <property name="loginName"/> <property name="password"/> <property name="name"/> <property name="gender"/> <property name="phoneNumber"/> <property name="email"/> <property name="description"/> <!-- department属性,本类与Department的多对一 --> <!-- name属性名 、class关联的实体类型 、column外键 --> <many-to-one name="department" class="Department" column="departmentId"></many-to-one> <!-- roles属性,本类与Role的多对多 --> <set name="roles" table="itcast_user_role"> <key column="userId"></key> <many-to-many class="Role" column="roleId"></many-to-many> </set> </class> </hibernate-mapping>
系统管理模块_部门管理_在增删改功能中增加对上级部门的处理
添加上级部门,添加和修改删除也要跟着改变,对列表没有影响
1. 转到添加页面时,把上级部门的信息显示出来
对addUI()方法修改
2. 选择某个部门的时候与上级部门关联起来
怎么知道选哪个部门了呢,这时要在DepartmentAction中添加字段,实体就不要随便修改
private Long parentId;并提供setget方法
无论在javabean中还是在Action中都可以传递过来
删除上级部门采用级联删除要在Department.hbm.xml文件中配置,子孙部门就统统删除掉了
显示顶级部门
List.jsp页面也要有修改,一点击就显示上一层
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
懒加载异常
具体步骤:
1. 对Action类进行修改
DepartmentAction.java
@Controller @Scope("prototype") public class DepartmentAction extends ActionSupport implements ModelDriven<Department>{//这里也需要转递参数id,名称和说明,实体里都有了。所以要实现ModelDriven,封装表单当中传递过来的参数 //有接口有实现类,想用它就创建,采用@Resource注入 @Resource private DepartmentService departmentService; private Long parentId; private Department model = new Department(); public Department getModel() { return model; } /** * 列表 */ public String list() throws Exception { List<Department> departmentList = departmentService.findAll();//findAll()在DepartmentService接口中创建 if(parentId == null) {//等于空就查询顶级 //显示顶级部门,设置查询顶级列表即可 departmentList = departmentService.findTopList(); }else { //查询子部门列表,告诉他我的Id departmentList = departmentService.findChildren(parentId); } //顶级部门与子部门集合在一起 ActionContext.getContext().put("departmentList", departmentList);//放在map里面方便拿,#号获取 return "list"; } /** * 删除 */ public String delete() throws Exception { departmentService.delete(model.getId());//delete()在DepartmentService接口中创建 return "toList"; } /** * 添加页面 */ public String addUI() throws Exception { //准备数据,DepartmnetList List<Department> departmentList = departmentService.findAll(); ActionContext.getContext().put("departmentList", departmentList);//一般放在值栈中的map,获取用#号获取方便 return "saveUI"; } /** * 添加 */ public String add() throws Exception { //封装到对象中 /*Department department = new Department(); department.setName(model.getName()); department.setDescription(model.getDescription()); //保存到数据库中 departmentService.save(department);*/ //关联上级部门 Department parent = departmentService.getById(parentId);//根据id查询出相应的对象再关联关系 model.setParent(parent); //添加的方法可以简化成一行代码 departmentService.save(model); return "toList"; } /** * 修改页面 */ public String editUI() throws Exception { //准备数据,DepartmnetList List<Department> departmentList = departmentService.findAll(); ActionContext.getContext().put("departmentList", departmentList);//一般放在值栈中的map,获取用#号获取方便 //准备回显的数据 Department department =departmentService.getById(model.getId());//把回显的数据的id告诉我 ActionContext.getContext().getValueStack().push(department);//把它放到栈顶就能回显 if(department.getParent() != null) {//回显上级部门 parentId = department.getParent().getId();//把数据给parentId } return "saveUI"; } /** * 修改 */ public String edit() throws Exception { //1.从数据库中取出原对象 Department department = departmentService.getById(model.getId()); //2.设置要修改的属性 department.setName(model.getName()); department.setDescription(model.getDescription()); department.setParent(departmentService.getById(parentId));//设置所属的上级部门 //3.更新到数据库中 departmentService.update(department); return "toList"; } public void setParentId(Long parentId) { this.parentId = parentId; } public Long getParentId() { return parentId; } }
对Service实现类进行修改
DepartmentServiceImpl.java
//在Action中要调用Service,要写下面两个注解 @Service @Transactional //业务层要管理实务,控制开关事务 @SuppressWarnings("unchecked") public class DepartmentServiceImpl implements DepartmentService{ //Service里要调用Dao,得到它通过注入 @Resource private DepartmentDao departmentDao; @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)//这里的索引0表示上面的问号 .list(); } public List<Department> findAll() { return departmentDao.findAll(); } public void delete(Long id) { departmentDao.delete(id); } public void save(Department model) { departmentDao.save(model); } public Department getById(Long id) { return departmentDao.getById(id); } public void update(Department department) { departmentDao.update(department); } }
Service接口中定义两个新的方法
DepartmentService.java
//接口中只有方法的声明,没有方法的实现 public interface DepartmentService { List<Department> findAll(); void delete(Long id); void save(Department model); Department getById(Long id); void update(Department department); //查询顶级部门列表 List<Department> findTopList(); //查询子部门列表 List<Department> findChildren(Long parentId); }
对BaseDaoImpl.java中的getById()方法修改
public T getById(Long id) { if(id == null) { return null; }else{ return (T) getSession().get(clazz, id); } }
处理懒加载问题
对Department.hbm.xml修改,添加lazy属性
<!-- parent属性,本类与Department(上级)的多对一 --> <!-- name属性名 、class关联的实体类型 、column外键 --> <many-to-one name="parent" class="Department" column="parentId" lazy="false"></many-to-one> <!-- children属性,本类与Department(下级)的一对多 --> <set name="children" cascade="delete" lazy="false"> <key column="parentId"></key> <one-to-many class="Department"/> </set>
list.jsp
saveUI.jsp
系统管理模块_部门管理_处理三个细节问题
点新建时默认显示上级部门,表单回显显示Action里的parentId的值,parentId属性怎么有值,传参数封装
增加返回上一级按钮,要不然后退会回到之前添加和修改的页面
//把parent对象事先放到map中,列表通过#号拿到parent对象 Department parent = departmentService.getById(parentId); ActionContext.getContext().put("departmentList", departmentList);
新建或修改后,回来不是在列表,解决:让它增删改之后回到列表页面
因为在struts.xml中没有带参数
这门在重定向到其他页面的时候,很有可能带些参数,可以使用ognl表达式
改进:使用OpenSessionInViewFilter方案解决Hibernate懒加载异常的问题
之前的解决办法是把懒加载关掉,懒加载好的特性就没用了
懒加载有点:可以适当的提高效率
把懒加载打开:去掉这个属性lazy="false"再访问会抛异常
想用懒加载,但又想不抛异常
Web程序中的懒加载异常说明及解决方案
出现:一个请求来的时候,先执行Action,再执行结果。在执行Action的时候里面调用Service,Service做真正的业务处理,开始执行Service方法的时候,开始事务,Service结束的时候事务提交或回滚session就会关闭。我们在Service中查询数据,在结果页面显示数据,在前面加载的时候没有懒加载属性,页面的时候用到了懒加载的属性,所以就出现懒加载异常,把懒加载关闭这个方法不好用。没有session我们就让他有session,不把session关掉,查询的时候可以不用事务,有session连接就行,在页面处理完之后再关,session早晚要关,我们在过滤器或拦截器里关session
使用OpenSessionInViewFilter解决解决懒加载问题,在web.xml中配置,一定要配置在struts2之前: <!-- 配置Spring的用于解决懒加载问题的过滤器 --> <filter> <filter-name>OpenSessionInViewFilter</filter-name> <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>OpenSessionInViewFilter</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping>
树状结构显示之讲解递归练习题并说明写递归代码的技巧
树状结构的显示说明
/** * 结构如下: * * ┣市场部 * ┣宣传部 * ┣业务部 * ┣业务一部 * ┣业务二部 * ┣开发部 * ┣开发一部 * ┣开发二部 * * @return 所有最顶层的部门的列表 */ public static List<Department> findTopLevelDepartmentList() { Department dept_1_1 = new Department(); dept_1_1.setId(new Long(11)); dept_1_1.setName("宣传部"); Department dept_1_2 = new Department(); dept_1_2.setId(new Long(12)); dept_1_2.setName("业务部"); Department dept_1_2_1 = new Department(); dept_1_2_1.setId(new Long(121)); dept_1_2_1.setName("业务一部"); Department dept_1_2_2 = new Department(); dept_1_2_2.setId(new Long(122)); dept_1_2_2.setName("业务二部"); dept_1_2_1.setParent(dept_1_2); dept_1_2_2.setParent(dept_1_2); Set<Department> children_0 = new LinkedHashSet<Department>(); children_0.add(dept_1_2_1); children_0.add(dept_1_2_2); dept_1_2.setChildren(children_0); // ================================ Department dept_1 = new Department(); dept_1.setId(new Long(1)); dept_1.setName("市场部"); dept_1_1.setParent(dept_1); dept_1_2.setParent(dept_1); Set<Department> children_1 = new LinkedHashSet<Department>(); children_1.add(dept_1_1); children_1.add(dept_1_2); dept_1.setChildren(children_1); // --- Department dept_2_1 = new Department(); dept_2_1.setId(new Long(21)); dept_2_1.setName("开发一部"); Department dept_2_2 = new Department(); dept_2_2.setId((new Long(22))); dept_2_2.setName("开发二部"); Department dept_2 = new Department(); dept_2.setId(new Long(2)); dept_2.setName("开发部"); dept_2_1.setParent(dept_2); dept_2_2.setParent(dept_2); Set<Department> children_2 = new LinkedHashSet<Department>(); children_2.add(dept_2_1); children_2.add(dept_2_2); dept_2.setChildren(children_2); // --- List<Department> depts = new ArrayList<Department>(); depts.add(dept_1); depts.add(dept_2); return depts; } 市场部 宣传部 业务部 业务一部 业务二部 开发部 开发一部 开发二部
/** * 练习一:打印所有顶层部门及其子孙部门的信息(名称) 提示:假设有一个 打印部门树 的信息 的方法 * * 要求打印如下效果: * * 市场部 * 宣传部 * 业务部 * 业务一部 * 业务二部 * 开发部 * 开发一部 * 开发二部 */ @Test public void printAllDepts_1() { List<Department> topList = findTopLevelDepartmentList(); /*// 方式一 for (Department top : topList) { showTree(top);//调用自己 }*/ // 方式二 showTreeList(topList); } /** * 显示一颗部门树中所有节点的信息 * * @param top * 树的顶点(根节点) */ private void showTree(Department top) { // 顶点 System.out.println(top.getName()); // 子树 for (Department child : top.getChildren()) { showTree(child); } } /** * 显示多颗树的所有节点的信息 * @param topList */ private void showTreeList(Collection<Department> topList) { for (Department top : topList) { // 顶点 System.out.println(top.getName()); // 子树 showTreeList(top.getChildren()); } }
/** * 练习二:打印所有顶层部门及其子孙部门的信息(名称),用不同的缩进表示层次(使用全角空格)。<br> * 子部门的名称前比上级部门多一个空格,最顶层部门的名字前没有空格。 提示:假设有一个打印部门集合中所有部门信息的方法 * * 要求打印如下效果: * * ┣市场部 * ┣宣传部 * ┣业务部 * ┣业务一部 * ┣业务二部 * ┣开发部 * ┣开发一部 * ┣开发二部 */ @Test public void printAllDepts_2() { List<Department> topList = findTopLevelDepartmentList(); showTreeList_2(topList, "┣"); } // 显示树 private void showTreeList_2(Collection<Department> topList, String prefix) { for (Department top : topList) { // 顶点 System.out.println(prefix + top.getName()); // 子树 showTreeList_2(top.getChildren(), " " + prefix); } }
以上是关于系统管理模块_部门管理_设计(映射)本模块中的所有实体并总结设计实体的技巧_懒加载异常问题_树状结构的主要内容,如果未能解决你的问题,请参考以下文章
系统管理模块_部门管理_改进_抽取添加与修改JSP页面中的公共代码_在显示层抽取BaseAction_合并Service层与Dao层
基于java+Spring+SpringMVC+mybatis的理论课_考勤,作业,签到管理系统
系统管理模块_岗位管理_实现CRUD功能的具体步骤并设计Role实体