以前SSH框架已經搭建完畢,如今進行實體類的分析和Base類的書寫。Base類是抽象類,專門用於繼承。前端
1、實體類關係分析java
既然是數據採集系統,首先調查實體(Survey)是必定要有的,一個調查有多個頁面(Page),一個頁面有多個問題(Question),因此還要有頁面和問題實體。參與完成調查以後必定還會生成若干個答案,因此還有答案實體(Answer),固然還有參與的用戶(User),管理員是特殊的User,只須要登錄的時候進行判斷便可。spring
分析實體類型是比較簡單的,最重要的是設計,怎樣設計才能知足調查中所須要的各類字段要求?各個實體之間是否有關係,若是有關係是否須要作雙向關聯(hibernate配置文件中聲明)?。sql
首先從User實體開始分析,一個用戶能夠參與多個調查,一個調查能夠被多個用戶參與,因此User和Survey實體之間是典型的多對多關係。既然有有關係了,那麼是否須要作雙向關聯?咱們常常作的是根據User對象拿到該User對象擁有的全部Survey,咱們基本上不會用到根據Survey對象取得User對象,因此咱們只須要作User到Survey的多對多映射關係便可。以上的分析是錯誤的。這裏的User和Survey之間的關係是建立的關係,而不是參與調查的關係。因此一個用戶可以建立多個調查,可是一個調查只能被一個用戶建立,因此調查和用戶之間是多對一關係。雖然咱們會經過User對象獲取Survey對象集合,可是咱們並不會常常這麼作,並且這麼作有一個致命的缺點,那就是會增長Session的存儲壓力。爲了減少Session的存儲壓力,咱們只作Survey到User的多對一單向關聯,不作User到Survey的多對一關聯。數據庫
Survey實體和Page以及User均有關係,可是不作到User的多對多關係的映射。Survey和Page之間是一對多的關係,一個頁面只能出如今一個Survey中,可是一個Survey中可以有多個Page。既然二者有關係,是須要作二者的雙向關聯關係仍是單向關聯關係?咱們會根據Survey對象獲取該對象的全部Page,也會根據該Page獲取該頁面屬於哪個Survey對象,因此咱們須要作雙向關聯關係,即作Survey到Page的一對多映射和作Page到Survey的多對一映射。apache
Page實體和Question同理,咱們須要作Page到Quesiton的一對多映射,也須要作Question到Page的多對一映射。數組
Answer實體暫時不做考慮。session
2、實體屬性分析app
1.Question分析(最複雜)框架
爲了可以使用該Question對象保存住全部九種類型的選項,Quesiton中的屬性可以表示出這九種類型。
九種類型的題型(排列順序不能改變,由於須要經過該位置獲取問題的類別):
第一類:非矩陣式橫向單選按鈕、非矩陣式縱向單選按鈕、非矩陣式橫向複選按鈕、非矩陣式縱向複選按鈕
第二類:非矩陣式下拉列表
第三類:非矩陣式文本框
第四類:矩陣式單選按鈕、矩陣式複選按鈕
第五類:矩陣式下拉列表
1 private transient Integer questionId; //問題的ID 2 /** 3 * 題型分爲0-8一共九種類型 4 */ 5 private int questionType; //問題的題型 6 private String title; //問題的標題 7 private String optionText; //問題的選項 8 private String[]optionTextArr; //問題選項的集合 9 10 private boolean other; //其餘項 11 //其餘項多是無、文本框、下拉列表框 12 private String otherType; //其餘項的樣式 13 private String otherSelectOptions; //其餘項若是是下拉列表框的話使用該項做爲內容 14 private String[] otherSelectOptionArr; //該字段對應着其餘項是多選框的狀況,這裏存放着拆分以後的字符串數組 15 16 private String matrixRowTitles; //矩陣式行標題集 17 private String[] matrixRowTitleArr; //矩陣式行標題集數組 18 private String matrixColTitles; //矩陣式列標題集 19 private String[] matrixColTitleArr; //矩陣式列標題集數組 20 private String matrixSelectOptions; //矩陣式下拉選項集 21 private String []matrixSelectOptionArr; //矩陣式下拉列表 22 23 //Question和Page之間是多對一的關係 24 private Page page;
對於每個問題來講,不可能每一個屬性都用的到,可是必需要這麼寫,不然就須要針對每一種提醒設計一種Question實體,那樣就麻煩了。
2.Page
private transient Integer pageId; //頁面id private String title="未命名"; //頁面標題 private String description; //頁面描述 //page和調查之間是多對一的關係 private transient Survey survey; //page和Question之間是一對多的關係 private Set<Question> questions=new HashSet<Question>(); private float orderNo; //排序的優先級,默認值和pageId相同
須要說明一個字段是orderNo,該字段的用處是排序,默認值和pageId相同,這個將會在之後的複製/移動頁的功能中使用到。
3.Survey分析(複雜)
1 private Integer surveyId; //對應着調查id 2 private String title="未命名"; //對應着調查名稱 3 private String preText="上一頁"; //對應着翻頁的上一個提示 4 private String nextText="下一頁"; //對應着下一頁的提示 5 private String exitText="退出"; //對應着退出的提示 6 private String doneText="完成"; //對應着完成的提示文本 7 private Date createDate=new Date(); //對應着建立的日期 8 private String logoPath; //使用該字段保存圖標的位置,保存的是相對位置 9 //調查和用戶之間是多對一的關係 10 private User user; 11 //調查和Page之間是一對多的關係 12 private transient Set<Page>pages=new HashSet<Page>(); 13 14 //添加一個調查是否可用的字段,表示打開或者關閉調查 15 private boolean closed; 16 17 /** 18 * TODO 在數據庫庫中沒有定義,可是須要在配置文件中定義並帶到前端頁面中使用 19 */ 20 private float maxOrderNo; //最小頁序 21 private float minOrderNo; //最大頁序 22 23 //定義幾個常量,方便判斷是哪一種類型的提交 24 private String submit_next="下一頁"; 25 private String submit_pre="上一頁"; 26 private String submit_done="提交"; 27 private String submit_exit="退出";
4.Use類分析
1 private Integer userId; //用戶id 2 private String password; //用戶密碼 3 private String nickName; //用戶暱稱 4 private String email; //用戶郵件 5 private Date registerDate; //用戶註冊日期 6 private Set<Role>roles; 7 private Boolean superAdmin; //斷定是不是超級管理員的標識字段 8 private long[]rightSum; //進行權限斷定的關鍵,注意這裏必定要使用基本數據類型,不然會有問題,由於包裝類型的默認值不是0,是null
該類在項目初期中只用到了一部分屬性,像是基本的userId、password等,剩下的roles、superAdmin、rightSum在權限管理模塊中會使用到。
5.hibernate映射文件略。
3、Base類書寫。
1.BaseDao書寫
針對每個實體,咱們都須要寫一個DAO操做對應的數據庫中的表,將全部的DAO中的公共方法抽象出來放到一個抽象類中是一個比較好的方法,這樣可以極大的重用代碼。固然,咱們還須要使用一個接口對該抽象類進行規範。
DAO接口規範:
1 package com.kdyzm.dao.base; 2 3 import java.io.Serializable; 4 import java.util.Collection; 5 import java.util.List; 6 7 public interface BaseDao <T>{ 8 //寫操做 9 public void saveEntity(T t); 10 public void updateEntity(T t); 11 public void saveOrUpdateEntity(T t); 12 public void deleteEntiry(T t); 13 14 //按照hql批處理 15 public void batchEntityByHql(String hql,Object ...objects); 16 17 //查詢方法 18 public T getEntityById(Serializable id); 19 public T loadEntiryById(Serializable id); 20 public List<T> findEntityByHQL(String hql,Object ...objects); 21 public Object findUniqueResult(String hql,Object ...objects); 22 public Collection<T> findAllEntities(); 23 public void executeSql(String sql,Object ...objects); 24 public Collection<T> findAllEntitiesBySql(String sql,Object ...objects); 25 }
實現類(抽象):
1 package com.kdyzm.dao.base.impl; 2 3 import java.io.Serializable; 4 import java.lang.reflect.ParameterizedType; 5 import java.util.Collection; 6 import java.util.List; 7 8 import javax.annotation.Resource; 9 10 import org.hibernate.Query; 11 import org.hibernate.SQLQuery; 12 import org.hibernate.SessionFactory; 13 14 import com.kdyzm.dao.base.BaseDao; 15 /*** 16 * BaseDaoImpl類必須是抽象類,實現已經定義好的接口 17 * @author kdyzm 18 * 19 * @param <T> 20 */ 21 @SuppressWarnings("unchecked") 22 public abstract class BaseDaoImpl<T> implements BaseDao<T> { 23 //手下須要兩個成員變量,這兩個成員變量的賦值,一個是經過spring容器管理,一個是經過泛型動態獲取 24 @Resource(name="sessionFactory") 25 public SessionFactory sessionFactory; 26 private Class<T> clazz; 27 28 //在默認構造方法中調用相關程序獲取真實的泛型類型 29 public BaseDaoImpl() { 30 ParameterizedType parameterizedType=(ParameterizedType) this.getClass().getGenericSuperclass(); 31 clazz=(Class<T>) parameterizedType.getActualTypeArguments()[0]; 32 } 33 @Override 34 public void saveEntity(T t) { 35 System.out.println("將要保存"+t); 36 this.sessionFactory.getCurrentSession().save(t); 37 } 38 39 @Override 40 public void updateEntity(T t) { 41 this.sessionFactory.getCurrentSession().update(t); 42 } 43 44 @Override 45 public void saveOrUpdateEntity(T t) { 46 this.sessionFactory.getCurrentSession().saveOrUpdate(t); 47 } 48 49 @Override 50 public void deleteEntiry(T t) { 51 this.sessionFactory.getCurrentSession().delete(t); 52 } 53 54 //批量處理更新的方法重點是使用Query對象 55 @Override 56 public void batchEntityByHql(String hql, Object... objects) { 57 Query query=this.sessionFactory.getCurrentSession().createQuery(hql); 58 for(int i=0;i<objects.length;i++){ 59 query.setParameter(i, objects[i]); 60 } 61 query.executeUpdate(); 62 } 63 64 @Override 65 public T getEntityById(Serializable id) { 66 return (T) this.sessionFactory.getCurrentSession().get(clazz,id); 67 } 68 69 @Override 70 public T loadEntiryById(Serializable id) { 71 return (T) this.sessionFactory.getCurrentSession().load(clazz, id); 72 } 73 74 @Override 75 public List<T> findEntityByHQL(String hql, Object... objects) { 76 Query query=this.sessionFactory.getCurrentSession().createQuery(hql); 77 for(int i=0;i<objects.length;i++){ 78 query.setParameter(i, objects[i]); 79 } 80 return query.list(); 81 } 82 @Override 83 public Object findUniqueResult(String hql, Object... objects) { 84 Query query=this.sessionFactory.getCurrentSession().createQuery(hql); 85 for(int i=0;i<objects.length;i++){ 86 query.setParameter(i, objects[i]); 87 } 88 return query.uniqueResult(); 89 } 90 @Override 91 public Collection<T> findAllEntities(){ 92 String hql="from "+clazz.getSimpleName(); 93 return this.sessionFactory.getCurrentSession().createQuery(hql).list(); 94 } 95 //直接執行sql語句的方法 96 @Override 97 public void executeSql(String sql, Object... objects) { 98 SQLQuery sqlQuery=this.sessionFactory.getCurrentSession().createSQLQuery(sql); 99 for(int i=0;i<objects.length;i++){ 100 sqlQuery.setParameter(i, objects[i]); 101 } 102 sqlQuery.executeUpdate(); 103 } 104 //根據sql語句獲得List集合的方法 105 @Override 106 public Collection<T> findAllEntitiesBySql(String sql, Object... objects) { 107 SQLQuery sqlQuery=this.sessionFactory.getCurrentSession().createSQLQuery(sql); 108 for(int i=0;i<objects.length;i++){ 109 sqlQuery.setParameter(i, objects[i]); 110 } 111 sqlQuery.addEntity(clazz); 112 return sqlQuery.list(); 113 } 114 }
實現類須要解決的問題:實現全部的公共方法是其功能要求,想要實現這一點,就必須解決一個最重要的問題,如何獲取泛型類型,全部的DAO都會提供一個泛型給父類,即BaseDaoImpl,父類必須知道該類型是什麼,在構造方法中獲取該類型是最合適的:
//在默認構造方法中調用相關程序獲取真實的泛型類型 public BaseDaoImpl() { ParameterizedType parameterizedType=(ParameterizedType) this.getClass().getGenericSuperclass(); clazz=(Class<T>) parameterizedType.getActualTypeArguments()[0]; }
這樣clazz對象就保存到了類中的成員變量,其它方法就可以直接使用該對象了。
2.BaseService書寫
BaseService接口中的方法和DAO中的方法相同,實現類中直接調用DAO中的方法
1 package com.kdyzm.service.base; 2 3 import java.io.Serializable; 4 import java.util.Collection; 5 import java.util.List; 6 7 public interface BaseService<T> { 8 //寫操做 9 public void saveEntity(T t); 10 public void updateEntity(T t); 11 public void saveOrUpdateEntity(T t); 12 public void deleteEntiry(T t); 13 14 //按照hql批處理 15 public void batchEntityByHql(String hql,Object ...objects); 16 17 //查詢方法 18 public T getEntityById(Serializable id); 19 public T loadEntiryById(Serializable id); 20 public List<T> findEntityByHQL(String hql,Object ...objects); 21 public Collection<T> findAllEntities(); 22 23 public void executeSql(String sql,Object ...objects); 24 public Collection<T> findAllEntitiesBySQl(String sql,Object ...objects); 25 }
BaseServiceImpl實現:實現類中有一個BaseDao<T>類型的成員變量,全部的DAO都實現了BaseDao接口,因此直接使用該接口來引用子類對象是能夠的,可是拿到泛型的方式並非DAO中的實現方式,而是直接由實現類經過set方法傳遞過來。
public BaseDao<T> baseDao; public void setBaseDao(BaseDao<T> baseDao) { this.baseDao = baseDao; }
4、針對各類DAO和Service的實現類略。
5、測試
1.實現加入log4j的配置文件到classpath,方便查看控制檯輸出。
1 ### direct log messages to stdout ### 2 log4j.appender.stdout=org.apache.log4j.ConsoleAppender 3 log4j.appender.stdout.Target=System.out 4 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 5 log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 6 7 ### direct messages to file hibernate.log ### 8 #log4j.appender.file=org.apache.log4j.FileAppender 9 #log4j.appender.file.File=hibernate.log 10 #log4j.appender.file.layout=org.apache.log4j.PatternLayout 11 #log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 12 13 ### set log levels - for more verbose logging change 'info' to 'debug' ### 14 15 log4j.rootLogger=warn, stdout 16 17 #log4j.logger.org.hibernate=info 18 log4j.logger.org.hibernate=info 19 20 ### log HQL query parser activity 21 #log4j.logger.org.hibernate.hql.ast.AST=debug 22 23 ### log just the SQL 24 #log4j.logger.org.hibernate.SQL=debug 25 26 ### log JDBC bind parameters ### 27 log4j.logger.org.hibernate.type=info 28 #log4j.logger.org.hibernate.type=debug 29 30 ### log schema export/update ### 31 log4j.logger.org.hibernate.tool.hbm2ddl=debug 32 33 ### log HQL parse trees 34 #log4j.logger.org.hibernate.hql=debug 35 36 ### log cache activity ### 37 #log4j.logger.org.hibernate.cache=debug 38 39 ### log transaction activity 40 #log4j.logger.org.hibernate.transaction=debug 41 42 ### log JDBC resource acquisition 43 #log4j.logger.org.hibernate.jdbc=debug 44 45 ### enable the following line if you want to track down connection ### 46 ### leakages when using DriverManagerConnectionProvider ### 47 #log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace
2.測試類
1 public class TestUserService { 2 private static ApplicationContext ac = null ; 3 4 @BeforeClass 5 public static void iniAC(){ 6 ac = new ClassPathXmlApplicationContext("spring/applicationContext.xml"); 7 } 8 9 @Test 10 public void insertUser(){ 11 UserService us = (UserService) ac.getBean("userService"); 12 User u = new User(); 13 u.setEmail("kdyzm@foxmail.com"); 14 u.setPassword("123456"); 15 us.saveEntity(u); 16 } 17 }