http://jinnianshilongnian.iteye.com/blog/1423971
下載地址
一 開發環境
1、動態web工程
2、部分依賴
?
java代碼: Java代碼 ?
hibernate-release-4.1.0.Final.zip ??hibernate-validator-4.2.0.Final.jar ??spring-framework-3.1.1.RELEASE-with-docs.zip ??proxool-0.9.1.jar ??log4j?1.2.16??slf4j?-1.6.1??mysql-connector-java-5.1.10.jar ??hamcrest?1.3.0RC2 ??ehcache?2.4.3?? hibernate-release-4.1.0.Final.zip
hibernate-validator-4.2.0.Final.jar
spring-framework-3.1.1.RELEASE-with-docs.zip
proxool-0.9.1.jar
log4j 1.2.16
slf4j -1.6.1
mysql-connector-java-5.1.10.jar
hamcrest 1.3.0RC2
ehcache 2.4.3
?
3、為了方便學習,暫沒有使用maven構建工程
?
二 工程主要包括內容
1、springMVC + spring3.1.1 + hibernate4.1.0集成
2、通用DAO層 和 Service層
3、二級緩存 Ehcache
4、REST風格的表現層
5、通用分頁(兩個版本)
5.1、首頁 上一頁,下一頁 尾頁 跳轉
5.2、上一頁 1 2 3 4 5 下一頁
6、數據庫連接池采用proxool
7、spring集成測試 ???
8、表現層的 java validator框架驗證(采用hibernate-validator-4.2.0實現)
9、視圖采用JSP,并進行組件化分離
?
三 TODO LIST? 將本項目做成腳手架方便以后新項目查詢
1、Service層進行AOP緩存(緩存使用Memcached實現)
2、單元測試(把常見的樁測試、偽實現、模擬對象演示一遍 區別集成測試)
3、監控功能
后臺查詢hibernate二級緩存 hit/miss率功能??????
? ?后臺查詢當前服務器狀態功能(如 線程信息、服務器相關信息)
4、spring RPC功能
5、spring集成 quartz 進行任務調度
6、spring集成 java mail進行郵件發送
7、DAO層將各種常用框架集成進來(方便查詢)
8、把工作中經常用的東西 融合進去,作為腳手架,方便以后查詢
?
四 集成重點及常見問題
1、spring-config.xml?配置文件:
1.1、該配置文件只加載除表現層之外的所有bean,因此需要如下配置:
?
java代碼: Java代碼 ?
<context:component-scan?base-package="cn.javass"> ??????<context:exclude-filter?type="annotation"?expression="org.springframework.stereotype.Controller"/> ??</context:component-scan>?? <context:component-scan base-package="cn.javass"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>
通過exclude-filter 把所有 @Controller注解的表現層控制器組件排除
?
?
1.2、國際化消息文件配置
?
java代碼: Java代碼 ?
<!--?國際化的消息資源文件?--> ??????<bean?id="messageSource"?class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> ??????????<property?name="basenames"> ??????????????<list> ??????????????????<!--?在web環境中一定要定位到classpath?否則默認到當前web應用下找??--> ??????????????????<value>classpath:messages</value> ??????????????</list> ??????????</property> ??????????<property?name="defaultEncoding"?value="UTF-8"/> ??????????<property?name="cacheSeconds"?value="60"/> ??????</bean>?? <!-- 國際化的消息資源文件 --><bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"><property name="basenames"><list><!-- 在web環境中一定要定位到classpath 否則默認到當前web應用下找 --><value>classpath:messages</value></list></property><property name="defaultEncoding" value="UTF-8"/><property name="cacheSeconds" value="60"/></bean>
此處basenames內一定是 classpath:messages ,如果你寫出“messages”,將會到你的web應用的根下找 即你的messages.properties一定在 web應用/messages.propertis。
?
1.3、hibernate的sessionFactory配置 需要使用org.springframework.orm.hibernate4.LocalSessionFactoryBean,其他都是類似的,具體看源代碼。
?
1.4、<aop:aspectj-autoproxy expose-proxy="true"/> 實現@AspectJ注解的,默認使用AnnotationAwareAspectJAutoProxyCreator進行AOP代理,它是BeanPostProcessor的子類,在容器啟動時Bean初始化開始和結束時調用進行AOP代理的創建,因此只對當容器啟動時有效,使用時注意此處。
?
1.5、聲明式容器管理事務
建議使用聲明式容器管理事務,而不建議使用注解容器管理事務(雖然簡單),但太分布式了,采用聲明式容器管理事務一般只對service層進行處理。
?
java代碼: Java代碼 ?
<tx:advice?id="txAdvice"?transaction-manager="txManager"> ??????<tx:attributes> ??????????<tx:method?name="save*"?propagation="REQUIRED"?/> ??????????<tx:method?name="add*"?propagation="REQUIRED"?/> ??????????<tx:method?name="create*"?propagation="REQUIRED"?/> ??????????<tx:method?name="insert*"?propagation="REQUIRED"?/> ??????????<tx:method?name="update*"?propagation="REQUIRED"?/> ??????????<tx:method?name="merge*"?propagation="REQUIRED"?/> ??????????<tx:method?name="del*"?propagation="REQUIRED"?/> ??????????<tx:method?name="remove*"?propagation="REQUIRED"?/> ??????????<tx:method?name="put*"?propagation="REQUIRED"?/> ??????????<tx:method?name="use*"?propagation="REQUIRED"/> ??????????<!--hibernate4必須配置為開啟事務?否則?getCurrentSession()獲取不到--> ??????????<tx:method?name="get*"?propagation="REQUIRED"?read-only="true"?/> ??????????<tx:method?name="count*"?propagation="REQUIRED"?read-only="true"?/> ??????????<tx:method?name="find*"?propagation="REQUIRED"?read-only="true"?/> ??????????<tx:method?name="list*"?propagation="REQUIRED"?read-only="true"?/> ??????????<tx:method?name="*"?read-only="true"?/> ??????</tx:attributes> ??</tx:advice> ??<aop:config?expose-proxy="true"> ??????<!--?只對業務邏輯層實施事務?--> ??????<aop:pointcut?id="txPointcut"?expression="execution(*?cn.javass..service..*.*(..))"?/> ??????<aop:advisor?advice-ref="txAdvice"?pointcut-ref="txPointcut"/> ??</aop:config>?? <tx:advice id="txAdvice" transaction-manager="txManager"><tx:attributes><tx:method name="save*" propagation="REQUIRED" /><tx:method name="add*" propagation="REQUIRED" /><tx:method name="create*" propagation="REQUIRED" /><tx:method name="insert*" propagation="REQUIRED" /><tx:method name="update*" propagation="REQUIRED" /><tx:method name="merge*" propagation="REQUIRED" /><tx:method name="del*" propagation="REQUIRED" /><tx:method name="remove*" propagation="REQUIRED" /><tx:method name="put*" propagation="REQUIRED" /><tx:method name="use*" propagation="REQUIRED"/><!--hibernate4必須配置為開啟事務 否則 getCurrentSession()獲取不到--><tx:method name="get*" propagation="REQUIRED" read-only="true" /><tx:method name="count*" propagation="REQUIRED" read-only="true" /><tx:method name="find*" propagation="REQUIRED" read-only="true" /><tx:method name="list*" propagation="REQUIRED" read-only="true" /><tx:method name="*" read-only="true" /></tx:attributes></tx:advice><aop:config expose-proxy="true"><!-- 只對業務邏輯層實施事務 --><aop:pointcut id="txPointcut" expression="execution(* cn.javass..service..*.*(..))" /><aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/></aop:config>
?
此處一定注意 使用 hibernate4,在不使用OpenSessionInView模式時,在使用getCurrentSession()時會有如下問題:
?
當有一個方法list 傳播行為為Supports,當在另一個方法getPage()(無事務)調用list方法時會拋出org.hibernate.HibernateException: No Session found for current thread 異常。
這是因為getCurrentSession()在沒有session的情況下不會自動創建一個,不知道這是不是Spring3.1實現的bug,歡迎大家討論下。
?
因此最好的解決方案是使用REQUIRED的傳播行為。
?
?
二、spring-servlet.xml:
2.1、表現層配置文件,只應加裝表現層Bean,否則可能引起問題。
?
java代碼: Java代碼 ?
<!--?開啟controller注解支持?--> ??<!--?注:如果base-package=cn.javass?則注解事務不起作用--> ??<context:component-scan?base-package="cn.javass.demo.web.controller"> ??????<context:include-filter?type="annotation"?expression="org.springframework.stereotype.Controller"/> ??</context:component-scan>?? <!-- 開啟controller注解支持 --><!-- 注:如果base-package=cn.javass 則注解事務不起作用--><context:component-scan base-package="cn.javass.demo.web.controller"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>
?
此處只應該加載表現層組件,如果此處還加載dao層或service層的bean會將之前容器加載的替換掉,而且此處不會進行AOP織入,所以會造成AOP失效問題(如事務不起作用),再回頭看我們的1.4討論的。
?
?
2.2、<mvc:view-controller path="/"?view-name="forward:/index"/> 表示當訪問主頁時自動轉發到index控制器。
?
?
2.3、靜態資源映射
?
java代碼: Java代碼 ?
<!--?當在web.xml?中???DispatcherServlet使用?????<url-pattern>/</url-pattern>?映射時,能映射靜態資源?--> ??<mvc:default-servlet-handler/> ??<!--?靜態資源映射?--> ??<mvc:resources?mapping="/images/**"?location="/WEB-INF/images/"?/> ??<mvc:resources?mapping="/css/**"?location="/WEB-INF/css/"?/> ??<mvc:resources?mapping="/js/**"?location="/WEB-INF/js/"?/>?? <!-- 當在web.xml 中 DispatcherServlet使用 <url-pattern>/</url-pattern> 映射時,能映射靜態資源 --><mvc:default-servlet-handler/><!-- 靜態資源映射 --><mvc:resources mapping="/images/**" location="/WEB-INF/images/" /><mvc:resources mapping="/css/**" location="/WEB-INF/css/" /><mvc:resources mapping="/js/**" location="/WEB-INF/js/" />
以上是配置文件部分,接下來來看具體代碼。
?
?
三、通用DAO層Hibernate4實現
為了減少各模塊實現的代碼量,實際工作時都會有通用DAO層實現,以下是部分核心代碼:
?
java代碼: Java代碼 ?
public?abstract?class?BaseHibernateDao<M?extends?java.io.Serializable,?PK?extends?java.io.Serializable>?implements?IBaseDao<M,?PK>?{ ??? ??????protected?static?final?Logger?LOGGER?=?LoggerFactory.getLogger(BaseHibernateDao.class); ??? ??????private?final?Class<M>?entityClass; ??????private?final?String?HQL_LIST_ALL; ??????private?final?String?HQL_COUNT_ALL; ??????private?final?String?HQL_OPTIMIZE_PRE_LIST_ALL; ??????private?final?String?HQL_OPTIMIZE_NEXT_LIST_ALL; ??????private?String?pkName?=?null; ??? ??????@SuppressWarnings("unchecked") ??????public?BaseHibernateDao()?{ ??????????this.entityClass?=?(Class<M>)?((ParameterizedType)?getClass().getGenericSuperclass()).getActualTypeArguments()[0]; ??????????Field[]?fields?=?this.entityClass.getDeclaredFields(); ??????????for(Field?f?:?fields)?{ ??????????????if(f.isAnnotationPresent(Id.class))?{ ??????????????????this.pkName?=?f.getName(); ??????????????} ??????????} ????????? ??????????Assert.notNull(pkName); ?????????? ??????????HQL_LIST_ALL?=?"from?"?+?this.entityClass.getSimpleName()?+?"?order?by?"?+?pkName?+?"?desc"; ??????????HQL_OPTIMIZE_PRE_LIST_ALL?=?"from?"?+?this.entityClass.getSimpleName()?+?"?where?"?+?pkName?+?"?>???order?by?"?+?pkName?+?"?asc"; ??????????HQL_OPTIMIZE_NEXT_LIST_ALL?=?"from?"?+?this.entityClass.getSimpleName()?+?"?where?"?+?pkName?+?"?<???order?by?"?+?pkName?+?"?desc"; ??????????HQL_COUNT_ALL?=?"?select?count(*)?from?"?+?this.entityClass.getSimpleName(); ??????} ????????? ??????@Autowired??????@Qualifier("sessionFactory") ??????private?SessionFactory?sessionFactory; ??? ??????public?Session?getSession()?{ ????????????????????return?sessionFactory.getCurrentSession(); ??????} ??…… ??}?? public abstract class BaseHibernateDao<M extends java.io.Serializable, PK extends java.io.Serializable> implements IBaseDao<M, PK> {protected static final Logger LOGGER = LoggerFactory.getLogger(BaseHibernateDao.class);private final Class<M> entityClass;private final String HQL_LIST_ALL;private final String HQL_COUNT_ALL;private final String HQL_OPTIMIZE_PRE_LIST_ALL;private final String HQL_OPTIMIZE_NEXT_LIST_ALL;private String pkName = null;@SuppressWarnings("unchecked")public BaseHibernateDao() {this.entityClass = (Class<M>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];Field[] fields = this.entityClass.getDeclaredFields();for(Field f : fields) {if(f.isAnnotationPresent(Id.class)) {this.pkName = f.getName();}}Assert.notNull(pkName);//TODO @Entity name not nullHQL_LIST_ALL = "from " + this.entityClass.getSimpleName() + " order by " + pkName + " desc";HQL_OPTIMIZE_PRE_LIST_ALL = "from " + this.entityClass.getSimpleName() + " where " + pkName + " > ? order by " + pkName + " asc";HQL_OPTIMIZE_NEXT_LIST_ALL = "from " + this.entityClass.getSimpleName() + " where " + pkName + " < ? order by " + pkName + " desc";HQL_COUNT_ALL = " select count(*) from " + this.entityClass.getSimpleName();}@Autowired@Qualifier("sessionFactory")private SessionFactory sessionFactory;public Session getSession() {//事務必須是開啟的,否則獲取不到return sessionFactory.getCurrentSession();}
……
}
Spring3.1集成Hibernate4不再需要HibernateDaoSupport和HibernateTemplate了,直接使用原生API即可。
?
?
四、通用Service層代碼?此處省略,看源代碼,有了通用代碼后CURD就不用再寫了。
?
java代碼: Java代碼 ?
@Service("UserService") ??public?class?UserServiceImpl?extends?BaseService<UserModel,?Integer>?implements?UserService?{ ??? ??????private?static?final?Logger?LOGGER?=?LoggerFactory.getLogger(UserServiceImpl.class); ??? ??????private?UserDao?userDao; ??? ??????@Autowired??????@Qualifier("UserDao") ??????@Override??????public?void?setBaseDao(IBaseDao<UserModel,?Integer>?userDao)?{ ??????????this.baseDao?=?userDao; ??????????this.userDao?=?(UserDao)?userDao; ??????} ????? ??? ??? ??????@Override??????public?Page<UserModel>?query(int?pn,?int?pageSize,?UserQueryModel?command)?{ ??????????return?PageUtil.getPage(userDao.countQuery(command)?,pn,?userDao.query(pn,?pageSize,?command),?pageSize); ??????} ??} ????? @Service("UserService")
public class UserServiceImpl extends BaseService<UserModel, Integer> implements UserService {private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);private UserDao userDao;@Autowired@Qualifier("UserDao")@Overridepublic void setBaseDao(IBaseDao<UserModel, Integer> userDao) {this.baseDao = userDao;this.userDao = (UserDao) userDao;}@Overridepublic Page<UserModel> query(int pn, int pageSize, UserQueryModel command) {return PageUtil.getPage(userDao.countQuery(command) ,pn, userDao.query(pn, pageSize, command), pageSize);}
}
?
?
?
五、表現層?Controller實現
采用SpringMVC支持的REST風格實現,具體看代碼,此處我們使用了java Validator框架 來進行 表現層數據驗證
?
在Model實現上加驗證注解
?
?
java代碼: Java代碼 ?
@Pattern(regexp?=?"[A-Za-z0-9]{5,20}",?message?=?"{username.illegal}")???private?String?username; ????@NotEmpty(message?=?"{email.illegal}") ??@Email(message?=?"{email.illegal}")???private?String?email; ????@Pattern(regexp?=?"[A-Za-z0-9]{5,20}",?message?=?"{password.illegal}") ??private?String?password; ????@DateFormat(?message="{register.date.error}")??private?Date?registerDate;?? @Pattern(regexp = "[A-Za-z0-9]{5,20}", message = "{username.illegal}") //java validator驗證(用戶名字母數字組成,長度為5-10)private String username;@NotEmpty(message = "{email.illegal}")@Email(message = "{email.illegal}") //錯誤消息會自動到MessageSource中查找private String email;@Pattern(regexp = "[A-Za-z0-9]{5,20}", message = "{password.illegal}")private String password;@DateFormat( message="{register.date.error}")//自定義的驗證器private Date registerDate;
?
在Controller中相應方法的需要驗證的參數上加@Valid即可
?
java代碼: Java代碼 ?
@RequestMapping(value?=?"/user/add",?method?=?{RequestMethod.POST}) ??public?String?add(Model?model,?@ModelAttribute("command")?@Valid?UserModel?command,?BindingResult?result)?? @RequestMapping(value = "/user/add", method = {RequestMethod.POST})public String add(Model model, @ModelAttribute("command") @Valid UserModel command, BindingResult result)
?
?
六、Spring集成測試
使用Spring集成測試能很方便的進行Bean的測試,而且使用@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)能自動回滾事務,清理測試前后狀態。
?
java代碼: Java代碼 ?
@RunWith(SpringJUnit4ClassRunner.class) ??@ContextConfiguration(locations?=?{"classpath:spring-config.xml"}) ??@Transactional??@TransactionConfiguration(transactionManager?=?"txManager",?defaultRollback?=?true) ??public?class?UserServiceTest?{ ????? ??????AtomicInteger?counter?=?new?AtomicInteger(); ????? ??????@Autowired??????private?UserService?userService; ??????……?? ??}?? @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-config.xml"})
@Transactional
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
public class UserServiceTest {AtomicInteger counter = new AtomicInteger();@Autowiredprivate UserService userService;……
}
?
其他部分請直接看源碼,歡迎大家討論。
?
?
原創內容,轉載請注明私塾在線【http://sishuok.com/forum/blogPost/list/2625.html】
?
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常见问题总结的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。