今天主要将Spring、Hibernate集成进CMS中,以及完成简单的数据库查询。
首先集成Spring,首先web项目中加入jar,关于Spring的jar这里不做要求(最好都用3.0以上的),在web.xml中加入Spring的监听,引导项目启动Spring,配置contextConfigLocation这个参数来装入Spring的配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- Spring配置文件引入 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
</param-value>
</context-param>
<!-- Struts2引入 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<!-- Spring启动配置 -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 欢迎页面 -->
<welcome-file-list>
<welcome-file>/public/index.jsp</welcome-file>
</welcome-file-list>
</web-app>
现在我们来看一下applicationContext.xml应该怎么配置?
⑴首先自然不能少了数据库连接配置:这里需要注意的就是数据源类型有几种,根据个人喜好。这里我用BasicDataSource,需要引入commons-dbcp.jar,commons-pool.jar。
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
这样配置数据源有2个缺点,一个是数据库密码没有加密,一个是参数值没有外在化管理。
所谓外在化管理,就是将配置文件需要传递参数单独用.properties文件保存。
Spring中有个标签可以很好的完成这项工作。目前applicationContext.xml文件配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
</beans>
jdbc.properties文件内容:(数据库配置根据自己需要配置)
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
jdbc.username=cms
jdbc.password=cms
现在我们在Spring中集成Hibernate,Spring集成Hibernate有两种:
1 .完全使用hibernate编写dao层,把dao注入到spring由spring来管理生命周期,这种方式的好处是dao层与spring没有耦合关系;缺点是需要谨慎处理hibernate的session 关闭, exception, transaction.
2 .使用spring的HibernateDaoSupport.这样的话dao层使用spring提供的一系列模板方法,同时不用关心session, exception,事务管理也交给了spring.第一种方式就不说了,基本无需改变dao层。只需要把dao注入就可以了,就学习一下第二种
在applicationContext.xml配置hibernate,主要分成3个部分:
1.引入数据源配置,即上面dataSource。
2.hibernate属性配置。
3.实体类加载,两种方法:要么自己列出来,要么要系统自己去读取。
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<value>
<!-- 设置数据库方言 -->
hibernate.dialect=org.hibernate.dialect.OracleDialect
<!-- 设置自动创建|更新|验证数据库表结构 -->
hibernate.hbm2ddl.auto=none
<!-- 是否在控制台显示sql -->
hibernate.show_sql=true
</value>
</property>
<property name="packagesToScan" value="com.bean" />
</bean>
以上关于数据库的配置基本已经完成,关于事务控制等用到在配置。
现在我们可以开始去完成简单的登录了,关于系统中acegi配置暂时不解析,我们主要验证数据库是否配置成功。
这里强调一下,关于hibernate的jar引用,根据错误提示自己去百度,这里我就不列举需要哪些jar了。
我们回到上一章的index.jsp,我们知道CMS内容展示系统主要在系统刚进入主页就会展示一些内容,因此这里我们要修改一下进入index.jsp的方式,前面我们用welcome-file来直接进主页,现在我们这用welcome-file配置的页面调用action来查询数据然后返回index.jsp来展示数据。
先新增toindex.jsp
<%@ page language="java" pageEncoding="utf-8"%>
<jsp:forward page="index.do"></jsp:forward>
然后修改web.xml中welcome-file来调用struts2中的action
<welcome-file-list>
<welcome-file>toindex.jsp</welcome-file>
</welcome-file-list>
我们主要是先检验hibernate是否能使用,因此先制作新闻头条这个功能,我们在struts.xml中添加index
这个action,struts.xml如下:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<constant name="struts.action.extension" value="do" />
<package name="CMS" extends="struts-default">
<action name="index" class="com.action.LoginAction" method="toIndex">
<result name="success">public/index.jsp</result>
</action>
</package>
</struts>
关于进首页就调用action,这里我遇到第一个瓶颈,首先是struts.xml中未配置以下
<constant name="struts.action.extension" value="do" />
那么我的struts2请求一直是404,因为前面关于struts2的集成我的配置结果如下,如果配置成*.action就不用配置上面常量,do是因为个人配置。
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
现在我们编写先编写hibernate接口类,此类的作用主要是复用,大家应该清楚基本上简单的实体类都存在增、删、改、查,因此我们需要将这些方法都提取出来,根据传递参数不同来实现代码的复用。
IHibernateSupportDao.java
package com.dao;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
public interface IHibernateSupportDao<T> {
public abstract List findByExample(DetachedCriteria dc);
}
IHibernateSupportDaoImpl.java
package com.dao.impl;
import java.util.List;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.dao.IHibernateSupportDao;
public class IHibernateSupportDaoImpl<T> implements IHibernateSupportDao<T>{
@Autowired
public SessionFactory sessionFactory;
@Transactional
@Override
public List findByExample(DetachedCriteria dc) {
return dc.getExecutableCriteria(sessionFactory.getCurrentSession()).list();
}
}
这里用sessionFactory.getCurrentSession()获取session,还有一种方法是openSession(),这两种方法是由区别的,具体网上都有,这里我们会遇到一个问题,我们必须在applicationContext.xml中添加Spring事务控制,然后在dao层数据库方法上添加@Transactional 这个注解<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
这样essionFactory.getCurrentSession()这个方法才能用,具体网上也有讲解,有疑问的可以查找。实体类NewsEntity
package com.bean;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@SuppressWarnings("serial")
@Entity
@Table(name="news")
public class NewsEntity implements Serializable{
private Integer id;
private String title; //标题
private String author; //作者
private String source; //来源
private Date pubtime=new Date(); //发布时间
private String content; //内容
private Integer viewNum=0; //浏览数目
private String img; //新闻封面图片
private Integer status=1; //新闻状态 1普通,2推荐, 3栏目头条, 4首页flash 图片新闻
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name="title",length=50,nullable=false)
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Column(name="author",length=10,nullable=true)
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Column(name="source",length=20,nullable=true)
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
@Column(name="pubtime")
public Date getPubtime() {
return pubtime;
}
public void setPubtime(Date pubtime) {
this.pubtime = pubtime;
}
@Column(name="content",length=65535,nullable=false)
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Column(name="viewnum")
public Integer getViewNum() {
return viewNum;
}
public void setViewNum(Integer viewNum) {
this.viewNum = viewNum;
}
@Column(name="img",length=50,nullable=true)
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
@Column(name="status")
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}
Service层NewService.java
package com.service;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.bean.NewsEntity;
import com.dao.NewDao;
@Service
public class NewService {
@Autowired
private NewDao newDao;
public List<NewsEntity> getNewList(DetachedCriteria newsBigImgdc){
return newDao.findByExample(newsBigImgdc);
}
}
DAO层NewDao.java
package com.dao;
import com.bean.NewsEntity;
public interface NewDao extends IHibernateSupportDao<NewsEntity>{
}
NewDaoImpl.java
package com.dao.impl;
import org.springframework.stereotype.Repository;
import com.bean.NewsEntity;
import com.dao.NewDao;
@Repository
public class NewDaoImpl extends IHibernateSupportDaoImpl<NewsEntity> implements NewDao{
}
LoginAction.java
package com.action;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.stereotype.Controller;
import com.bean.NewsEntity;
import com.opensymphony.xwork2.ActionSupport;
import com.service.NewService;
@Controller
public class LoginAction extends ActionSupport{
@Autowired
private NewService service;
private List<NewsEntity> newsBigImgList;
public List<NewsEntity> getNewsBigImgList() {
return newsBigImgList;
}
public void setNewsBigImgList(List<NewsEntity> newsBigImgList) {
this.newsBigImgList = newsBigImgList;
}
public String toIndex(){
DetachedCriteria newsBigImgdc = DetachedCriteria.forClass(NewsEntity.class);
newsBigImgdc.add(Restrictions.eq("status", 4));
newsBigImgList=service.getNewList(newsBigImgdc);
return SUCCESS;
}
}
在上面代码我们可以看到我用了@AutoWired自动注入,这里我遇到第二个纠结的问题,就是bean已经在容器里了,但是这里一直不能注入,查找了很多资料,后面才发现我们必须引入struts2-spring-plugin-2.1.8.1.jar这个jar包,这个是spring与struts2整合用的包。
现在我们在数据库创建表和加入数据
create table NEWS
(
id NUMBER,
content CLOB,
source VARCHAR2(20),
status NUMBER,
title VARCHAR2(50),
author VARCHAR2(10),
pubtime DATE,
viewnum NUMBER,
img VARCHAR2(50),
menuid NUMBER
)
insert into news (ID, CONTENT, SOURCE, STATUS, TITLE, AUTHOR, PUBTIME, VIEWNUM, IMG, MENUID)
values (10, '<CLOB>', '校园网', 4, '大一美女新生报道', 'admin', to_date('27-04-2013 17:33:39', 'dd-mm-yyyy hh34:mi:ss'), 0, '20060502213355913.jpg', 3);
insert into news (ID, CONTENT, SOURCE, STATUS, TITLE, AUTHOR, PUBTIME, VIEWNUM, IMG, MENUID)
values (12, '<CLOB>', '哈哈', 4, '这个校园动态新闻1,你懂的。', 'admin', to_date('27-04-2013 17:35:24', 'dd-mm-yyyy hh34:mi:ss'), 0, '200812201116135572.jpg', 3);
insert into news (ID, CONTENT, SOURCE, STATUS, TITLE, AUTHOR, PUBTIME, VIEWNUM, IMG, MENUID)
values (13, '<CLOB>', '哈哈', 2, '这个校园动态新闻2,你懂的。', 'admin', to_date('27-04-2013 17:35:42', 'dd-mm-yyyy hh34:mi:ss'), 0, null, 3);
insert into news (ID, CONTENT, SOURCE, STATUS, TITLE, AUTHOR, PUBTIME, VIEWNUM, IMG, MENUID)
values (14, '<CLOB>', '哈哈', 1, '这个校园动态新闻1,你懂的。', 'admin', to_date('27-04-2013 17:36:34', 'dd-mm-yyyy hh34:mi:ss'), 0, null, 3);
insert into news (ID, CONTENT, SOURCE, STATUS, TITLE, AUTHOR, PUBTIME, VIEWNUM, IMG, MENUID)
values (15, '<CLOB>', '哈哈', 1, '这个校园风采新闻1,你懂的。', 'admin', to_date('27-04-2013 17:37:10', 'dd-mm-yyyy hh34:mi:ss'), 0, null, 4);
insert into news (ID, CONTENT, SOURCE, STATUS, TITLE, AUTHOR, PUBTIME, VIEWNUM, IMG, MENUID)
values (16, '<CLOB>', '哈哈', 2, '这个校园风采新闻2,你懂的。', 'admin', to_date('27-04-2013 17:37:19', 'dd-mm-yyyy hh34:mi:ss'), 0, null, 4);
insert into news (ID, CONTENT, SOURCE, STATUS, TITLE, AUTHOR, PUBTIME, VIEWNUM, IMG, MENUID)
values (17, '<CLOB>', '哈哈', 2, '这个校园风采新闻2,你懂的。', 'admin', to_date('27-04-2013 17:37:19', 'dd-mm-yyyy hh34:mi:ss'), 0, null, 4);
insert into news (ID, CONTENT, SOURCE, STATUS, TITLE, AUTHOR, PUBTIME, VIEWNUM, IMG, MENUID)
values (18, '<CLOB>', '哈哈', 2, '这个校园风采新闻1,你懂的。', 'admin', to_date('27-04-2013 17:37:27', 'dd-mm-yyyy hh34:mi:ss'), 0, null, 4);
这时候我们进入首页就会查询这张表并展示,注意index.jsp页面的这一块,循环遍历查询到的list,然后轮询展示,这个以后遇到了可以借鉴。
<div >
<script type=text/javascript>
var focus_width=300;
var focus_height=230;
var swf_height = focus_height;
var picPath='${cms}/p_w_picpaths/';
var pics='';
var links='';
<c:forEach items="${newsBigImgList}" var="nb">
pics+=picPath+'<c:out value="${nb.img}"/>|';
links+="<c:url value="/news/see.do?id=${nb.id}"/>|";
</c:forEach>
pics=pics.substring(0,pics.length-1);
links=links.substring(0,links.length-1);
var flash_path='<c:url value="/p_w_picpaths/s_flash.swf"/>';
document.write('<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" width="'+ focus_width +'" height="'+ swf_height +'">');
document.write('<param name="allowScriptAccess" value="sameDomain"><param name="movie" value="'+flash_path+'"><param name="quality" value="high"><param name="bgcolor" value="#F0F0F0">');
document.write('<param name="menu" value="false"><param name=wmode value="opaque">');
document.write('<param name="FlashVars" value="pics='+pics+'&links='+links+'&borderwidth='+focus_width+'&borderheight='+focus_height+'">');
document.write('<embed src="'+flash_path+'" wmode="opaque" FlashVars="pics='+pics+'&links='+links+'&borderwidth='+focus_width+'&borderheight='+focus_height+'" menu="false" bgcolor="#F0F0F0" quality="high" width="'+ focus_width +'" height="'+ swf_height +'" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />');
document.write('</object>');
</script>
</div>
我们看一下现在的效果图:
目前已经初步完成了SSH3个框架之间的集成,剩下的就是添加其他的功能,关于权限的控制我们后面需要重点做,这节的代码我上传到51,地址:http://down.51cto.com/data/2259941