Spring与Struts2集成

    技术2024-10-28  59

    完整版见https://jadyer.github.io/

    这里需要用到struts2-spring-plugin-2.0.11.jar文件

    首先是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"> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 启动Web服务器时,便加载Spring容器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <welcome-file-list> <welcome-file>loginSpring.jsp</welcome-file> </welcome-file-list> </web-app>

    然后是同样位于WEB-INF目录下的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"> <!-- 理论上来说,这里<bean/>的id值可以随意命名 --> <!-- 但是下面的那个对应具体的Action类的id值【即Struts2SpringPlugin】就必须与struts.xml中的class值相同 --> <bean id="loginSpringService" class="com.jadyer.service.impl.LoginServiceImpl"/> <!-- 将scope设为prototype就是指:每过来一个请求,都会生成当前类的一个实例 --> <!-- 这里<property name=""/>中的name值应该与com.jadyer.action.LoginSpringAction类中的loginService成员变量的名字相同 --> <!-- 这里其中<property name=""/>中的ref的值对应的就是上面配置的<bean/>的id值 --> <bean id="Struts2SpringPlugin" class="com.jadyer.action.LoginSpringAction" scope="prototype"> <property name="loginService" ref="loginSpringService" /> </bean> </beans> <!-- ***********【<bean>中的singleton与设计模式中的Singleton】**************************** --> <!-- 不过Spring中的<bean scope="singleton">与设计模式中的Singleton有些不同 --> <!-- 设计模式中的Singleton只是针对一个JVM而言,它只会生成类的唯一的一个实例 --> <!-- 而Spring中的singleton只是针对一个IoC容器,它只会生成类的唯一的一个实例 --> <!-- 如果应用启动时有两个IoC容器,那么在整个JVM运行中,该类就会生成两个实例 --> <!-- *************【关于Strust2的校验框架以及scope="prototype"】************************** --> <!-- 将Struts2和Spring整合时,若前台表单应用了Struts2的校验框架 --> <!-- 当第一个输入错误的内容时,校验框架生效,表单中就会提示校验信息 --> <!-- 然后再接着输入正确的内容,我们会离奇的发现,提交表单时没有反应 --> <!-- 这时因为IoC容器默认使用唯一的一个Ation实例来处理用户所有请求 --> <!-- 当第一次校验框架提示错误信息时,那么该实例中已经包含了错误消息 --> <!-- 紧接着第二次表单请求时,它就发现在该Action实例中还存在错误消息 --> <!-- 我们可以在Action中验证一下,示例代码如下所示: --> <!-- @Override public void validate() { Map map = this.getFieldErrors(); Set set = map.keySet(); for (Iterator iter = set.iterator(); iter.hasNext();) { System.out.println(map.get(iter.next())); } } --> <!-- 然后我们在前台表单中第一次输入错误的内容,然后第二次也输入错误的内容 --> <!-- 这时我们会发现前台中出现了两条相同的错误提示消息,然后对比控制台输出 --> <!-- 究其原因是Struts2和Struts1不同,它的Action是有状态的,即成员变量 --> <!-- 所以Struts2的Action交给Spring管理时,应定义scope="prototype" --> <!-- 这就表示每次使用Ation时,它都会为我们new一个Action实例出来 --> <!-- ********************************************************************************* -->

    然后是位于classpath下的struts.xml文件

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="struts2" extends="struts-default"> <action name="springplugin" class="Struts2SpringPlugin"> <result>/loginSpringResult.jsp</result> <result name="input">/loginSpring.jsp</result> </action> </package> </struts> <!-- *****************【Struts2与Spring整合的关键点】************************************************************* --> <!-- Spring的IOC容器可以看作是一个大的工厂,它里面维护了很多很多的<bean/> --> <!-- 当我们需要某个<bean>的时候,Spring的IOC工厂就会直接把我们需要的东西给我们 --> <!-- 这个IOC工厂里面可以维护的是一般的JavaBean、业务类、DAO类等等 --> <!-- 也就是说凡是我们能想到的,或者程序中用到的Java类等等,都可以由IOC容器来管理 --> <!-- Struts1.X和Struts2.X都是通过Plugin插件的方式,但二者相对于Spring的配置方式还是不太一样的 --> <!-- *****************【浅析Spring插件中的struts-plugin.xml文件】**************************************************** --> <!-- 查看struts2-spring-plugin-2.0.11.jar里面的struts-plugin.xml文件发现里面定义了一个<bean/> --> <!-- <bean/>的类型是com.opensymphony.xwork2.ObjectFactory --> <!-- <bean/>的名字是spring --> <!-- <bean/>对应的类org.apache.struts2.spring.StrutsSpringObjectFactory --> <!-- 也就是说,该插件真正运行的就是struts2-spring-plugin-2.0.11.jar中的StrutsSpringObjectFactory类 --> <!-- 接下来它又配置了一个常量,常量的名字是struts.objectFactory,常量的值是spring --> <!-- 实际上这个常量的名字就是在引用StrutsSpringObjectFactory类 --> <!-- 换句话说struts.objectFactory属性对应StrutsSpringObjectFactory类,然后再查看Struts2中该属性的说明 --> <!-- 将Struts2的org.apache.struts2.default.properties全局属性文件的第38行的说明文字翻译过来就是 --> <!-- 翻译:如果被指定的话,那么默认的对象工厂就可以被覆盖掉了 --> <!-- 说明:当接收到一个请求的时候,Struts2框架本身的ObjectFactory就会为我们生成一个Action实例 --> <!-- 当我们整合Spring之后,就可以由Spring帮助我们生成Action实例,然后自动注入Action实例里面的属性 --> <!-- 在Spring插件中定义好com.opensymphony.xwork2.ObjectFactory的<bean>并配置struts.objectFactory属性后 --> <!-- 那么生成Action实例的工作就可以由Struts2本身转交给Spring来完成了 --> <!-- 补充:Struts2本身是由WebWork发展起来的,实际上WebWork本身就提供了一个IOC容器,但是Struts2抛弃了这个容器 --> <!-- 因为它觉得Spring的实现已经非常非常好了,它就没有必要再去【重新发明轮子】,就没必要再去重新做这件事情了 --> <!-- 因此它就直接引用了Spring的IOC容器,于是它就为我们提供了Spring插件的集成方式 --> <!-- 另外:在struts-plugin.xml中还配置了spring-default包,里面定义了两个拦截器。我们还用不到它们,暂时无需理会 --> <!-- 我们只要知道:配置好Spring插件后,对象的工厂便由Struts2转化到了Spring,变成由Spring来完成这个工作 --> <!-- *****************【<action/>中的class值一定要与<bean/>中的id值相同】********************************************* --> <!-- 服务器启动时,Struts2会根据这里的class值到applicationContext.xml中通过id值匹配<bean/> --> <!-- 也就是说拿Struts2SpringPlugin到Spring配置文件中寻找id为Struts2SpringPlugin的<bean/> --> <!-- 然后才会由Spring自动实例化名为Struts2SpringPlugin的<bean/>中的class对应的Action --> <!-- 也就说,这里的class的值一定一定要与Spring配置文件中的<bean/>的id值一致 --> <!-- 这样子,Spring才会自动进行映射,自动进行装配 --> <!-- ************************************************************************************************************ -->

    用于输入用户名和密码的loginSpring.jsp页面

    <%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <h2>Struts2整合Spring</h2> <h3><font color="red">提示:</font>程序设定的用户名和密码各为<font color="blue"><strong>admin</strong></font>和<font color="blue"><strong>jadyer</strong></font></h3> <h3><font color="red">注意:</font>用户名或密码不正确时将停留在该页面不动</h3> <s:form action="springplugin" theme="simple"> 姓名:<s:textfield name="username"/><br/> 密码:<s:password name="password"/><br/> <s:submit value="整合测试"/> </s:form>

    当用户名和密码正确时登录成功的loginSpringResult.jsp页面

    <%@ page pageEncoding="UTF-8"%> <h2>Login Success</h2>

    用到的service层的接口和实现类

    package com.jadyer.service; /** * Spring推荐面向接口编程 */ public interface LoginService { /** * 判断是否登录成功 */ public boolean isLogin(String username, String password); } package com.jadyer.service.impl; import com.jadyer.service.LoginService; public class LoginServiceImpl implements LoginService { public boolean isLogin(String username, String password) { if ("admin".equals(username) && "jadyer".equals(password)) { return true; }else{ return false; } } }

    最后是用到的Action类

    package com.jadyer.action; import com.jadyer.service.LoginService; import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings("serial") public class LoginSpringAction extends ActionSupport { private String username; private String password; /* 关于username和password对应的setter和getter略 */ private LoginService loginService; //loginService成员变量并不是由我们自己主动进行set的,是由Spring的IOC容器帮助我们完成的 //因此只要为它提供一个setXxx()方法就可以了,而不需要提供getXxx()方法 public void setLoginService(LoginService loginService) { this.loginService = loginService; } @Override public String execute() throws Exception { if(loginService.isLogin(username, password)){ return SUCCESS; }else{ return INPUT; } } }

    最新回复(0)