本项目使用Struts2+spring3+hibernate3;
第一步:引入jar包,具体需要哪些包根据实际情况加入。注意:把jar包导入后需要对所有包Add to Build Path;然后对工程名右键Build Path——>configure Build Path——>Add External JARS选择tomcat路径,添加"servlet-api.jar" "el-api.jar" "jsp-api.jar" 这三个jar包。
:
第二步:配置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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <context:component-scan base-package="ssh.demo.dao,ssh.demo.service,ssh.demo.action" /> <import resource="dao.xml"/> <import resource="service.xml"/> </beans>
我把配置根据作用对象不同分别写在两个配置文件中,再在applicationContext.xml文件中import.
1.dao.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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <!--c3p0连接池参数设置说明 --> <!--maxPoolSize表示连接池中保留的最大连接数,default为15 --> <!--minPoolSize表示连接池中保留的最小连接数 --> <!--initialPoolSize表示初始化时获取的连接数,取值应该在maxPoolSize和minPoolSize之间,default为3 --> <!--maxIdleTime表示最大空闲时间,60秒内未使用则连接被丢弃,若为0则永不丢弃,default为0 --> <!--acquireIncrement当连接池用连接被耗尽的时候c3p0一次同时获取的连接数,default 3 --> <!--maxStatements,JDBC的标准参数,用于控制数据源内加载的PreparedStatements数量,但由于预缓存的statements属于单个connection而不是整个连接池。 所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭,default 0 --> <!--idleConnectionTestPeriod表示每多少秒检查连接池中的空闲连接,default 0 --> <!--acquireRetryAttempts定义在数据库获取新连接失败后重新尝试的次数,default --> <!--breakAfterAcquireFailure获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调用getConnection()的时候继 续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false --> <!--testConnectionOnCheckout因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都将校验其有效性。建议使用 idleConnectionTestPeriod或automaticTestTable等方法来提升连接测试的性能。Default: false --> <!-- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/sshanno" /> <property name="user" value="root" /> <property name="password" value="root" /> <property name="maxPoolSize" value="20" /> <property name="minPoolSize" value="5" /> <property name="maxStatements" value="50" /> <property name="maxIdleTime" value="1800" /> </bean> --> <!-- location值为参数配置文件的位置 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!--dbcp连接池参数设置说明 --> <!--initialSize表示池启动时创建的连接数量 --> <!--maxActive表示同一时间可以从池分配的最多连接数量,设置为0时表示无限制 --> <!--maxIdle表示池里不会释放的最多的空闲的连接数量,设置为0时表示无限制 --> <!--minIdle表示在不新建连接条件下,池中保持空闲的最少连接数 --> <!--removeAbandoned设置自动回收超时连接,value为true或false --> <!--removeAbandonedTimeout设置自动回收超时时间(以秒数为单位) --> <!--logAbandoned设置在自动回收超时连接的时候打印连接的超时错误,value为true或false --> <!--maxWait等待超时以毫秒为单位,在抛出异常前,池等待连接被回收的最长时间(当没有可用连接时),设置为-1表示无限等待 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${driverClassName}" p:url="${url}" p:username="${username}" p:password="${password}" p:maxActive="${maxActive}" p:maxIdle="${maxIdle}" p:minIdle="${minIdle}"/> <!--在hibernate3中获取sessionFactory ,hibernate4则class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" --> <!--设置属性说明 --> <!--hibernate.dialect设置方言 --> <!--hibernate.format_sql输出格式化的sql --> <!--hibernate.show_sql控制台输出sql --> <!--hibernate.hbm2ddl.auto 自动创建|更新|验证数据库表结构。有以下几个参数: create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。 create-drop:每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。 update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了 但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。 validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 --> <!--current_session_context_class使用缓存机制。(hibernate3:Thread或jta);(hibernate4:org.springframework.orm.hibernate4.SpringSessionContext) --> <!--hibernate.cache.provider_class 使用Ehcache缓存;hibernate3是org.hibernate.cache.HashtableCacheProvider;hibernate4是net.sf.ehcache.hibernate.EhCacheProvider --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource"/> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2005Dialect</prop> --> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> --> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="current_session_context_class">Thread</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</prop> </props> </property> <!--自动扫描(实体类)注解包:实体类位置为:com.spring.mvc.entities.User,不能写成:com.spring.mvc.entities,而要写成:com.spring.mvc,packagesToScan要比实际上前一层--> <property name="packagesToScan" value="ssh.demo..*"/> <!-- 对于annotatedClasses只能一个类一个类的写,不能用*通配符 。可以用packagesToScan扫描包的方式代替annotatedClasses方式--> <!-- <property> <list> <value>ssh.demo.*</value> </list> </property> --> <!--上面的方法是错误的,下面的方法才是正确的。但是当类很多时,可以用packagesToScan扫描包的方式代替 --> <!-- <property name="annotatedClasses"> <list> <value>ssh.demo.domain.User</value> <value>ssh.demo.domain.UserLog</value> <value>ssh.demo.domain.Product</value> </list> </property> --> </bean> <!--hibernate3.1以及以上版本取消了hibernateTemplate,hibernate4需要通过getCurrentSession()获取session --> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate" p:sessionFactory-ref="sessionFactory" /> </beans>
上面设置数据源时使用了外部参数配置文件:jdbc.properties
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/sshanno?useUnicode=true&characterEncoding=utf-8 username=root password=root maxActive=50 maxIdle=40 minIdle=10 #driverClassName=net.sourceforge.jtds.jdbc.Driver #url=jdbc:jtds:sqlserver://localhost:1433;databaseName=ssh #username=sa #password=sa #maxActive=50 #maxIdle=40 #minIdle=10 #driverClassName=oracle.jdbc.driver.OracleDriver #url=jdbc:oracle:thin:@localhost:1521:orcl #username=cd #password=cd #maxActive=50 #maxIdle=40 #minIdle=10
2.service.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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <!--spring对hibernate的事务管理 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory"> </bean> <aop:config> <aop:pointcut expression="execution(* ssh.demo.service..*(..))" id="serviceMethod"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/> </aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--默认: isolation:DEFAULT propagation:REQUIRED timeout:-1 事物超时时间由底层事物系统决定 read-only:false rollback-for:所有允许异常回滚 no-rollback-for:所有检查异常不回滚 --> <tx:method name="get*" read-only="true"/> <tx:method name="do*"/> </tx:attributes> </tx:advice> </beans>
第三步:配置struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!-- 自动扫描action包 --> <!-- 注解需要的jar包:struts2-convention-plugin --> <!-- <constant name="struts.convention.default.parent.package" value="default" /> --> <constant name="struts.convention.package.locators" value="action" /> <constant name="struts.convention.classes.reload" value="true" /> <!-- <constant name="struts.objectFactory" value="spring"/> --> <package name="default" namespace="/" extends="struts-default"> <!-- <action name="product" class="ssh.demo.action.ProdutAction" method="getProducts"> <result name="success">/product.jsp?preparedProducts=true</result> </action> --> </package> </struts>
第四步:配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>ssh</display-name> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list> <context-param> <param-name>log4jConfigLocation</param-name> <!-- <param-value>/WEB-INF/classes/log4j.properties</param-value> --> <param-value>classpath:log4j.properties</param-value> </context-param> <context-param> <param-name>log4jRefreshInterval</param-name> <param-value>3000</param-value> </context-param> <listener> <listener-class> org.springframework.web.util.Log4jConfigListener </listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <!-- <param-value>/WEB-INF/classes/applicationContext.xml</param-value> --> <param-value>classpath*:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- strut2 dispatcher --> <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>/*</url-pattern> <!-- 为了页面能用jsp:forward,否则struts2接管请求,跳不到action去。 --> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping> <!--为解决lazy=true在jsp页面上遍历数据,此时相关类(one2many)再查找,没有session的情况 --> <!--getCurrentSession()事务会自动关闭,所以在所有jsp页面查询数据都会关闭session。要想在jsp查询数据库需要加入下面这个 --> <filter> <filter-name>hibernateFilter</filter-name> <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class> </filter> <filter-mapping> <filter-name>hibernateFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
第五步:新建实体类
package ssh.demo.domain; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; import org.hibernate.annotations.BatchSize; /** * 用户表 * * 一般不要使用catalog属性, * catalog是对应数据库名称,比如:在MySQL中数据库名称是ssh * 但在MSSQL中,不使用catalog,使用的是schema * MSSQL默认的schema是dbo * @author fox * */ @Entity @Table(name="tbl_user") public class User implements Serializable { private static final long serialVersionUID = -8992313421496945642L; /** * Oracle 下查看序列命令:select * from user_sequences */ @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="user_id") private Long id; @Column(name="user_loginname", unique=true, nullable=false) private String loginName; @Column(name="user_loginpassword", nullable=false) private String loginPassword; @OneToMany(mappedBy="user", fetch=FetchType.LAZY) @BatchSize(size=10) private Set<UserLog> userLogs = new HashSet<UserLog>(); public Set<UserLog> getUserLogs() { return userLogs; } public void setUserLogs(Set<UserLog> userLogs) { this.userLogs = userLogs; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } public String getLoginPassword() { return loginPassword; } public void setLoginPassword(String loginPassword) { this.loginPassword = loginPassword; } }
package ssh.demo.domain; 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.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; /** * 用户登录情况表 * * @author fox * */ @Entity @Table(name="tbl_userlog") public class UserLog implements Serializable { private static final long serialVersionUID = -6520978050619047269L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="userlog_id") private Long id; @Column(name="userlog_date", nullable=false) private Date date; @Column(name="userlog_type") private String type; @ManyToOne @JoinColumn(name="user_id") private User user; public String getType() { return type; } public void setType(String type) { this.type = type; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
tbl_user表和tbl_userlog表是一对多的关系。
第六步:controller层
package ssh.demo.action; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.struts2.interceptor.ServletRequestAware; import org.apache.struts2.interceptor.ServletResponseAware; import org.springframework.web.context.ServletContextAware; import com.opensymphony.xwork2.ActionSupport; public class BaseAction extends ActionSupport implements ServletContextAware, ServletRequestAware, ServletResponseAware { private static final long serialVersionUID = -2778286744226080905L; protected HttpServletRequest request; protected HttpServletResponse response; protected HttpSession session; protected ServletContext application; @Override public void setServletResponse(HttpServletResponse response) { this.response = response; } @Override public void setServletRequest(HttpServletRequest request) { this.request = request; this.session = this.request.getSession(); } @Override public void setServletContext(ServletContext application) { this.application = application; } }
package ssh.demo.action; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Result; import org.apache.struts2.convention.annotation.Results; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import ssh.demo.domain.User; import ssh.demo.service.UserService; import com.opensymphony.xwork2.ModelDriven; /** * 使用注解的方式配置,struts2的action不再是单例,不需要加@scope("prototype") * 而此时,service和dao默认还是单例 * @author fox * */ @Controller @Results({ @Result(name = "input", location = "/login.jsp", type="redirect" , params={"error", "1"}), @Result(name = "success", location = "/index.jsp", type="redirect")}) public class LoginAction extends BaseAction implements ModelDriven<User> { private static final long serialVersionUID = -6335887400814653355L; public LoginAction(){ System.out.println("---LoginAction 构造函数---"); } @Autowired private UserService userService; private User user = new User(); public User getModel() { return this.user; } @Action("/doLogin") public String doLogin() throws Exception { System.out.println("--Hello--"); System.out.println(this.user.getLoginName()); System.out.println(this.user.getLoginPassword()); System.out.println(this.request.getParameter("loginName")); System.out.println(this.request.getParameter("loginPassword")); System.out.println(this.userService); User u = this.userService.getUserLogin(this.user.getLoginName(), this.user.getLoginPassword()); if(u == null) { System.out.println("--登录失败---"); return INPUT; } else { System.out.println("--登录成功---"); this.userService.doSaveUserLog(u); return SUCCESS; } } }
第七步:service层
package ssh.demo.service; import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import ssh.demo.dao.UserDao; import ssh.demo.dao.UserLogDao; import ssh.demo.domain.User; import ssh.demo.domain.UserLog; @Service("userService") public class UserServiceImpl implements UserService{ public UserServiceImpl(){ System.out.println("---UserService 构造函数---"); } @Autowired private UserDao userDao; @Autowired private UserLogDao userLogDao; @Override public User getUserLogin(String loginName, String loginPassword) { return this.userDao.getUser(loginName, loginPassword); } }
第八步:dao层
package ssh.demo.dao; import java.sql.SQLException; import java.util.List; import org.hibernate.HibernateException; import org.hibernate.Session; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.stereotype.Repository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate3.HibernateTemplate; import ssh.demo.domain.User; @Repository("userDao") public class UserDaoImpl extends BaseDao implements UserDao{ public UserDaoImpl(){ System.out.println("---UserDao 构造函数---"); } @Autowired protected HibernateTemplate hibernateTemplate; @Override public User getUser(final String name, final String password) { System.out.println(this.hibernateTemplate); return (User)this.hibernateTemplate.execute(new HibernateCallback<Object>() { @Override public Object doInHibernate(Session session) throws HibernateException, SQLException { return session .createQuery("from User u where u.loginName=:name and u.loginPassword=:password") .setString("name", name) .setString("password", password) .uniqueResult(); } }); } @Override public void saveUser(User user) { this.hibernateTemplate.save(user); } @Override public List<User> getUsers() { return this.hibernateTemplate.loadAll(User.class); } }
最后补充:为了方便在控制台看见后台操作的结果,能够输出后台执行情况,再加一个文件log4j.properties
1 ##OFF->FATAL->ERROR->WARN->INFO->DEBUG->ALL 2 ##ERROR->WARN->INFO->DEBUG 3 # define a logger named CONSOLE 4 log4j.rootLogger=INFO, CONSOLE 5 # CONSOLE logger - console 6 log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 7 # COSOLE Layout 8 log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 9 # CONSOLE format Layout 10 log4j.appender.CONSOLE.layout.ConversionPattern=%5p %d{yyyy-MM-dd HH:mm:ss,SSS} %c:(%F:%L) - %m%n
到这里,再写好相应的jsp页面就可以运行一个springmvc的网站了。