【Struts 2开发模式基础和简单示例程序】

Struts 2开发模式基础和简单示例程序

一、Model 2模式的缺陷

之前的文章中已经介绍了Model 2开发模式(JSP+Servlet+JavaBean+JDBC)的优越性,它通过分离系统各部分模块的功能职责,成功地克服了Model 1的缺点,但是这种开发方式仍然存在弊端,原因在于:它是以重新引入原始Servlet编程为代价的,程序员在编写程序时必须继承HttpServlet、覆盖doGet()和doPost()方法,严格遵守Servlet代码的编写规范。

二、Servlet Filter技术

Servlet过滤器是在Java Servlet规范中定义的,它能够对过滤器关联的URL请求和响应进行检查和修改。过滤器能够在Servlet被调用之前检查Request对象,修改Request Header和Request内容;在Servlet被调用之后检查Response对象,修改Response Header和Response内容。过滤器过滤的URL资源可以是Servlet、JSP、HTML文件,或者是整个路径下的任何资源。多个过滤器可以构成一个过滤器链,当请求过滤器关联的URL时,过滤器链上的过滤器会挨个发生作用。
如图所示为过滤器处理请求的过程,图中显示了正常请求、加过滤器请求和加过滤器链请求的处理过程。过滤器可以对Request对象和Response对象进行处理。
在这里插入图片描述

1、所有的过滤器类都必须实现java.Servlet.Filter接口,它含有3个过滤器类必须实现的方法。

① init(FilterConfig)。
这是过滤器的初始化方法,Servlet容器创建过滤器实例后将调用这个方法。在这个方法中可以通过FilterConfig参数读取web.xml文件中过滤器的初始化参数。
② doFilter(ServletRequest,ServletResponse,FilterChain)。
这个方法完成实际的过滤操作,当用户请求与过滤器关联的URL时,Servlet容器将先调用过滤器的doFilter方法,在返回响应之前也会调用此方法。FilterChain参数用于访问过滤器链上的下一个过滤器。
③ destroy()。 Servlet容器在销毁过滤器实例前调用该方法,这个方法可以释放过滤器占用的资源。
过滤器编写完成后,要在web.xml进行配置,格式如下:

<filter>
    <filter-name>过滤器名称</filter-name>
    <filter-class>过滤器对应的类</filter-class>
    <!--初始化参数-->
    <init-param>
        <param-name>参数名称</param-name>
        <param-value>参数值</param-value>
    </init-param>
</filter>

2、在web.xml中配置过滤器与URL关联的方法

① 与一个URL资源关联。

<filter-mapping>
    <filter-name>过滤器名</filter>
    <url-pattern>xxx.jsp</url.pattern>
</filter-mapping>

② 与一个URL目录下的所有资源关联。

<filter-mapping>
    <filter-name>过滤器名</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

③ 与一个Servlet关联。

<filter-mapping>
    <filter-name>过滤器名</filter-name>
    <Servlet-name>Servlet名称</Servlet-name>
</filter-mapping>

3、过滤器主要功能

① 权限控制。通过过滤器实现访问的控制,当用户访问某个链接或者某个目录时,可利用过滤器判断用户是否有访问权限。
② 字符集处理。可以在过滤器中处理request和response的字符集,而不用在每个Servlet或者JSP中单独处理。
③ 其他一些场合。过滤器非常有用,可以利用它完成很多适合的工作,如计数器、数据加密、访问触发器、日志、用户使用分析等。

三、Struts 2内部机制

Struts 2的设计思想:用Servlet Filter技术将Servlet API隐藏于框架之内,一个请求在Struts 2框架内被处理,大致分为以下几个步骤
在这里插入图片描述

1、工作原理如下:

① 客户端初始化一个指向Servlet容器(如Tomcat)的请求。
② 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个为ActionContextCleanUp,它对于Struts 2和其他框架的集成很有帮助,如SiteMesh Plugin)。
③ 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用某个Action。
④ 如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy。
⑤ ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类。
⑥ ActionProxy创建一个ActionInvocation的实例。
⑦ ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及相关拦截器(Interceptor)的调用。
⑧ 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的JSP或FreeMarker的模板。在表示的过程中可以使用Struts 2 框架中继承的标签,在这个过程中还要涉及ActionMapper。

2、Struts 2框架工作流程

在这里插入图片描述

Struts 2的基本流程如下。
① Web浏览器请求一个资源。
② 过滤器Dispatcher查找请求,确定适当的Action。
③拦截器自动对请求应用通用功能,如验证和文件上传等操作。
④Action的execute()方法通常用来存储和(或)重新获得信息(通过数据库)。
⑤结果被返回到浏览器。可能是HTML、图片、PDF或其他。

四、Struts2示例程序(采用JSP+Struts 2+JavaBean+JDBC方式开发一个Web登录程序。)

1、创建一个Java EE项目jsp_struts2_javabean_jdbc,下载Struts2的jar包

http://struts.apache.org/,下载Struts2最小核心依赖库(大小仅为4.44 MB),单击页面中“Essential Dependencies Only”,本例使用Struts2.5.18,可通过资源下载。
在其目录struts-2.5.18-min-lib\struts-2.5.18\lib下看到有8个jar包,包括以下内容。
1)Struts 2的4个基本类库
struts2-core-2.5.18.jar
ognl-3.1.15.jar
log4j-api-2.10.0.jar
freemarker-2.3.26-incubating.jar
2)附加的4个库
commons-io-2.5.jar
commons-lang3-3.6.jar
javassist-3.20.0-GA.jar
commons-fileupload-1.3.3.jar
以上Struts 2包连同数据库驱动jar包一共是9个jar包,
将它们一起复制到项目的\WebRoot\WEB-INF\lib路径下。

2、配置Struts2项目的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" 
	xmlns="http://java.sun.com/xml/ns/j2ee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <filter>
        <filter-name>struts-prepare</filter-name>
        <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareFilter</filter-class>
    </filter>
    <filter>
        <filter-name>struts-execute</filter-name>
        <filter-class>org.apache.struts2.dispatcher.filter.StrutsExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts-prepare</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>struts-execute</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <display-name>jsp_struts2_javabean_jdbc</display-name>
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>
</web-app>

3、在src下构造JavaBean、创建JDBC

JavaBean代码如下:

package org.easybooks.test.model.vo;

public class UserTable {
	//Fields
	private Integer id;
	private String username;
	private String password;
	
	//Property accessors
	//属性 id 的 get/set 方法
	public Integer getId(){
		return this.id;
	}
	public void setId(Integer id){
		this.id=id;
	}
	//属性 username 的 get/set 方法
	public String getUsername(){
		return this.username;
	}
	public void setUsername(String username){
		this.username=username;
	}
	//属性 password 的 get/set 方法
	public String getPassword(){
		return this.password;
	}
	public void setPassword(String password){
		this.password=password;
	}

}

JDBC代码如下;

package org.easybooks.test.jdbc;
import java.sql.*;
public class SqlSrvDBConn {
	private Statement stmt;
    private Connection conn;
    ResultSet rs;
   
    public SqlSrvDBConn(){
    	stmt=null;
    	try{
//加载SQL server数据库驱动与下面连接mysql二选一
    		Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    		conn=DriverManager.getConnection("jdbc:sqlserver://localhost:1433;databaseName=TEST","sa","123456");
    	//加载MySQL数据库驱动
    		Class.forName("com.mysql.jdbc.Driver");
    		conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/TEST","root","123456");	
    	}catch(Exception e){
    		e.printStackTrace();
    	}
    	rs=null;
    }
    
    public ResultSet executeQuery(String sql)
    {
        try
        {
        	stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
        	rs=stmt.executeQuery(sql);
        }catch(SQLException e){
        	System.err.println("Data.executeQuery: " + e.getMessage());
        }
        return rs;
    }
   
    public void closeStmt()
    {
        try
        {
            stmt.close();
        }catch(SQLException e){
        	System.err.println("Data.executeQuery: " + e.getMessage());
        }
    }
    public void closeConn()
    {
        try
        {
            conn.close();
        }catch(SQLException e){
        	System.err.println("Data.executeQuery: " + e.getMessage());
        }
    }
}

4、编写jsp代码

login.jsp

<%@ page language="java" pageEncoding="gb2312"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
	<title>简易留言板</title>
</head>
<body bgcolor="#E3E3E3">
<s:form action="main" method="post" theme="simple">
<table>
	<caption>用户登录</caption>
	<tr>
		<td>
			用户名:<s:textfield name="user.username" size="20"/>
		</td>
	</tr>
	<tr>
		<td>&nbsp;&nbsp;码:<s:password name="user.password" size="21"/>
		</td>
	</tr>
	<tr>
		<td>
			<s:submit value="登录"/>
			<s:reset value="重置"/>
		</td>
	</tr>
</table>
</s:form>
如果没注册单击<a href="">这里</a>注册!
</body>
</html>

main.jsp

<%@ page language="java" pageEncoding="gb2312"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
	<title>留言板信息</title>
</head>
<body>
	<s:set var="user" value="#session['user']"/>
	<s:property value="#user.username"/>,您好!欢迎登录留言板。
</body>
</html>

error.jsp

<%@ page language="java" pageEncoding="gb2312"%>
<html>
<head>
	<title>出错</title>
</head>
<body>
	登录失败!单击<a href="login.jsp">这里</a>返回
</body>
</html>

5、实现控制器Action

基于Struts 2框架的Java EE应用程序使用自定义的Action(控制器)来处理深层业务逻辑。本例定义名为“main”的控制器。
MainAction.java

package org.easybooks.test.action;
import java.sql.*;
import java.util.*;
import org.easybooks.test.model.vo.*;
import org.easybooks.test.jdbc.SqlSrvDBConn;
import com.opensymphony.xwork2.*;
public class MainAction extends ActionSupport{
	private UserTable user;
	//处理用户请求的 execute 方法
	public String execute() throws Exception{
		String usr=user.getUsername();			//获取提交的用户名
		String pwd=user.getPassword();			//获取提交的密码
		boolean validated=false;				//验证成功标识
		SqlSrvDBConn sqlsrvdb=new SqlSrvDBConn();
		ActionContext context=ActionContext.getContext();
		Map session=context.getSession();		//获得会话对象,用来保存当前登录用户的信息 
		UserTable user1=null;
		//先获得 UserTable 对象,如果是第一次访问该页,用户对象肯定为空,但如果是第二次甚至是第三次,就直接登录主页而无须再次重复验证该用户的信息
		user1=(UserTable)session.get("user");
		//如果用户是第一次进入,会话中尚未存储 user1 持久化对象,故为 null
		if(user1==null){
			//查询 userTable 表中的记录
    		String sql="select * from userTable";
    		ResultSet rs=sqlsrvdb.executeQuery(sql);		//取得结果集
    		try {
				while(rs.next())
				{
					if((rs.getString("username").trim().compareTo(usr)==0)&&(rs.getString("password").compareTo(pwd)==0)){
						user1=new UserTable();				//创建持久化的 JavaBean 对象 user1
						user1.setId(rs.getInt(1));
						user1.setUsername(rs.getString(2));
						user1.setPassword(rs.getString(3));
						session.put("user", user1);			//把 user1 对象存储在会话中
						validated=true;						//标识为 true 表示验证成功通过
					}
				}
	    		rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
    		sqlsrvdb.closeStmt();
    		sqlsrvdb.closeConn();
		}
        else{
        	validated=true;									//该用户在之前已登录过并成功验证,故标识为 true 表示无须再验了
        }
        if(validated)
        {
        	//验证成功返回字符串"success"
        	return "success";
        }
        else{
            //验证失败返回字符串"error"
        	return "error";
        }
		
	}
	public UserTable getUser(){
		return user;
	}
	public void setUser(UserTable user){
		this.user=user;
	}
}

6、配置Action

在编写好Action(控制器)的代码之后,还需要进行配置才能让Struts 2识别这个Action。在src下创建文件struts.xml(注意文件位置和大小写),输入如下的配置代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
	"http://struts.apache.org/dtds/struts-2.5.dtd">
<!-- START SNIPPET: xworkSample -->
<struts>
	<package name="default" extends="struts-default">
		<!-- 用户登录 -->
		<action name="main" class="org.easybooks.test.action.MainAction">
			<result name="success">main.jsp</result>
			<result name="error">error.jsp</result>
		</action>
	</package>
	<constant name="struts.i18n.encoding" value="gb2312"/>
</struts>
<!-- END SNIPPET: xworkSample -->

7、配置Tomcat服务器后即可成功运行

五、Struts 2在其中所起的作用

可以发现,我们用Action模块(MainAction)取代了原来的Servlet类(MainServlet),这样做的好处在于:屏蔽了Servlet原始的API,简化了代码结构,而改用Struts 2核心来自动地控制JSP页面跳转,系统的结构所示。
相比较以加深理解,可以很清楚地看出:这里用Struts 2取代了原Servlet的位置,而且业务逻辑处理的功能由用户自定义编写Action去实现,与Struts 2的控制核心相分离,这就进一步降低了系统中各部分组件的耦合度。
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fpl1116

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值