系统管理模块_部门管理_设计(映射)本模块中的所有实体并总结设计实体的技巧_懒加载异常问题_树状结构

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实体

Java-单机版的书店管理系统(练习设计模块和思想_系列 四 )

java建站系统_无聊建站系统模块设计