1,有幾個實體?java
通常是一組增刪改查對應一個實體。web
2,實體之間有什麼關係?spring
通常是頁面引用了其餘的實體時,就表示與這個實體有關聯關係。數據庫
3,每一個實體中都有什麼屬性?session
1,主鍵。推薦使用代理主鍵app
2,關聯關係屬性。在類圖中,關聯關係是一條線,有兩端,每一端對應一個表達此關聯關係的屬性。有幾個端指向本類,本類中就有幾個關聯關係屬性。dom
3,通常屬性。分析全部有關的頁面,找出表單中要填寫的或是在顯示頁面中要顯示的信息等。jsp
4,特殊屬性:爲解決某問題而設計的屬性。好比要顯示年齡,但不會設計一個int age字段,而是一個Date birthday字段,年齡是在顯示時實時計算出來的。ide
完成測試
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; } }
系統管理模塊_部門管理_映射本模塊中的全部實體並總結映射實體的技巧
設計實體、映射文件、建表
多對一 |
<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); } }