http://jinnianshilongnian.iteye.com/blog/1423971
下載地址 一 開(kāi)發(fā)環(huán)境 1、動(dòng)態(tài)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、為了方便學(xué)習(xí),暫沒(méi)有使用maven構(gòu)建工程
?
二 工程主要包括內(nèi)容 1、springMVC + spring3.1.1 + hibernate4.1.0集成
2、通用DAO層 和 Service層
3、二級(jí)緩存 Ehcache
4、REST風(fēng)格的表現(xiàn)層
5、通用分頁(yè)(兩個(gè)版本)
5.1、首頁(yè) 上一頁(yè),下一頁(yè) 尾頁(yè) 跳轉(zhuǎn)
5.2、上一頁(yè) 1 2 3 4 5 下一頁(yè)
6、數(shù)據(jù)庫(kù)連接池采用proxool
7、spring集成測(cè)試 ???
8、表現(xiàn)層的 java validator框架驗(yàn)證(采用hibernate-validator-4.2.0實(shí)現(xiàn))
9、視圖采用JSP,并進(jìn)行組件化分離
?
三 TODO LIST? 將本項(xiàng)目做成腳手架方便以后新項(xiàng)目查詢 1、Service層進(jìn)行AOP緩存(緩存使用Memcached實(shí)現(xiàn))
2、單元測(cè)試(把常見(jiàn)的樁測(cè)試、偽實(shí)現(xiàn)、模擬對(duì)象演示一遍 區(qū)別集成測(cè)試)
3、監(jiān)控功能
后臺(tái)查詢hibernate二級(jí)緩存 hit/miss率功能??????
? ?后臺(tái)查詢當(dāng)前服務(wù)器狀態(tài)功能(如 線程信息、服務(wù)器相關(guān)信息)
4、spring RPC功能
5、spring集成 quartz 進(jìn)行任務(wù)調(diào)度
6、spring集成 java mail進(jìn)行郵件發(fā)送
7、DAO層將各種常用框架集成進(jìn)來(lái)(方便查詢)
8、把工作中經(jīng)常用的東西 融合進(jìn)去,作為腳手架,方便以后查詢
?
四 集成重點(diǎn)及常見(jiàn)問(wèn)題 1、spring-config.xml?配置文件:
1.1、該配置文件只加載除表現(xiàn)層之外的所有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>
通過(guò)exclude-filter 把所有 @Controller注解的表現(xiàn)層控制器組件排除
?
?
1.2、國(guó)際化消息文件配置
?
java代碼: Java代碼 ?
<!--?國(guó)際化的消息資源文件?--> ?? ????<bean?id="messageSource" ?class ="org.springframework.context.support.ReloadableResourceBundleMessageSource" > ?? ????????<property?name="basenames" > ?? ????????????<list> ?? ????????????????<!--?在web環(huán)境中一定要定位到classpath?否則默認(rèn)到當(dāng)前web應(yīng)用下找??--> ?? ????????????????<value>classpath:messages</value> ?? ????????????</list> ?? ????????</property> ?? ????????<property?name="defaultEncoding" ?value="UTF-8" /> ?? ????????<property?name="cacheSeconds" ?value="60" /> ?? ????</bean>?? <!-- 國(guó)際化的消息資源文件 --><bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"><property name="basenames"><list><!-- 在web環(huán)境中一定要定位到classpath 否則默認(rèn)到當(dāng)前web應(yīng)用下找 --><value>classpath:messages</value></list></property><property name="defaultEncoding" value="UTF-8"/><property name="cacheSeconds" value="60"/></bean>
此處basenames內(nèi)一定是 classpath:messages ,如果你寫出“messages”,將會(huì)到你的web應(yīng)用的根下找 即你的messages.properties一定在 web應(yīng)用/messages.propertis。
?
1.3、hibernate的sessionFactory配置 需要使用org.springframework.orm.hibernate4.LocalSessionFactoryBean,其他都是類似的,具體看源代碼。
?
1.4、<aop:aspectj-autoproxy expose-proxy="true"/> 實(shí)現(xiàn)@AspectJ注解的,默認(rèn)使用AnnotationAwareAspectJAutoProxyCreator進(jìn)行AOP代理,它是BeanPostProcessor的子類,在容器啟動(dòng)時(shí)Bean初始化開(kāi)始和結(jié)束時(shí)調(diào)用進(jìn)行AOP代理的創(chuàng)建,因此只對(duì)當(dāng)容器啟動(dòng)時(shí)有效,使用時(shí)注意此處。
?
1.5、聲明式容器管理事務(wù)
建議使用聲明式容器管理事務(wù),而不建議使用注解容器管理事務(wù)(雖然簡(jiǎn)單),但太分布式了,采用聲明式容器管理事務(wù)一般只對(duì)service層進(jìn)行處理。
?
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必須配置為開(kāi)啟事務(wù)?否則?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" > ?? ????<!--?只對(duì)業(yè)務(wù)邏輯層實(shí)施事務(wù)?--> ?? ????<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必須配置為開(kāi)啟事務(wù) 否則 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"><!-- 只對(duì)業(yè)務(wù)邏輯層實(shí)施事務(wù) --><aop:pointcut id="txPointcut" expression="execution(* cn.javass..service..*.*(..))" /><aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/></aop:config>
?
此處一定注意 使用 hibernate4,在不使用OpenSessionInView模式時(shí),在使用getCurrentSession()時(shí)會(huì)有如下問(wèn)題:
?
當(dāng)有一個(gè)方法list 傳播行為為Supports,當(dāng)在另一個(gè)方法getPage()(無(wú)事務(wù))調(diào)用list方法時(shí)會(huì)拋出org.hibernate.HibernateException: No Session found for current thread 異常。
這是因?yàn)間etCurrentSession()在沒(méi)有session的情況下不會(huì)自動(dòng)創(chuàng)建一個(gè),不知道這是不是Spring3.1實(shí)現(xiàn)的bug,歡迎大家討論下。
?
因此最好的解決方案是使用REQUIRED的傳播行為。
?
?
二、spring-servlet.xml:
2.1、表現(xiàn)層配置文件,只應(yīng)加裝表現(xiàn)層Bean,否則可能引起問(wèn)題。
?
java代碼: Java代碼 ?
<!--?開(kāi)啟controller注解支持?--> ?? <!--?注:如果base-package =cn.javass?則注解事務(wù)不起作用--> ?? <context:component-scan?base-package ="cn.javass.demo.web.controller" > ?? ????<context:include-filter?type="annotation" ?expression="org.springframework.stereotype.Controller" /> ?? </context:component-scan>?? <!-- 開(kāi)啟controller注解支持 --><!-- 注:如果base-package=cn.javass 則注解事務(wù)不起作用--><context:component-scan base-package="cn.javass.demo.web.controller"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>
?
此處只應(yīng)該加載表現(xiàn)層組件,如果此處還加載dao層或service層的bean會(huì)將之前容器加載的替換掉,而且此處不會(huì)進(jìn)行AOP織入,所以會(huì)造成AOP失效問(wèn)題(如事務(wù)不起作用),再回頭看我們的1.4討論的。
?
?
2.2、<mvc:view-controller path="/"?view-name="forward:/index"/> 表示當(dāng)訪問(wèn)主頁(yè)時(shí)自動(dòng)轉(zhuǎn)發(fā)到index控制器。
?
?
2.3、靜態(tài)資源映射
?
java代碼: Java代碼 ?
<!--?當(dāng)在web.xml?中???DispatcherServlet使用?????<url-pattern>/</url-pattern>?映射時(shí),能映射靜態(tài)資源?--> ?? <mvc:default -servlet-handler/> ?? <!--?靜態(tài)資源映射?--> ?? <mvc:resources?mapping="/images/**" ?location="/WEB-INF/images/" ?/> ?? <mvc:resources?mapping="/css/**" ?location="/WEB-INF/css/" ?/> ?? <mvc:resources?mapping="/js/**" ?location="/WEB-INF/js/" ?/>?? <!-- 當(dāng)在web.xml 中 DispatcherServlet使用 <url-pattern>/</url-pattern> 映射時(shí),能映射靜態(tài)資源 --><mvc:default-servlet-handler/><!-- 靜態(tài)資源映射 --><mvc:resources mapping="/images/**" location="/WEB-INF/images/" /><mvc:resources mapping="/css/**" location="/WEB-INF/css/" /><mvc:resources mapping="/js/**" location="/WEB-INF/js/" />
以上是配置文件部分,接下來(lái)來(lái)看具體代碼。
?
?
三、通用DAO層Hibernate4實(shí)現(xiàn)
為了減少各模塊實(shí)現(xiàn)的代碼量,實(shí)際工作時(shí)都會(huì)有通用DAO層實(shí)現(xiàn),以下是部分核心代碼:
?
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() {//事務(wù)必須是開(kāi)啟的,否則獲取不到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);}
}
?
?
?
五、表現(xiàn)層?Controller實(shí)現(xiàn)
采用SpringMVC支持的REST風(fēng)格實(shí)現(xiàn),具體看代碼,此處我們使用了java Validator框架 來(lái)進(jìn)行 表現(xiàn)層數(shù)據(jù)驗(yàn)證
?
在Model實(shí)現(xiàn)上加驗(yàn)證注解
?
?
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驗(yàn)證(用戶名字母數(shù)字組成,長(zhǎng)度為5-10)private String username;@NotEmpty(message = "{email.illegal}")@Email(message = "{email.illegal}") //錯(cuò)誤消息會(huì)自動(dòng)到MessageSource中查找private String email;@Pattern(regexp = "[A-Za-z0-9]{5,20}", message = "{password.illegal}")private String password;@DateFormat( message="{register.date.error}")//自定義的驗(yàn)證器private Date registerDate;
?
在Controller中相應(yīng)方法的需要驗(yàn)證的參數(shù)上加@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集成測(cè)試
使用Spring集成測(cè)試能很方便的進(jìn)行Bean的測(cè)試,而且使用@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)能自動(dòng)回滾事務(wù),清理測(cè)試前后狀態(tài)。
?
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;……
}
?
其他部分請(qǐng)直接看源碼,歡迎大家討論。
?
?
原創(chuàng)內(nèi)容,轉(zhuǎn)載請(qǐng)注明私塾在線【http://sishuok.com/forum/blogPost/list/2625.html】
?
與50位技術(shù)專家面對(duì)面 20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖
總結(jié)
以上是生活随笔 為你收集整理的SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常见问题总结 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。