Java Web开发现在已然成为大型Wed项目的标准,之前一直盲目的使用框架,往往知其然不知其所以然。在经过一段时间的学习与开发,大概掌握了其脉络的基础上,对其做一定总结。
一、Java Web 基础
一个典型的Java Web项目往往包含这些元素:Jsp页面、Servlet、Listener、Filter,以及配置文件web.xml。其中:
Jsp和Servlet基本是一回事,主要用来响应客户端的请求。当然Jsp中可以直接嵌入HTML标签,主要还是负责展现。
Listener则是负责监听Web应用的改变,包括整个应用的改变(继承接口ServletContextListener)、session的改变(继承接口 HttpSessionListener)等。Listener伴随着Web应用一起启动,因而有时也不用来监听,而是执行某些附加功能的初始化工作。
Filter顾名思义,则是实现对请求的过滤,现在常常用于某些MVC框架的中。
最后web.xml则是对Web应用版本、首页等基本特性的配置,以及以上元素的在Web中的配置。典型的web.xml配置文件如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 配置首页 --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!-- 配置Web容器参数,例如其他配置文件的位置 contextConfigLocation --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <!-- 配置 Listener --> <listener> <listener-class>ListenerXClass</listener-class> </listener> <!-- 配置 Filter --> <filter> <filter-name>FilterX</filter-name> <filter-class>FilterXClass</filter-class> </filter> <filter-mapping> <filter-name>FilterX</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置 Servlet --> <servlet> <servlet-name>ServletX</servlet-name> <servlet-class>ServletXClass</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletX</servlet-name> <url-pattern>/ServletX/path</url-pattern> </servlet-mapping> </web-app>
此外,一个典型的Java Web应用,其目录结构为:
|-- WebRoot | |-- META-INF | |-- MANIFEST.MF | |-- WEB-INF | |-- classes(servlet, listener, filter...) | |-- lib | |-- web.xml | |-- index.jsp
二、Struts
Struts是Java Web开发中非常流行的MVC框架,功能非常强大。然而,它的实现原理并没有它看上去那么高深,本质上Struts就是个Filter!所以使用它的时候,我们需要在web.xml中配置(struts2.3):
<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> </filter-mapping>
配好这个Filter之后,所有的请求就都被Struts接管了。然后请求的处理逻辑由另一个配置文件struts.xml来设置,包括action的跳转逻辑以及Struts的interceptor(用来代替原web.xml中的Filter)的配置。
<?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> <!-- 定义属性 --> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <constant name="struts.devMode" value="true" /> <!-- 定义全局默认配置,包括默认action、默认结果、默认异常处理 --> <package name="global-default" namespace="/" extends="struts-default"> <action name="defaultAction"> <result type="redirectAction">/index.jsp</result> </action> <default-action-ref name="defaultAction" /> <global-results> <result name="error">/error.jsp</result> </global-results> <global-exception-mappings> <exception-mapping exception="java.lang.Exception" result="error"/> </global-exception-mappings> </package> <!-- 定义action --> <package name="user-define" namespace="/user" extends="global-default"> <action name="user" class="user.UserAction"> <result name="success">/registerSuccess.jsp</result> <result name="failure">/registerFail.jsp</result> <result name="list">/userList.jsp</result> </action> </package> </struts>
此外,action的处理类常常继承自Struts的ActionSupport,其参数传递方式包括属性setter传递、domainModel传递、modelDriven传递(要继承ModelDriven接口)、原生Request传递(要继承RequestAware接口)。
三、Spring 和 Hibernate
Spring和Hibernate一般要同时设置,因为Hibernate基本上把自己全部交给了Spring去管理(连配置都是)。而Spring对应第一部分所讲的Java web元素而言,就是个Listener(当然责任要远大于一个Listener,Listener只是起到一个程序入口的作用)。所以在使用Spring的时候,我们需要在web.xml中配置(spring4.1):
<!-- Spring配置文件的位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- Spring程序入口 --> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>
Spring的作用主要有两个:
(1)管理对象的容器,即 Application Context, 负责对象的注入,称为依赖注入(DI),或控制反转(IOC)
(2)声明式事务管理,将事务的开始与提交以面向切面的方式(AOP)嵌入到程序中。
而Hibernate主要负责与数据库进行连接,即 SessionFactory,还有将数据库表映射成为对象,并维护对象之间一对多等的对应关系,以面向对象的方式对数据库进行增删改查。
Spring与Hibernate都可以配置在Spring的配置文件applicationContext.xml中:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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-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.xsd"> <!-- 以annotation的方式配置Spring的bean --> <context:annotation-config /> <context:component-scan base-package="user_package" /> <!-- 将数据库连接信息配置在jdbc.properties中 --> <context:property-placeholder location="classpath:jdbc.properties" /> <!-- 应用连接信息配置dbcp类型的数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 应用数据源配置Hibernate的sessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <!-- 应用数据源 --> <property name="dataSource" ref="dataSource" /> <!-- model配置 --> <property name="packagesToScan"> <list> <value>user_package.model</value> </list> </property> <!-- Hibernate的配置 --> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.show_sql=true </value> </property> </bean> <!-- 应用sessionFactory配置用于DAO层的hibernateTemplate --> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate4.HibernateTemplate"> <!-- 应用sessionFactory --> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 应用sessionFactory配置TransactionManager --> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 使用AOP将TransactionManager配置到相应的方法上 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="get*" read-only="true" /> <tx:method name="add*" propagation="REQUIRED" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* service..*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" /> </aop:config> </beans>
另外,程序中的annotation配置如下:
(1)Spring中的bean:
import javax.annotation.Resource; import org.springframework.stereotype.Component; //... @Component("beanName")//表明这是Spring管理的一个bean public class DaoBean { private HibernateTemplate hibernateTemplate; //... public HibernateTemplate getHibernateTemplate () { return hibernateTemplate; } @Resource(name = "hibernateTemplate")// 以 by name 的方式注入bean public void setHibernateTemplate (HibernateTemplate hibernateTemplate) { this.hibernateTemplate = hibernateTemplate; } //... }
(2)Hibernate中的实体类,即Model:
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; //... @Entity //表明这是一个Hibernate的实体类 public class EntityModel { private int id; //... @Id //设置主键 @GeneratedValue //设置自增 public int getId() { return id; } public void setId(int id) { this.id = id; } //... }
四、Struts与Spring、Hibernate的整合
Struts由于跟Spring一样都占据一种web组件(一个是Filter,一个是Listener),所以地位比较超然,既可以让Spring作为容器来管理action对象,也可以自己管理对象。
当Struts让Spring来管理对象时,需要通过一个插件 Struts-Spring plugin 来实现。通过这个插件,Struts就可以到Spring的容器中去获取对象了。此外其配置文件struts.xml需要加上:
<constant name="struts.objectFactory" value="spring" />
另外,配置action时,其class属性也应改为Spring中bean的名字,即:
<action name="user" class="userBeanName">
最后,在action的源代码中加入Spring的annotation就可以了:
@Component("userBeanName") @Scope("prototype") public class UserAction extends ActionSupport { private UserManager userManager; //... public UserManager getUserManager() { return userManager; } @Resource public void setUserManager(UserManager userManager) { this.userManager = userManager; } //... }
需要注意的是一定设置Scope为"prototype",这样当多个用户请求时,Spring就会创建多个action实例来处理请求;否则action就是单例,会引发未知的效果。