J2EE学习篇之--Struts1详解

今天来看一下Struts1的相关知识,其实Struts现在是出名的,每个Web开发者都会知道的,也是现在比较流行的框架,下面就来看一下我们为什么要用Struts框架呢?


摘要

1.建立在mvc这种好的模式上的,Struts在m,v,c上都有涉及,但主要的是提供一个好的控制器和一套定制的标签库上也就是说它在这里体现在c和v上,有mvc的一系列的优点,如:结构层次分明,高重用性,增加了程序的健壮性和可伸缩性,便于开发与设计分工,提供集中统一的权限的控制,校验,国际化,日志等等
2.开源项目,得到了包括它的发明者Craig R.McClanahan在内的一些程序大师和高手持续而细心的呵护,并且经受了实战的检验,使其功能越来越强大。
3.其他技术和框架具有很好的融合性,如与Spring,hibernate等框架的整合
4.大大提高了开发速度


框架的概念和struts的概念和体系结构

1.Framework概念

人们用于解决相同或者相似类型问题的方案。
特点:可重用性,可扩展性,可收缩性。基于请求响应(Request-response)模式的应用Framework的逻辑结构
控制器(Controller)
业务逻辑层(Business Logic)
数据逻辑层(Data Logic)


2.Struts的概念和体系结构

struts是Apache组织的一个开源的项目,主要是采用Servlet和Jsp技术来实现的,Struts是一个基于Sun JavaEE 平台大的MVC框架,它采用了MVC模式,将MVC模式“分离显示逻辑和业务逻辑”的能力发挥的淋漓尽致

Struts工作原理结构

WebBroser——>UserAction———>Front end Controller ActionServlet——>Back End Controller Action——>Model JavaBean



搭建配置环境

1.新建web工程


2.加入必要的jar包


当然还可能需要其他的jar,这个在实际应用用遇到问题或者报错,我们可以添加相应的jar,而没必要刻意的去记住哪些jar


3.在WEB-INF下加入配置文件struts-config.xml

主要在这里我们需要配置我们定义的ActionForm,和Action

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
          "http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
    <form-beans>
    </form-beans>
    <action-mappings>  
    <action path=""></action>     
    </action-mappings>
</struts-config>

4.配置web.xml

配置Struts中的总控制器ActionServlet,把配置文件作为一个实例化参数的值传进来的(这里可以传递多个配置文件的,中间使用逗号进行分割的,具体可以查看源码ActionServlet),而且我们还看到这个servlet的启动优先级是0,也就是最高的优先级,这个只是我们在之前JavaWeb学习篇中的Servlet中说过,还有就是要配置访问的映射url,这里是只要后缀名是.do的就可以

<?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">
	<display-name></display-name>
	<servlet>
		<servlet-name>action</servlet-name>
		<servlet-class>
			org.apache.struts.action.ActionServlet
		</servlet-class>
		<init-param>
			<param-name>config</param-name>
			<param-value>/WEB-INF/struts-config.xml</param-value>
		</init-param>
		<load-on-startup>0</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>action</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>


开发第一个struts程序

1.开发form

1)建立一个类,继承ActionForm
2)注册,修改struts-config.xml
Name:变量名
Type:类的全名
例如:

<form-beans>
	<form-bean name="loginForm" type="cn.com.hewei.bean.LoginForm"/>
</form-beans>


2.开发Action

1) 建立一个类,继承Action覆盖execute方法

2) 注册,修改strutrs-config.xml

Path:指明调用者(jsp)能通过中心控制器ActionServlt找到该Action

Type:指明该Action的类名

Name:该Action应用的Form名称


3.实例:模拟用户的登录,第一个用户程序

1)写bean程序,继承ActionForm
package cn.com.hewei.Bean;
import org.apache.struts.action.ActionForm;
public class LoginForm extends ActionForm {
	private String userName;
	private String password;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
}

编写Action程序

package cn.com.hewei.Action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import cn.com.hewei.Bean.LoginForm;

public class LoginAction extends Action {
	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		// 转换成LoginForm
		LoginForm login = (LoginForm) form;
		if (login.getUserName().equals("admin")) {
			return mapping.findForward("loginSuccess");
		} else {
			return mapping.findForward("loginFail");
		}
	}
}

配置struts-config.xml文件

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
       	  "http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
	<form-beans>
		<form-bean name="loginForm"
			type="cn.com.hewei.Bean.LoginForm">
		</form-bean>
	</form-beans>
	<action-mappings>
		<action path="/Login" type="cn.com.hewei.Action.LoginAction"
			name="loginForm">
			<forward name="loginSuccess" path="/loginSuccess.jsp"></forward>
			<forward name="loginFail" path="/loginFail.jsp"></forward>
		</action>
	</action-mappings>
</struts-config>
我们要注意一点所有的path=都要以“/”开头


Login.jsp

<body>
	<form action="<%=request.getContextPath()%>/Login.do" method="post">
		<!--这里的uerName和passWord要和bean中的一模一样-->
  username:
		<input type="text" name="userName">用户名</input>
  password:
  		<input type="text" name="passWord">密码</input></br>
		<input type="submit" value="提交">
   	<form>
</body>

登录成功页面loginSuccess.jsp

<body>
   Login Success <br>
</body>

登录失败页面loginFail.jsp
<body>
   Login Fail <br>
</body>

原理分析:


1)在浏览器的地址栏中输入index.jsp
2)输入用户名密码后点击提交,跳转到Login.do、
3)因为是.do结尾的所以会被web.xml的ActionServlet解析到,ActionServlet会查看struts-config.xml文件,根据action标签的path和跳       转到LoginAction这个Servlet目录
4)跳转时,会根据action的name属性带着ActionForm中的内容交给LoginAction处理
5)LoginAction处理好后根据findForward将跳转的关键字带给ActionServlet处理,ActionServlet会查看Struts-config.xml文件根据forward标签,和name属性(那么属性判断带来的关键字)跳转到path指定的路径


Struts的基本原理


1.读取配置(初始化ModuleConfig对象)
Struts框架总控制器(ActionServlet)是一个Servelt,在web.xml中配置成自动启动的Servlet,在Web.xml中配置成自动启动的Servlet。读取配置文件(Struts-config.xml)的配置文件信息,为不同的Struts模块初始化响应的ModuleCofig对象:ActionConfig,ControlConfig,FormBeanConfig,ForwardConfig,MessageResourcesConfig(一定要记得看源码)
2.发送请求
用户提交表单或调用URL向web应用的程序器提交一个请求,请求的数据用HTTP协议上传给Web服务器
3.填充Form(实例化,复位,填充数据,校验,保存)
(*.do请求)从ActionConfig中找到对应该请求的Action的子类,如没有对应的Action,控制器直接转化给Jsp或静态的页面。如有对应的Action且这个Action有一个对应的ActionForm,ActionForm被实例化并用HTTP请求的数据填充其属性,并且保存在ServletConfig中(request或session中),这样他们就可以被其他的Action对象或者Jsp调用了。这个后面会说到如何保存这个form到各个域中
4.派发请求
控制器根据配置信息ActionConfig将请求派发到具体的Action,相应的FormBean一并传给这个Action的execute()方法
5.处理业务
Action一般只包含一个execute()方法,它负责执行相应的业务逻辑(调用其他业务模块)。完毕返回一个ActionFoward对象,控制器通过这个AcationForward对象进行转发工作。
6.返回响应
Action根据业务逻辑处理的不同结果返回一个目标响应对象总控制器,该目标响应对象给总控制器,该目标响应对象对应一个具体的Jsp页面或另一Action
7.查找响应(翻译响应)
总控制器根据业务功能Action返回的目标响应对象,找到对应的资源对象,通常是一个具体的jsp页面.
8.响应客户
目标响应对象结果展现给用户目标响应对象(JSP)将结果页面展现给用户。


Struts的原理详细分析

1.Struts组件

ActionServlet 

Acation Classes,

Action Mapping(此包括ActionForward)

ActionForm Bean。

2.Struts的Mvc

1.模型(Model):本质上来说在Struts中Model是一个商业逻辑类,开发者实现商业逻辑
2.视图(View):View是与控制器Servelt配合工作的一整套Jsp定制标签构成,利用他们可以快速建立应用系统的界面
3.控制器(Controller):前端控制器(总控制器)是一个Servlet,它将客户端的请求转发到响应的后端控制器Action类


3.ActionServlet(中心控制器)

定义:继承自javax.servelt.http.HttpServlet类,是中心控制器(总控制器)。它提供了一个中心位置来处理全部的终端请求
1)作用:接受请求,填充数据,派发请求,响应用户
2)配置:在web配置文件(web.xml)声明:

<servlet>
	<servlet-class>
		org.apache.struts.action.ActionServlet
	</servlet-class>
	<init-param>
		<param-name>config</param-name>
		<param-value>/WEB-INF/struts-config.xml</param-value>
	</init-param>
	<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>action</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>


Action图解


1.Action:一个请求和业务逻辑的适配器

1)初始化时间:第一次请求的时候初始化,不是在读取配置时初始化,
2)初始化次数:每个Action只被初始化一次(多个请求共享一个Action)
3)安全问题:Action是线程不安全的,因为所有的请求共享一个action实例
4)怎样实现Action的安全性问题:
主要不要用实例变量或者类变量共享只是针对某个请求的数据
注意资源操作的同步性


实例:设计一个实例变量count,统计访问的次数 

package cn.com.hewei.Action;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class CountAction extends Action{
	int count=0;
	@Override
	//每个访问一个execute方法
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		response.setCharacterEncoding("gbk");
		request.setCharacterEncoding("gbk");
		synchronized (this) {
			count++;		
		}
		PrintWriter out=response.getWriter();
		out.print("访问的次数"+count);
		return null;
	}
}

配置文件
<action path="/countAction" type="cn.com.hewei.Action.CountAction"/>

访问连接
http://localhost:8081/Mystruts/countAction.do


2.ActionMapping和ActionForward

1).每个<action>元素都是类org.apache.struts.action.AcationMapping
2).ActionMapping中的方法(使用ActtionStudent实例)

public ActionForward execute(ActionMapping mapping, ActionForm form,
		HttpServletRequest request, HttpServletResponse response)
		throws Exception {
			// 获得Action的name
			String name=mapping.getName();
			// 获得Action的type
			String type=mapping.getType();
			// 获得Action的path
			String path=mapping.getPath();
			String []forwardNames=mapping.findForwards();
			System.out.println("name  "+name);
			System.out.println("path  "+path);
			System.out.println("type  "+type);
			for(String forwardName:forwardNames ){
				ActionForward forward=mapping.findForward(forwardName);
				String forwardPath=forward.getPath();
				System.out.println("forwardName  "+forwardName);
				System.out.println("forwardPath  "+forwardPath);
			}
		}

配置文件
<action path="/addStudent" type="cn.com.hewei.Action.AddStudentAction"
		name="AddStudentForm">
	<forward name="addSuccess" path="/loginSuccess.jsp"></forward>
	<forward name="addFail" path="/loginFail.jsp"></forward>
</action>

输出:
name  AddStudentForm
path  /addStudent
type  cn.com.hewei.Action.AddStudentAction
forwardName  addSuccess
forwardPath  /loginSuccess.jsp
forwardName  addFail
forwardPath  /loginFail.jsp


3. ActionForward(导航器)

ActionForWard对象是配置对象,这些配置对象拥有独一无二的标识允许按照name属性等检索,ActionForward对象封装了向前进的Url路径且被请求处理器用于识别目标视图
name:逻辑名称
path:页面或者模块的访问路径

redirect:控制转发还是重定向

<forward name="addFail" path="/loginFail.jsp" redirect="true"/>

redirect=false 转发(默认值)
redirect=false:RequestDispatch.forward
redirect=true  重定向
redirect=true:HttpServletResponse.sendRedirects


4.ActionForm

ActionForm工作原理
处理anctionForm的一般步骤
1)检查Action的映射,确定Action中已经配置了对ActionForm的映射
2)根据name属性,查找formbean的配置信息
3)检查Action的formbean的使用范围确定在此范围下(request,session),是否已经有此formbean的实例<action scope=”request”>,默认是session
4)假如当前范围下,已经存在了此form bean的实例,而且对于当请求来说,是同一种类型的话,那么就重用
5)否则,就重新构建一个formbean的实例(调用构造方法),并且保存在一定的作用范围
6)form bean的reset()方法被调用
7)调用对应的setter方法,对状态属性赋值
(类似<jsp:setProperty name=”person” property=”*” >)
8)如果validate的属性设置为true,那么就调用form bean的validate()方法
<action validate=”true”>
9)如果validate()方法没有返回任何的错误,控制器将ActionForm作为参数,传给Action实例的execute()方法并执行
注意:直接从ActionForm类继承的reset()和validate()方法,并不能实现什么处理功能,所以有必要自己重新覆盖

图例:


注意:
1.无参构造函数必须要有(通过读取配置文件中的信息进行实例化)
2.Scope缺省值为session
我们怎么查看是否往scope中添加了元素了呢?我们可以使用监听器来做(这个我们在前面说到Servlet中的监听器和过滤器)
1)监听HttpSessionAttributeListener,
ServletRequestAttributeListener接口

package cn.com.hewei.listener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import org.apache.struts.action.ActionForm;
public class ActionListener implements HttpSessionAttributeListener,ServletRequestAttributeListener {
	public void attributeAdded(HttpSessionBindingEvent event) {		//得到session中的name
		String attributeName=event.getName();
		//得到session中的value,判断是否是struts的类
		if(event.getValue() instanceof ActionForm){   
			System.out.println("Add a Session Attribute");
			System.out.println("name="+attributeName+",value="+event.getValue());
		}
	}
	public void attributeReplaced(HttpSessionBindingEvent event) {
		String attributeName=event.getName();
		if(event.getValue() instanceof ActionForm){   
			System.out.println("Replace a Session Attribute");
			System.out.println("name="+attributeName+",value="+event.getValue());
		}
	}
	public void attributeAdded(ServletRequestAttributeEvent event) {
		String attributeName=event.getName();
		if(event.getValue() instanceof ActionForm){	
			System.out.println("Add a Request Attribute");
			System.out.println("name="+attributeName+",value="+event.getValue());
		}
	}
	public void attributeReplaced(ServletRequestAttributeEvent event) {
		String attributeName=event.getName();
		if(event.getValue() instanceof ActionForm){   
			System.out.println("Replace a Request Attribute");
			System.out.println("name="+attributeName+",value="+event.getValue());
		}
	}
}

2)注册监听器

<listener>
	<listener-class>
		cn.com.hewei.listener.ActionListener
	</listener-class>
</listener>


在Action中加入Scope=request,输出
Add a Session Attribute
name=AddStudentForm,value=cn.com.hewei.Bean.AddStudentForm@3bce70


3.reset方法,是让表当中的数据恢复默认值
4.调用setter方法,实际上是调用对应的标准set方法,比如username有setUsername()
5.<action validate=“false”>关闭校验,默认自动校验

6.配置文件中的属性
1)<action-mappings>元素
<action-mappings>元素帮助进行扩建内部的流程控制,可将请求的URL映射到Action类,将Action对象与ActionForm对象想相互联,<action-mappings>元素内可以定义多个<action>子元素

2)<action>元素
所描述的是将特定的请求路径和一个相应的Action类之间的映射关系,有以下的属性
attribute:设置和Action关联的formbean在request/session内的属性key,通过request/session的getAttribute(attribute)方法返回该formbean实例(用来存取form的关键字,缺省值和formbean标签中的name一样的)
validate:用来控制是否校验表单,(校验表单时,当返回null或者ActionErrors没有带ActionMessage信息时,校验成功)
input:当表单验证失败时请求转发的URL,一般结合validate=“true“使用

public ActionErrors validate(ActionMapping mapping,
		HttpServletRequest request) {
		ActionErrors errors=new ActionErrors();
		ActionMessage m=new ActionMessage("ss");
		errors.add("error",m);
		return errors;
}

我们在jsp中可以通过<bean:errors property=”error”>获得错误信息


3)<global-forwards>全局跳转
<global-forwards>元素用于定义在整个应用程序内的全局转发,在该元素内可定义多个<forward>子元素
<global-forwards>
	<forward name=”error” path=”/error.jsp”>
</global-fowards>


自己开发Struts思路

1.ActionServlet

读取配置dom4j
填充form
派发请求:调用对应的Action的execute方法。

查找响应


2.ActionForm

set()/get()

reset()

validate()


3.Action

Execute(ActionMapping,ActionForm,HttpServletRequest,HttpServletResponse)


4.ActionMapping

属性:path,type,name,validate,forwards(HashMap)


5.ActionForward

name,path


6.配置文件

实例:模仿struts填充formbean


分析:
1)创建AddstudentForm对象----根据类的全名进行反射(Class.forName)
2)需要把页面的参数提取出来(request.getParameterNames()----Enumeration)
3)把参数名与bean的属性名进行匹配:如果能匹配就把取出来的值填充到bean中(借助BeanUtils)
4)保存form
设计一个FormUtil完成以上描述的功能

package cn.com.hewei.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.struts.action.ActionForm;

public class FormUtil {
	public static void fillForm(HttpServletRequest request,
			String formClassFullName, String ClassName)
			throws InstantiationException, IllegalAccessException,
			ClassNotFoundException, InvocationTargetException {// 实例化实体
			ActionForm form = (ActionForm) Class.forName(formClassFullName).newInstance();
			// 得到所有从网页传来的参数
			Map parameters = request.getParameterMap();
			// 得到所有bean中的参数
			Field[] fields = Class.forName(formClassFullName).getDeclaredFields();
			// 填充bean
			BeanUtils.populate(ClassName, parameters);
			// 往session中传数
			request.getSession().setAttribute(ClassName, form);
	}
}


struts高级部分

1.Struts的标签

1.1 struts标记库

Jsp视窗组件所使用的struts标记库由四类标记组成:

1)Bean标记:用来在Jsp页中管理bean

2)逻辑标记:用来在Jsp页中控制流程

3)Html标记:用来生成HTML标记,在表单中显示数据,使用会话的ID对URL进行编程

Struts提供了很多表单相关的自定义标签,如:
<html:text>
<html:radio>
<html:select>
<html:option>
<html:checkbox>
<html:multibox>
<html:textarea>
这些标签除用于生成相应的html标签外,最大的好处在于它在产生html标签时,会自动检索相应formbean的数据予以显示,这样,当表单校验失败时,表单数据的回显struts帮我们干了,开发人员就不需要再编码去取了。

使用Struts的html标签完成数据回显时注意的问题:
html标签回显数据时,会以org.apache.struts.taglib.html.BEAN为关键字,从各个域中查找bean,找不到则抛空指针异常。所以使用html标签时域中须有以org.apache.struts.taglib.html.BEAN为关键字的对象。
这个工作可以交给html:form标签做,html:form标签在执行时,会查找域中已有的formbean,并以org.apache.struts.taglib.html.BEAN为关键字把formbean存在域中。如果html:form标签在域中找不到formbean,则html:form标签会实例化一个空bean,然后存储到域中。因此,为了在页面中使用struts的html标签回显数据,这些标签需要配合html:form标签使用。(查看html:form标签的源文件可以看到这点)。
对于复选框中的数据,Html:checkbox标签不能完成数据回显,复选框的数据回显需要使用html:multibox。
Struts中的html:password标签也会回显数据,如果不想password回显,需要把其redisplay属性置为false。

4)tiles标记:使用动态模块构造普通格式的的页


1. 2 Bean标记:

在标签库中包含用于定义新的bean,访问bean及其属性的标记,Bean标记库将标记定义在四个子类别中:
创建和复制bean的标记
脚本变量定义标记
bean翻译标记
消息国际化标记

1)Bean:define 从已有的变量或者变量的属性定义一个新的变量
Serach:fromwhere---scope,who----name,which property---property
Define: 新定义的变量名是id属性
Save:towhere---toScope
实例:从request中得到userName将其放到session中去

<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<!--taglib可以从struts-taglib.bean包中META-INF中的tld中找到-->
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="b"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head> 
    <title>My JSP 'BeanUtil.jsp' starting page</title>
  </head>
  <body>
  	<%String userName="ss";request.setAttribute("userName",userName);%>
	<!--id是新定义的名称,name是scope中的key值,toScope是将存到的域的值。如果是复合类型的值,定义property获得是哪个参数的值-->
	<b:define id="name" name="userName" scope="request" toScope="session"/>
	${sessionScope.name}
  </body>
</html>

这里注意的是scope是从哪个域中进行取值,toScope是将取出来的值放到哪个域中


Bean:write ,输出域中的值
<b:write name="name" scope="session"/>

3)message 和jstl的<fmt:message>类似,国际化信息
定义资源文件:

com.itcast.AlliacationRescources.properties
com.itcast. AlliacationRescources_zh-CN.properties

下面是AlliacationRescources_zh-CN.properties的内容:


这个是UTF-8编码之后的内容了


在struts-config中添加

<message-resources paremeter="com.itcast.ApplicationResources"key="myKey"/>

这里的填写的就是资源文件的全称地址,但是要注意不需要后缀名的,而且这里可以配置多个资源文件的


页面中使用

<bean:message bundle=”myKey” key=”userName”>
<bean:message bundle=”myKey” key=”password’>
注意:上面配置的key=”myKey”和这里的bundle=”myKey”可以不写


1.3 逻辑标记

逻辑库的标记能够用来处理外观逻辑而不需要使用scriptlet(这个属性在我们之前说到的自定义标签库的时候用到了)。Struts逻辑标签库包含的标记能够有条件的产生输出文本,在对象集合中循环从而重复的产生输出文本,应用程序流程控制,它也提供了一组在Jsp页中处理流程控制的标记。这些标记封装在文件名struts-logic.tld的标记 包中,逻辑标记库定义的标记能够执行下列三个功能
条件逻辑,重复,转发/重定向响应
1.循环 iterate(相当于forEach标签)
1)name:所指代的bean必须是一个集合类型
2)property:bean中的属性
<logic:iterator id=”username’ scope=”request’  name=”userNames”>
   ${username}
</logic:iterator>
3)   offset 设置循环的起始值
4)indexId 当前循环的下标
5)length 长度


2.动态表单和异常处理

2.1 动态表单

它让程序员不需要书写formbean,只需要在配置文件中配置即可
1)配置struts-config.xml

<form-bean name="dynStudentForm"
	type="org.apache.struts.action.DynaActionForm">
	<!-- 这里的type必须是完整的 -->
	<form-property name="sname" type="java.lang.String" />
	<form-property name="birthday" type="java.sql.Date" />
	<form-property name="major" type="java.lang.String" />
	<form-property name="score" type="java.lang.Float" />
</form-bean>

<action path="/dynAddStudent"
	type="cn.com.hewei.Action.DynAddStudentAction" name="dynStudentForm">
	<forward name="addSuccess" path="/loginSuccess.jsp"></forward>
	<forward name="addFail" path="/loginFail.jsp"></forward>
</action>

系统调用
package cn.com.hewei.Action;

import java.sql.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;

public class DynAddStudentAction extends Action {
	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
			DynaActionForm dynform = (DynaActionForm) form;
			// 获得信息
			String name = (String) dynform.get("sname");
			Date birthday = (Date) dynform.get("birthday");
			String major = (String) dynform.get("major");
			Float score = (Float) dynform.get("score");
			System.out.println("name=" + name + "birthday=" + birthday + "score="
					+ score);
			return null;
	}
}

2.2 struts中异常的处理

一.配置异常(在struts-config.xml文件中定义)
定制异常有两种:“全局异常(Global Exceptions)”和局部异常(Local Exception)
1.局部异常定义如下:(写在action的内部第一个)

<exception type="java.lang.Exception" path="/index.jsp" key="ss"></exception>
这里的path是要跳转的页面,type是异常的类型,key是异常的关键字,相应action中execute抛出异常就会跳到这里处理

 2.全局异常的配置

<global-exceptions>
	<exception type="java.lang.Exception" path="/index.jsp" key="ss"></exception>
</global-exceptions>

2.3.得到异常的信息

我们可以通过exception中的key关键字到配置文件中找到配置文件的信息
1)写异常文件
 ApplicationResource.properties
在其中输入信息:<exception>标签中key的值 = 异常的描述
例:ss=it is a validare user

2)注册异常文件(文件的末尾不要加.properties)
<message-resources parameter="cn.com.hewei.bean. ApplicationResource">
</message-resources>

3)在页面输出异常的信息
在页面注册taglib
<%@taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
调用
<html:errors/>  输出所有的异常信息

2.4 struts中插件的使用

1.接口为Plugin,生命周期方法:init和destroy
2.用户提供setter方法,告诉ActionServlet中心控制器设置属性
应用:在struts启动的时候把hibernate加载进来(读取hibernate配置文件和打开hibernate的sessionfactory)。
1)struts 的jar包+hibernate的jar包
2)设计一个类:HibernatePlugin实现plugin接口 
属性:String  hibernateConfigFile
读取hibernate配置文件
打开SessionFactory
释放资源
3)在struts-config配置文件中填上一对<plugin>,在plugin中加上子标签
实例:
工具类:
package cn.com.hewei.plugin;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class SessionFactoryManager {
	private static String hibernateConfigFile = null;

	public static String getHibernateConfigFile() {
		return hibernateConfigFile;
	}

	public static void setHibernateConfigFile(String hibernateConfigFile) {
		SessionFactoryManager.hibernateConfigFile = hibernateConfigFile;
	}

	private static Configuration con = null;
	private static SessionFactory sessionFactory = null;

	public static SessionFactory getSessionFactory() {
		con = new Configuration().configure(hibernateConfigFile);
		sessionFactory = con.buildSessionFactory();
		return sessionFactory;
	}

	public static void closeSessionFactory() {
		if (sessionFactory != null && sessionFactory.isClosed() == false)
			sessionFactory.close();

	}
}

插件类
package cn.com.hewei.plugin;

import javax.servlet.ServletException;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;

public class HibernatePlugin implements PlugIn {
	private String hibernateConfigFile;

	public String getHibernateConfigFile() {
		return hibernateConfigFile;
	}

	public void setHibernateConfigFile(String hibernateConfigFile) {
		this.hibernateConfigFile = hibernateConfigFile;
	}

	public void destroy() {
		// 关闭sessionFactory
		System.out.println("closeSessionFactory");
		SessionFactoryManager.closeSessionFactory();
	}

	public void init(ActionServlet arg0, ModuleConfig arg1)
			throws ServletException {
		System.out.println("openSessionFactory");
		// 1.读取hibernate配置文件
		SessionFactoryManager.setHibernateConfigFile(hibernateConfigFile);
		// 2.打开sessionFactory
		SessionFactoryManager.getSessionFactory();
	}
}

配置文件
<plug-in className="cn.com.hewei.plugin.HibernatePlugin">
    	<set-property property="hibernateConfigFile" value="/WEB-INF/hibernate.cfg.xml"/>
</plug-in>

可以在中心控制器ActionServlet的init方法对plugin初始化在destroy方法中销毁
插件的生命周期:


DispatchAction

3.1 DispatchAction

派发Action的使用:实现多个方法会有多个Action这样太复杂了,可以使用DispatchAction
如图:

在action标签中使用parameter属性:<action parameter=”method”>
调用:http://localhost:8081/Mystruts/SrudentAction?method=update
实例:
1,继承DispathAction

package cn.com.hewei.Action;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;

public class StudentAction extends DispatchAction{
	public ActionForward addStudent(ActionMapping arg0, ActionForm arg1,
			HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
		PrintWriter out=arg3.getWriter();
		out.println("addStudent");
		return null;
	}
	public ActionForward deleteStudent(ActionMapping arg0, ActionForm arg1,
			HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
		PrintWriter out=arg3.getWriter();
		out.println("deleteStudent");
	
		return null;
	}
	public ActionForward updateStudent(ActionMapping arg0, ActionForm arg1,
			HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
		PrintWriter out=arg3.getWriter();
		out.println("updateStudent");
		return null;
	}

}

写配置文件

<action path="/StudentAction" type="cn.com.hewei.Action.StudentAction"
		name="dynStudentForm" parameter="method">
	<forward name="addSuccess" path="/loginSuccess.jsp"></forward>
	<forward name="addFail" path="/loginFail.jsp"></forward>
</action>

3.访问
http://localhost:8080/Mystruts/StudentAction.do?method=addStudent
输出:addStudent
http://localhost:8080/Mystruts/StudentAction.do?method=deleteStudent
输出:deleteStudent
http://localhost:8080/Mystruts/StudentAction.do?method=updateStudent

输出:updateStudent


注意:
1)可以开发一个DispatherAction’的子类
这里的方法注意必须与原来的execute方法同参同返回值
2)配置parameter属性

3.2 MappingDispatchAction

使用DispatchAction转发,每次使用的是同一个Action,这样很容易错误,为了解决这个问题我们使用MappingDispatchAction
实例:

public class StudentAction extends MappingDispatchAction{
	public ActionForward addStudent(ActionMapping arg0, ActionForm arg1,
			HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
		PrintWriter out=arg3.getWriter();
		out.println("addStudent");
		return null;
	}
	public ActionForward deleteStudent(ActionMapping arg0, ActionForm arg1,
			HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
		PrintWriter out=arg3.getWriter();
		out.println("deleteStudent");
	
		return null;
	}
	public ActionForward updateStudent(ActionMapping arg0, ActionForm arg1,
			HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
		PrintWriter out=arg3.getWriter();
		out.println("updateStudent"); 
		return null;
	}

}

配置文件:这里的parameter不可以随便写,必须和action中的方法名相同
<action path="/addStudent" type="cn.com.hewei.Action.StudentAction"
	name="dynStudentForm" parameter="addStudent">
</action>
<action path="/deleteStudent" type="cn.com.hewei.Action.StudentAction"
	name="dynStudentForm" parameter="deleteStudent">
</action>
<action path="/updateStudent" type="cn.com.hewei.Action.StudentAction"
	name="dynStudentForm" parameter="updateStudent">
</action>

访问:(这样就可以访问不同的路径转到不同的action了)
http://localhost:8080/Mystruts/addStudent.do
http://localhost:8080/Mystruts/deleteStudent.do

http://localhost:8080/Mystruts/updateStudent.do


3.3.Struts防止表单的重复提交

Struts的<html:form>标签除了可以生成<form>标签、协助其它html标签完成数据回显外,它还提供了防止表单重复提交的功能。
<html:form>标签在生成表单时,会检查session域中是否存在token,如果存在则自动使用token生成隐藏字段。
Struts为方便开发人员生成token,在action中提供了saveToken方法,调用这个方法就可以在session域中保存一个token。
Struts为方便开发人员在action中校验用户是否为重复提交,因此它在action中也提供了isTokenValid方法,该方法会自动判断表单是否为重复提交。
防表单重复提交在struts中的做法:
1、用户先访问Action,Action中调用saveToken方法,然后派发到表单页面。
2、在表单页面中使用<html:form>标签, <html:form>标签会自动为表单生成一个带随机值的隐藏字段。
3、在表单提交的Action中调用isTokenValid方法,就可以判断出表单是否为重复提交,从而可以根据情况决定如何处理。 isTokenValid方法返回true,则为允许提交,处理提交后,要记得调用reset清除token。


代码如下:

package cn.com.ambow.struts.day3;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.MappingDispatchAction;

public class TokenAction extends MappingDispatchAction {
	public ActionForward toLogin(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		ActionForward forward = null;
		// 生成随机数
		saveToken(request);
		return mapping.findForward("login");
	}

	public ActionForward login(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		ActionForward forward = null;
		try {
			String name = request.getParameter("userName");
			String password = request.getParameter("password");
			IUserDao dao = new UserDaoImpl();
			// 比较token
			if (!isTokenValid(request, true)) {
				request.setAttribute("message", "Token Error!!");
				forward = mapping.findForward("error");

			} else {
				User user = dao.findByNameAndPassword(name, password);
				if (user != null) {
					request.setAttribute("user", user);
					forward = mapping.findForward("success");
				} else {
					request.setAttribute("message", "Login Error!!");
					forward = mapping.findForward("error");

				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			request.setAttribute("message", "Login Error!!");
			forward = mapping.findForward("error");
		}
		return forward;
	}

}

配置文件
<action path="/struts1/token/toLogin"
	type="cn.com.ambow.struts.day3.TokenAction" parameter="toLogin">
	<forward name="login" path="/struts/day3/token/login.jsp"></forward>
</action>
<action path="/struts1/token/login"
	type="cn.com.ambow.struts.day3.TokenAction" parameter="login"
	name="loginForm">
	<forward name="success" path="/struts/day3/token/success.jsp"></forward>
	<forward name="error" path="/struts/day3/token/error.jsp"></forward>
</action>

login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<html>
  <head>
    <title>My JSP 'login.jsp' starting page</title>
  </head>
  <body>
    <h2 align="center">测试Srtuts1 Token</h2>
  <hr/>
  <html:errors/>
   <html:form action="/struts1/token/login.do" method="post">
			userName:<input type="text" name="userName">
			password:<input type="password" name="password">
			<input type="submit"  value="loginsss">
	</html:form>
  </body>
</html>

访问toLogin.do会带来jsessionid,跳到登录页面,登录页面跳转到login.do执行,isTokenValid(request, true)判断是否重复提交。


3.4 struts的验证框架

Validator(验证器)框架是一个 Struts 插件,它支持采用声明式的方式对表单进行校验,而不需要用户编写一行Java代码。集成validate框架  ,Struts那哥们他帮你校验了表单,而且客户端也校验,比如javascript校验他也帮你校验了使用 Validator 框架的好处:
更好的可维护性
校验实现标准化
正确的实现
更少的代码重复
自动客户端验证


解压Struts的例子struts-cookbook-1.3.8,部署到web服务器中,查看例子体验。
在工程中集成validate框架,你需要查看org.apache.struts.validator包下的validator-rules.xml文件,它是validate框架的校验规则文件,这个文件说明了如何在struts工程中集成validate框架:
1、在struts-config.xml文件中配置validate插件。
2、创建资源文件,并复制validate框架工作需要的信息。
3、把struts-cookbook-1.3.8例程自带的、validate框架的配置文件validation.xml,复制到当前web工程的WEB-INF目录下。


validate框架环境搭建好后,就可以采用配置的方式对formbean的属性进行校验,但需要注意:
1、formbean要想使用validate框架校验,不能直接继承 ActionForm, 而要继承其子类 ValidatorForm。
2、如果是DynaActionForm,就必须要继承DynaValidatorForm


Validation.xml文件详解

<form>元素:为表单配置验证规则,它的 name 属性指定了表单的名字.<form>元素可以包含一个或多个<field>子元素
<field>元素:配置表单中字段的验证规则
property:指定 ActionForm Bean 中需要进行验证的字段的名字
depends:指定字段的验证规则,多个验证规则之间以逗号隔开
<msg>元素:指定验证规则对应的消息文本。该消息文本将替代在 validator-rules.xml 文件中为验证规则配置的默认的消息文本
name:指定验证规则的名字
key:当 resource 为 true 时,该属性指定消息 key,该消息 key 应该在 Resource Bundle 中存在,当 resource为 false 时,该属性直接指定消息文本
resource:当该属性为true时,表明使用来自于 Resource Bundle 的消息;如果为 false,表明 直接在 key 属性中设置消息文本,默认为 true
arg 元素:替换符合消息中的参数
name,key,resource 元素同上
position 元素:指定替换符合消息中的参数的位置
var 元素:向验证规则传递参数
<arg> 元素:也可以访问<var>元素,语法为${var:var-name}


Struts-Validate客户端验证

Validator 框架也可以进行浏览器客户端验证,示例:


注意:<html:javascript>的formName指定表单的名称。onsubmit事件的值也必须为return validate表单名(this)


具体步骤:

1)在src下导入validation.xml和validator-rules.xml

validattion.xml文件可以从Struts1源代码目录中的apps目录中的例子中找到
validator-rules.xml
2)在配置文件中加入对以上两个文件的插件

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
	<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" />
</plug-in>

bean类
package cn.com.hewei.Bean;
import org.apache.struts.action.ActionForm;
public class LoginForm extends ActionForm {
	private String userName;
	private String password;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
}

Action类
package cn.com.hewei.Action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.MappingDispatchAction;
public class LoginAction  extends MappingDispatchAction{
public ActionForward login(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		ActionForward forward = null;
		try{
			String name = request.getParameter("name");
			String password = request.getParameter("password");
			if("admin".equals(name) && "admin".equals(password)){
					request.setAttribute("name", name);
					forward = mapping.findForward("success");
			}else{
				request.setAttribute("message", "Login Error!!!!");
				forward = mapping.findForward("error");
			}
		}catch(Exception e){
			e.printStackTrace();
			request.setAttribute("message", "Login Error!!!!");
			forward = mapping.findForward("error");
		}
		return forward;
	}
}

登陆界面

<body>
	<h2 align="center">测试struts的验证框架</h2>
	<hr />
	<font color="red">
		<html:errors />
	</font>
	<! —必须使用struts标签提交--
    	
	<html:form action="/login.do" method="post" onsubmit="return vloginForm(this)">
    	userName:<input name="name" type="text" />
    	password:<input name="password"  type="password" />
    				<input type="submit"  value="login"/>
    				<html:javascript formName="vloginForm"/>
    	</html:form>
</body>

写validation.xml
<form-validation>
	<formset>
		<!—这里的name和表单的formName要一致-->
		<form name="vloginForm">
			<!—depends是验证器,key是输出的信息-->
			<field property="name" depends="required">
				<arg key="validate.name"/>
			</field>
			<field property="password" depends="required">
				<arg key="validate.password"/>
			</field>
		</form>
	</formset>
</form-validation>

7) 写显示错误的资源文件(Login.properties)

validate.name=userName
validate.password=password
errors.required={0} is required

这里使用了占位符操作


8) 写配置文件

<!—这里的name和表单的name以及 validation中form的name一致-->
<form-bean name="vloginForm"  type="cn.com.hewei.Bean.ValidateLoginForm"></form-bean>
<action path="/login"  type="cn.com.hewei.Action.LoginAction" parameter="login" name="vloginForm" validate="true" input="/login.jsp">
				<forward name="success" path="/loginSuccess.jsp"></forward>
				<forward name="error" path="/loginFail.jsp"></forward>
</action>

<!—加入资源文件-->
<message-resources parameter="cn.com.hewei.Bean.Login" ></message-resources>  


总结:Struts1本身的内容很多的,一篇文章是讲不完的,只有在使用的时候遇到具体的问题的时候,采取解决,当然这里还需要说明的一点就是一定要记得看源码,因为Struts1的源码不是很难的,看的也不费劲,有很多问题都是可以在源码中找到答案的,大纲如下:

Struts的控制器组件主要包括
ActionServlet对象:Struts 的核心类
RequestProcessor对象:由ActionServlet调用,负责处理用户请求
Action对象:用户自己编写的类
Struts处理请求的流程:
当 ActionServlet 接收到 HTTP 请求后,在 doGet 或 doPost 方法中都会调用process()方法处理请求
在 ActionServlet 的 process() 方法中一旦选择了正确的子应用模块,就会调用RequestProcessor实例的process()方法来处理请求。在ActionServlet调用这个方法时,会把当前的request和response对象传给它
RequestProcessor实例的process()方法调用ProcessActionCreate()方法,先判断是否在 Action 缓存中存在Action实例,如果不存在,就创建一个Action实例,把它保存在 Action 缓存中
RequestProcessor实例的process()方法调用Action实例的execute()方法

本文所使用的案例项目工程下载地址:

http://download.csdn.net/detail/jiangwei0910410003/7398529








posted @ 2014-05-23 09:15  roccheung  阅读(227)  评论(0编辑  收藏  举报