之前我已经讲过让Action类访问到业务逻辑组件有两种策略,一种是Spring容器负责管理控制器Action,并利用依赖注入为控制器注入业务逻辑组件。另一种便是利用Spring的自动装配,Action将会自动从Spring容器中获取所需要的业务逻辑组件。其中之前的文章Spring整合struts2(一)讲述的就是第一种策略,而本文就来讲述第二种策略。
首先,最开始的步骤还是不变,需要将相应的jar包复制到web应用WEB-INF\lib目录下,对于jar包,需要什么就复制什么,过多容器造成冲突,Spring整合struts2需要的jar包如下:
1.struts项目中apps中的struts2-blank解压,将jar包复制到web项目WEB-INF\lib下
2.struts2项目中lib目录下的struts2-spring-plugin-2.3.34.jar
3.spring项目lib目录下的jar包
然后,进行web.xml的配置,配置内容与策略一的一致,并放在WEB-INF下,配置内容如下:
<?xml version="1.0" encoding="GBK"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<!-- 使用ContextLoaderListener初始化Spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 定义Struts 2的FilterDispathcer的Filter -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<!-- FilterDispatcher用来初始化Struts 2并且处理所有的WEB请求。 -->
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
接着就是Action类的编写,以及Action中需要的组件类:
package handle.action;
import com.opensymphony.xwork2.ActionSupport;
import handle.service.*;
public class LoginAction extends ActionSupport
{
// 下面是用于封装用户请求参数的两个成员变量
private String username;
private String password;
// 系统所用的业务逻辑组件
private MyService ms;
// 设值注入业务逻辑组件所必需的setter方法
public void setMs(MyService ms)
{
this.ms = ms;
}
// username的setter和getter方法
public void setUsername(String username)
{
this.username = username;
}
public String getUsername()
{
return this.username;
}
// password的setter和getter方法
public void setPassword(String password)
{
this.password = password;
}
public String getPassword()
{
return this.password;
}
// 处理用户请求的execute方法
public String execute() throws Exception
{
// 调用业务逻辑组件的validLogin()方法
// 验证用户输入的用户名和密码是否正确
if (ms.validLogin(getUsername(), getPassword()) > 0)
{
addActionMessage("哈哈,整合成功!");
return SUCCESS;
}
return ERROR;
}
}
package handle.service;
public interface MyService {
int validLogin(String username , String pass);
}
package handle.service.impl;
import handle.service.MyService;
public class MyServiceImpl implements MyService
{
public int validLogin(String username , String pass)
{
// 此处只是简单示范,故直接判断用户名、密码是否符合要求
if ( username.equals("carson")
&& pass.equals("0408") )
{
return 99;
}
return -1;
}
}
因为本文介绍的是利用Spring的自动装配,所以相当于将业务逻辑组件在Spring容器中配置好之后,
Action将会自动从Spring容器中获取所需要的业务逻辑组件。所以这里先对业务逻辑组件进行配置,这里可以知道,业务逻辑组件是MyService类产生的对象。所以先对其进行配置,配置文件为applicationContext.xml。
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- 定义一个业务逻辑组件,该组件id必须与Action的setter方法名对应,LoginAction类中有MyService组件对应的setter方法setMs,所以id必须为ms -->
<bean id="ms"
class="handle.service.impl.MyServiceImpl"/>
</beans>
由以上配置文件可以看出,spring不再对Action进行管理,而是管理业务逻辑组件,而Action需要什么业务逻辑组件,则会自动获取,这里配置的要求是业务逻辑组件的id必须与Action的setter方法名对应。接下来便是jsp文件的编写:
error.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>错误页面</title>
</head>
<body>
您不能登录!
</body>
</html>
welcome.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>成功页面</title>
</head>
<body>
您已经登录!<br/>
<s:actionmessage />
</body>
</html>
loginForm.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>登录页面</title>
</head>
<body>
<h3>用户登录</h3>
<s:form action="login">
<s:textfield name="username" label="用户名"/>
<s:textfield name="password" label="密码"/>
<tr align="center">
<td colspan="2">
<s:submit value="登录" theme="simple"/>
<s:reset value="重设" theme="simple"/>
</td>
</tr>
</s:form>
</body>
</html>
最后便是对struts.xml的配置,配置控制器,这里的配置与策略一的稍有不同,策略一<action.../>元素中class属性是bean id,那是因为策略一将Action也放入Spring容器进行管理了,而策略二Action类并未放入容器进行管理,所以与一般地struts.xml配置相同,class是指Action类。配置内容如下:
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Struts 2配置文件的DTD信息 -->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<!-- Struts 2配置文件的根元素 -->
<struts>
<!-- 配置了系列常量 -->
<constant name="struts.i18n.encoding" value="GBK"/>
<constant name="struts.devMode" value="true"/>
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
<package name="default" namespace="/" extends="struts-default">
<!-- 定义处理用户请求的Action,该Action的class属性不是实际处理类
, 而是Spring容器中的Bean实例的ID -->
<action name="login" class="handle.action.LoginAction">
<!-- 为两个逻辑视图配置视图页面 -->
<result name="error">/error.jsp</result>
<result>/welcome.jsp</result>
</action>
<!-- 让用户直接访问该应用时列出所有视图页面 -->
<action name="*">
<result>/content/{1}.jsp</result>
</action>
</package>
</struts>
运行项目,得到结果如下:
Spring管理Action能够达到解耦效果,但也有不足:
1.必须将所有Action配置在Spring容器中,而struts.xml还需要配置一个伪Action,从而导致配置文件臃肿冗余。
2.Action的业务逻辑组件接收容器注入,将导致代码可读性降低。
使用自动装配可以简化配置文件,但也有不足:
1.Action与业务逻辑组件的耦合降低到代码层次,必须在配置文件中配置与Action所需控制器同名的业务逻辑组件,不利于高层次解耦。
2.Action接收Spring容器的自动装配,代码可读性较差。