Annotation(注解)是JDK5.0及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解的使用非常简单,在代码中只需要以‘@注解名’这种形式使用即可。除了符号'@'以外,注解的用法和java的基本语法基本相似。
注解式配置又称为“零配置”。这是由于采用这种配置方式几乎不用写XML配置文件(仍旧有少量配置文件,后文将具体介绍)。在以往的项目中我们总是会使用大量的XML配置来搭建项目,项目越大其对应的配置文件就越多。项目维护时不仅要修改java文件还要修改XMl配置文件。而使用注解式配置则免去了配置文件膨胀以及维护点分散的麻烦,你只需要关注于java文件的修改。
本文的介绍基于Myeclipse9.0。
一、JAR
首先向大家介绍引入的jar包。偶是懒人一个,jar包就不一一写出了,特截图如下,图中是示例项目的所有外部jar包:
以上jar包已经表明了版本号,同学们切勿用错。
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_2_5.xsd" version="2.5"> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/SpringConfig/beans.xml</param-value> <!-- Spring配置文件地址 --> </context-param> <!-- Dwr配置 --> <servlet> <servlet-name>dwr</servlet-name> <servlet-class>org.directwebremoting.spring.DwrSpringServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dwr</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping> <!-- Spring上下文监听器 --> <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> <!-- Strust2配置 --> <filter> <filter-name>struts2</filter-name> <filter-class>util.DwrStrutsFilter</filter-class> <init-param> <param-name>actionPackages</param-name> <param-value>com.licong.action</param-value> </init-param> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
需要注意的是,struts2的过滤器需要使用 <url-pattern>/*</url-pattern> 配置,也就是拦截所有格式的请求。为了能够访问dwr的测试页面能正常工作(dwr测试页面地址为:"localhost:端口号/项目名称/dwr"),不被strust2拦截。本文采用自定义过滤器的方法放行dwr测试页面。
public class DwrStrutsFilter extends StrutsPrepareAndExecuteFilter {//继承strust2的过滤器,并加以修改 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest)request; if(httpRequest.getRequestURL().indexOf("/dwr") != -1) {//如果请求url中包含“/dwr”则放行 chain.doFilter(request, response); } else { super.doFilter(request, response, chain); } } }
在web.xml中struts2的过滤器用自定义的类替换掉自带的StrutsPrepareAndExecuteFilter
<!-- Strust2配置 --> <filter> <filter-name>struts2</filter-name> <filter-class>util.DwrStrutsFilter</filter-class> <init-param>
当然测试页面在项目发布时是需要关闭的,此时只要将
<servlet-class>org.directwebremoting.spring.DwrSpringServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param>
中得true设为false即可。表明dwr不开启调试模式。
Web.xml中包含了spring、strust2、dwr的配置,唯独没有hibernate。这是因为本文通过Spring来管理hibernate,只需要在spiring的配置文件中配号hibernate的相关配置就可以了。
Spring配置文件,BEAN.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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd" default-autowire="byName"> <context:annotation-config /> <!-- 配置Spring 注解扫描范围 --> <context:component-scan base-package="com.licong" /> <!-- 扫描spring注解的类,使其成为客户端调用接口 --> <dwr:annotation-config id="dwr_config"/> <!-- 扫描需要转换的java对象 --> <dwr:annotation-scan scanRemoteProxy="true" base-package="com.licong.dwr" /> <!-- dwr初始化配置 --> <dwr:configuration></dwr:configuration> <!-- 配置数据库连接dataSource --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@localhost:1521:TEST" /> <property name="username" value="lctm2005" /> <property name="password" value="tiger" /> </bean> <!-- 配置sessionFactory --> <bean id="sf" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan"> <list> <value>com.licong.domain</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.OracleDialect </prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> </props> </property> </bean> <!-- 配置hibernateTemplate --> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sf"></property> </bean> <!-- 注解式事务管理 --> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sf" /> </bean> </beans>
3、包结构:
示例项目中包层次分别为:
Action:action层,包含所有action类,这些类继承BaseAction
Service: 业务层,包含所有处理业务逻辑的类,这些类继承BaseService
Dao :数据连接层,包含所有用于访问数据的类,这些类继承BaseHibernateDao
Framework:框架,包含所有以Base开头的父类,以及DaoFactory
Domain:实体层,由hibernate使用,建立OR映射
Dwr:包含dwr需要调用的所有类
Uitl:工具类,目前仅包含自定义的Strust2过滤器DwrStrutsFilter
4、Action:
a) 所有的Action都通过继承BaseAction来继承Strust2的ActionSupport
b)BaseAction中可以完成一些公共的方法,比如异常日志的记录,操作日志的记录等等
c)以下是子类的代码
//@Namespace(value="/") //指定名称空间 //@ParentPackage(value="struts-default") //指定继承的包,struts-default无需指定 @Results({ @Result(name="success",location="/example/exampleResult.jsp"), @Result(name="error",location="/framework/error.jsp"), @Result(name="exception",location="/framework/exception.jsp") }) @ExceptionMappings({ @ExceptionMapping(exception = "java.lang.Exception", result = "exception") }) @Component("exampleAction") public class ExampleAction extends BaseAction { private List<CityPairDomain> cityPairList; private CityPairService cityPairService; @Override @Action ("exampleAction") public String execute() throws Exception { try{ cityPairList = cityPairService.getCityPairs(); }catch(Exception e) { e.printStackTrace(); throw e; } if (null != cityPairList) { return SUCCESS; } else { return ERROR; } } public List<CityPairDomain> getCityPairList() { return cityPairList; } public void setCityPairList(List<CityPairDomain> cityPairList) { this.cityPairList = cityPairList; } public CityPairService getCityPairService() { return cityPairService; } @Resource public void setCityPairService(CityPairService cityPairService) { this.cityPairService = cityPairService; } }
我们主要关注注释部分,其实注释大概有哪些大家可以通过XML配置推测出来,该有的总是要有的。
1)与Action相关的两个Annotation是@Action 和@Actions
2)@Action中可指定一个value属性。类似于指定<action name=””/>属性值,用于前台请求的映射,这个是必须的
3)@Action中还可以指定一个params属性,该属性是一个字符串数组,用于该Acion指定的参数名和参数值。params属性应遵守如下格式:{“name1”,”value1”,”name2”,”value2”} ,不过各人觉得完全没有这个必要,毕竟strust2已经能够“自动”把前台的form表单的内容映射到action的字段了。
4)@Actions 也用于修饰Action类里的方法,用于将该方法映射到多个URL.@Actions用于组织多个@Action.因此它可将一个方法映射成多个逻辑Action。当某个方法需要被多个不同URL公用时才派上用场,不过各人觉得容易导致混乱的代码,毕竟一般开发是按模块来的,各个类都有其特有作用,除非这个action定义出来就是作为一个公共类来使用。
5)@Results用于组织多个@Result因此它只需指定一个value属性值,该value属性值为多个@Result
6)@Result相当于struts.xml文件中的<result/>元素。使用@Result必须指定一个name属性,相当于<result name=””/>另外,它还有几个可选的属性。
7) @Namespace:修饰Action类或其所在的包。该Annotation中指定一个value属性值,用于指定被修饰的Action所在的命名空间
8) @Namespaces:修饰Action类或其所在的包,用于组合多个@Namespace
9) @ParentPackage: 用于指定被修饰的Action所在包的父包。
10)@ExceptionMappings
用于组织多个@ExceptionMapping,因此它只需指定一个value属性值,该value属性值为多个@ExceptionMapping。
11)@ExceptionMapping 用于定义异常类和物理视图之间的对应关系,也相当于struts.xml文件里<exception-mapping../>元素的作用 使用时,必须注意以下两个属性:
exception: 用于指定异常类 ;result:用于指定逻辑视图
12)除此之外,我们还可以定义拦截器,与拦截器配置的Annotation有@InterceptorRef、@InterceptorRefs和@DefaultInterceptorRef 同法与其他注解雷同,就不再介绍了。
如果你需要查看strust2注解配置的结果,struts2提供了Config Browser插件。使用方法:将struts2-config-browser-plugin-2.1.6.jar文件复制到struts2应用的WEB-INF\lib目录中。打开首页地址:http://localhost:8080/应用名字/config-browser/actionNames.action
这里可以看到Config Browser插件的首页。
5、Service:
一般来说业务层会抽象为接口供上次使用,例如:
public interface CityPairService { public List<CityPairDomain> getCityPairs() throws Exception; }
而实现类:
@Component("cityPairService") public class CityPairServiceImpl extends BaseService implements CityPairService { public List<CityPairDomain> getCityPairs() throws Exception{ return daoFactory.getCityPairDao().getCityPairs(); } }
由于在配置文件中配置了按名字进行注入(default-autowire="byName"),在action层调用该接口时需要保证对象名字与注解声明的名字一致。
QueryCityPairAction中部分代码:
private CityPairService cityPairService; public CityPairService getCityPairService() { return cityPairService; } @Resource public void setCityPairService(CityPairService cityPairService) { this.cityPairService = cityPairService; }
在set方法上加注解@Resource告知Spring使用set方法注入,当然也可以直接在变量上用@AutoWire注解告诉Spring进行注入操作。
那么BaseService又是怎么实现的呢?
public class BaseService { protected DaoFactory daoFactory; public DaoFactory getDaoFactory() { return daoFactory; } @Resource public void setDaoFactory(DaoFactory daoFactory) { this.daoFactory = daoFactory; } }
BaseService中注入了一个叫座DaoFactory的类的对象,该类中包含了所有Dao层类的对象(当然也是通过Spring注入的),任何一个业务层的类只需要调用
DaoFactory的getXXXDao()方法就可以获得相应DAO的对象,免去了再每个service类中注入DAO对象的麻烦。一个service类可能会用到多个DAO对象,会使得该类的代码变的冗长,通过该方法,在业务类中只需要专注于编写业务实现。
@Component("daoFactory") public class DaoFactory { private CityPairDao cityPairDao; public CityPairDao getCityPairDao() { return cityPairDao; } @Resource private void setCityPairDao(CityPairDao cityPairDao) { this.cityPairDao = cityPairDao; } }
6、DAO:
考虑到DAO层可能有多种实现方式,hibernate、jdbc等等,DAO层仍旧采用提供接口的方式供上层使用。此处以hibernate访问数据库为例
public abstract class BaseHibernateDao { protected HibernateTemplate hibernateTemplate; public HibernateTemplate getHibernateTemplate() { return hibernateTemplate; } @Resource public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { this.hibernateTemplate = hibernateTemplate; } }
BaseHIbernateDao中注入hibernateTemplate供所有继承该类的dao类使用。这么做同样是为了简化代码,避免在每个Dao类中注入
hibernateTemplate。
7、Domain:
以CityPairDomain为例:
@Entity @Table(name = "CITYPAIR") //对应的数据库表名 @SequenceGenerator(sequenceName = "SEQ_CITYPAIR", name = "s") //定义Sequence public class CityPairDomain { @Id //标注ID,也就是数据库表的主键 @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "s")//规定ID的自生成策略为Sequence生成 private int id; @Column(name = "ARRCITYNAME") //对应的列名,可以不写 private String arriveCity; @Column(name = "ARRCITYCODE") private String arriveCityCode; @Column(name = "DEPCITYNAME") private String depatureCity; @Column(name = "DEPCITYCODE") private String depatureCityCode; public int getId() { return id; } ...set\get方法 }
hibernate可以把上面这个类和数据库中对应的表建立起对应关系。
值得注意的是主键是必须得,没有主键hibernate会报错。
8、DWR
以下是测试DWR页面的截图,部分说明见图
我们需要在页面中调用dwr映射好的方法,我把调用的JS函数卸载名为dwr.js的JS文件中:
function btn_onClick() { //调用dwr.xml中配置的类方法,回调函数callback带有返回的结果集 TestDwrInvoke.getCityPairs(callback); }
如果函数有返回值,可以在JS文件中再谢一个callback函数
然后再页面上就需要多调用一个js文件
<!--dwr必备的两个js文件 --> <script type='text/javascript' src='/TestDWRSpring/dwr/util.js'> </script> <script type='text/javascript' src='/TestDWRSpring/dwr/engine.js'> </script> <!--配置自己的类 --> <script type='text/javascript' src='/TestDWRSpring/dwr/interface/TestDwrInvoke.js'> </script> <!--外部引用JS文件 --> <script type="text/javascript" src="./js/dwr.js"> </script> </head> <body> <form name="myform" method="post"> <input type="button" value="print" onclick="btn_onClick()" /> <div id="info"></div> </form> </body> </html>
到此为止,全文结束,童鞋们可以试着配置一把,有什么问题可以相互探讨探讨,:)