Blog信息 |
blog名称:小鸟吹烟 日志总数:157 评论数量:424 留言数量:-1 访问次数:1253016 建立时间:2006年10月23日 |

| |
[SSH 学习区]struts 笔记  文章收藏, 网上资源
tone 发表于 2007/3/12 16:38:08 |
转自http://blog.chinaunix.net/u/4764/showart.php?id=143800
struts 笔记
第一篇 struts的初始化
struts 的核心类是org.apache.struts.action.ActionServlet,这个类将会在struts第一次使用时,
作为servlet初始化并存入servlet容器。很显然的,初始化将会调用init方法初始化相应的数据。
1.Init()流程:
1) 调用initInternal()方法,初始化Struts框架内在的消息资源,如系统日志相关的通知、警告和错误消息
initInternal()方法:
通过调用MessageResources.getMessageResources(internalName)方法生成一个
MessageResources类,getMessageResources是通过调用MessageResourcesFactory.
createResources(config)来实现的。至于MessageResourcesFactory是一个abstract类,任何
继承自它的类都要实现createResources方法,生成MessageResources对象。整个程序生成
MessageResourcesFactory使用了如下技巧:
MessageResourcesFactory.factoryClass = factoryClass;
MessageResourcesFactory.clazz = null;
首先会通过factoryClass来定义一个类全名,然后通过ClassLoader.loadClass
(factoryClass)方法来生成这个类,并赋给clazz,然后通过newInstance来生成一个对象。
在本程序中,生成MessageResources对象实际就是对如下属性进行了初始化:
this.factory = factory;("org.apache.struts.util.PropertyMessageResourcesFactory")
this.config = config;("org.apache.struts.action.ActionResources")
this.returnNull = returnNull;(true/false)
对于MessageResources类的作用是根据不同的Locate来格式化相应的string。或者把你需要改变
的string存放到数组中,然后通过getMessage(Locale locale, String key, Object args[])
方法来格式化。然后把格式好的string存放到HashMap里,这样就可以为以后重用。这里的key是
使用的locale.toString() + "." + key
在PropertyMessageResources中的loadLocale方法用来读取resource的初始化信息。首先它会
通过一个HashMap检测这个localKey相关的message是否已经被初始化了,如果被初始化过就跳
出,检测的方法是locales.get(localeKey) != null。
然后会读取如下一个文件:
org/apache/struts/action/ActionResources_(localKey).properties,然后进行如下操作:
Properties props = new Properties();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
is = classLoader.getResourceAsStream(name);
props.load(is);
Iterator names = props.keySet().iterator();
while (names.hasNext()) {
String key = (String) names.next();
if (log.isTraceEnabled()) {
log.trace(" Saving message key '" + messageKey(localeKey, key));
}
messages.put(messageKey(localeKey, key), props.getProperty(key));
}
PropertyMessageResources 就是通过上面的loadLocale方法查找与Locale locale, String key
相对对应的Message.查找的次序如下locale.toString(),然后是
localeKey = localeKey.substring(0, underscore),然后是defaultLocale,然后是key。
最后,resource类的结构如下:
PropertyMessageResources extends MessageResources
PropertyMessageResourcesFactory extends MessageResourcesFactory
2) 调用initOther()方法,从web.xml中加载ActionServlet的初始化参数,如config等
initOther()方法:
从servlet中获取config和debug两个参数,然后初始化ConvertUtils对象。由于
ConvertUtils.deregister()的初始化,所有的Converter都是有初始值的,所以这里Struts自己
把这些初始值设置为null,即转换出错的时候返回null,而不是初始值。使用ConvertUtils类的
原因是由于从form传输过来的都是String类型的值,所以我们要把它们转换成相应的类型。
提到几个技巧:
*public boolean isIndexed() {
if (type == null) {
return (false);
//技巧一:判断是否是一个Array类的方法
} else if (type.isArray()) {
return (true);
//技巧二:判断type是否是List的一个父类或者父接口,或者与List为同一个类
//要注意如果List是另一个primitive的TYPE类,那么type必须也是这个类才会
//返回true,否则都是false。注意long.TYPE与Long.class是不同的
} else if (List.class.isAssignableFrom(type)) {
return (true);
} else {
return (false);
}
}
*//componentType为Array类所存储的元素的类别
Class componentType = indexedProperty.getClass().getComponentType();
//生成一个新的Array
Object newArray = Array.newInstance(componentType, (index + 1));
System.arraycopy(indexedProperty, 0, newArray, 0, length);
indexedProperty = newArray;
set(name, indexedProperty);
int newLength = Array.getLength(indexedProperty);
for (int i = length; i < newLength; i++) {
Array.set(indexedProperty, i, createProperty(name+"["+i+"]", componentType));
}
3) 调用initServlet()方法,从web.xml文件中加载ActionServlet的Url映射信息。此外还会注册web.xml和struts配置文件所使用的DTD文件,这些DTD文件用来验证web.xml和strutc配置文件的语法
initServlet()方法:
这个方法主要是通过digester类解析web.xml,对String servletMapping属性进行初始化。对于
digester说明如下:这是一个基于DOM的SAX实现的类,它是事件触发的,根据xml文件的结构,
每次读到一个节点元素就会触发一个事件。
InputStream input = getServletContext().getResourceAsStream("/WEB-INF/web.xml");
这是一个比较少见的方法。首先通过this.servletName = getServletConfig().
getServletName()获取servlet的名称,然后根据
if (servletName.equals(this.servletName)) {
this.servletMapping = urlPattern;
}
来判断当前读到的servlet名称是否是我们运行的servlet的名称,如果是,就把url-pattern作为
我们的servletMapping。
4) 调用initModuleConfig()方法,加载并解释默认子应用模块的struts配置文件;创建ModuleConfig对象,把它存储在ServletContext中
ModuleConfig moduleConfig = initModuleConfig("", config)
这个方法使用由initOther()方法获取的config值为要解析的xml路径,用来初始化ModuleConfig。
它首先采用与生成MessageResourcesFactory同样的方法产生一个MessageResourcesFactory对象:
MessageResourcesFactory为一个抽象类,每一个继承它的类都要实现
createModuleConfig(String prefix)方法。本程序使用的缺省的MessageResourcesFactory类为
org.apache.struts.config.impl.DefaultModuleConfigFactory,它
的createModuleConfig(String prefix)方法会生成一个ModuleConfigImpl类。
ModuleConfigImpl类相当于一个JavaBean,用来存放一个web模块运行时所需要的配置信息。当
然,一个web模块可以拥有多个ModuleConfig,但是缺省的是prefix长度为0的ModuleConifg。它
的每个属性几乎都是由HashMap组成的,它通过一个configured布尔值来描述当前的ModuleConfig
是否已经被初始化完毕,在每存放一个属性的时候都会监测这个值。如果初始化完毕而还要改变
里面的属性值,则会报出IllegalStateException("Configuration is frozen")异常,现在对它
的属性简单说明如下:
* protect |
|
回复:struts 笔记 文章收藏, 网上资源
tone发表评论于2007/3/12 16:54:20 |
protected boolean processValidate(HttpServletRequest request,
HttpServletResponse response,
ActionForm form,
ActionMapping mapping)
throws IOException, ServletException {
if (form == null) {
return (true);
}
// Was this request cancelled?
if (request.getAttribute(Globals.CANCEL_KEY) != null) {
if (log.isDebugEnabled()) {
log.debug(" Cancelled transaction, skipping validation");
}
return (true);
}
// Has validation been turned off for this mapping?
if (!mapping.getValidate()) {
return (true);
}
// Call the form bean's validation method
if (log.isDebugEnabled()) {
log.debug(" Validating input form properties");
}
ActionMessages errors = form.validate(mapping, request);
if ((errors == null) || errors.isEmpty()) {
if (log.isTraceEnabled()) {
log.trace(" No errors detected, accepting input");
}
return (true);
}
// Special handling for multipart request
if (form.getMultipartRequestHandler() != null) {
if (log.isTraceEnabled()) {
log.trace(" Rolling back multipart request");
}
form.getMultipartRequestHandler().rollback();
}
// Was an input path (or forward) specified for this mapping?
String input = mapping.getInput();
if (input == null) {
if (log.isTraceEnabled()) {
log.trace(" Validation failed but no input form available");
}
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
getInternal().getMessage("noInput",
mapping.getPath()));
return (false);
}
// Save our error messages and return to the input form if possible
if (log.isDebugEnabled()) {
log.debug(" Validation failed, returning to '" + input + "'");
}
request.setAttribute(Globals.ERROR_KEY, errors);
if (moduleConfig.getControllerConfig().getInputForward()) {
ForwardConfig forward = mapping.findForward(input);
processForwardConfig( request, response, forward);
} else {
internalModuleRelativeForward(input, request, response);
}
return (false);
}
/**
* <p>Do a module relative forward to specified URI using request dispatcher.
* URI is relative to the current module. The real URI is compute by prefixing
* the module name.</p>
* <p>This method is used internally and is not part of the public API. It is
* advised to not use it in subclasses. </p>
*
* @param uri Module-relative URI to forward to
* @param request Current page request
* @param response Current page response
*
* @since Struts 1.1
*/
protected void internalModuleRelativeForward(
String uri,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Construct a request dispatcher for the specified path
uri = moduleConfig.getPrefix() + uri;
// Delegate the processing of this request
// :FIXME: - exception handling?
if (log.isDebugEnabled()) {
log.debug(" Delegating via forward to '" + uri + "'");
}
doForward(uri, request, response);
}
/**
* <p>Do a module relative include to specified URI using request dispatcher.
* URI is relative to the current module. The real URI is compute by prefixing
* the module name.</p>
* <p>This method is used internally and is not part of the public API. It is
* advised to not use it in subclasses.</p>
*
* @param uri Module-relative URI to include
* @param request Current page request
* @param response Current page response
*
* @since Struts 1.1
*/
protected void internalModuleRelativeInclude(
String uri,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Construct a request dispatcher for the specified path
uri = moduleConfig.getPrefix() + uri;
// Delegate the processing of this request
// FIXME - exception handling?
if (log.isDebugEnabled()) {
log.debug(" Delegating via include to '" + uri + "'");
}
doInclude(uri, request, response);
}
/**
* <p>Do a forward to specified URI using a <code>RequestDispatcher</code>.
* This method is used by all internal method needing to do a forward.</p>
*
* @param uri Context-relative URI to forward to
* @param request Current page request
* @param response Current page response
* @since Struts 1.1
*/
protected void doForward(
String uri,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Unwrap the multipart request, if there is one.
if (request instanceof MultipartRequestWrapper) {
request = ((MultipartRequestWrapper) request).getRequest();
}
RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);
if (rd == null) {
response.sendError(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
getInternal().getMessage("requestDispatcher", uri));
return;
}
rd.forward(request, response);
}
/**
* <p>Do an include of specified URI using a <code>RequestDispatcher</code>.
* This method is used by all internal method needing to do an include.</p>
*
* @param uri Context-relative URI to include
* @param request Current page request
* @param response Current page response
* @since Struts 1.1
*/
protected void doInclude(
String uri,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Unwrap the multipart request, if there is one.
if (request instanceof MultipartRequestWrapper) {
request = ((MultipartRequestWrapper) request).getRequest();
}
RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);
if (rd == null) {
response.sendError(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
getInternal().getMessage("requestDispatcher", uri));
return;
}
rd.include(request, response);
}
// -------------------------------------------------------- Support Methods
/**
* <p>Return the <code>MessageResources</code> instance containing our
* internal message strings.</p>
*/
protected MessageResources getInternal() {
return (servlet.getInternal());
}
/**
* <p>Return the <code>ServletContext</code> for the web application in which
* we are running.
*/
protected ServletContext getServletContext() {
return (servlet.getServletContext());
}
/**
* <p>Log the specified message to the servlet context log for this
* web application.</p>
*
* @param message The message to be logged
* @deprecated Use commons-logging instead. This will be removed in a release
* after Struts 1.2.
*/
protected void log(String message) {
// :TODO: Remove after Struts 1.2
servlet.log(message);
}
/**
* <p>Log the specified message and exception to the servlet context log
* for this web application.</p>
*
* @param message The message to be logged
* @param exception The exception to be logged
* @deprecated Use commons-logging instead. This will be removed in a release
* after Struts 1.2.
*/
protected void log(String message, Throwable exception) {
// :TODO: Remove after Sruts 1.2
servlet.log(message, exception);
}
} |
|
回复:struts 笔记 文章收藏, 网上资源
tone发表评论于2007/3/12 16:51:56 |
3.实例说明:
1)web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<display-name>HelloApp Struts Application</display-name>
<!-- Standard Action Servlet Configuration -->
<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>2</load-on-startup>
</servlet>
<!-- Standard Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- The Usual Welcome File List -->
<welcome-file-list>
<welcome-file>hello.jsp</welcome-file>
</welcome-file-list>
<!-- Struts Tag Library Descriptors -->
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
</web-app>
2) struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<!--
This is the Struts configuration file for the "Hello!" sample application
-->
<struts-config>
<!-- ======== Form Bean Definitions =================================== -->
<form-beans>
<form-bean name="HelloForm" type="hello.HelloForm"/>
</form-beans>
<!-- ========== Action Mapping Definitions ============================== -->
<action-mappings>
<!-- Say Hello! -->
<action path = "/HelloWorld"
type = "hello.HelloAction"
name = "HelloForm"
scope = "request"
validate = "true"
input = "/hello.jsp"
>
<forward name="SayHello" path="/hello.jsp" />
</action>
</action-mappings>
<!-- ========== Message Resources Definitions =========================== -->
<message-resources parameter="hello.application"/>
</struts-config>
3)流程:
A)用户请求/HelloWorld.do
B)Servlet容器在web.xml中寻找<url-pattern>属性为“*.do”的<servlet-mapping>元素:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
C)servlet容器依据以上<servlet-mapping>元素的<servlet-name>属性”action”,在web.xml中寻找匹配的<servlet>元素
<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>2</load-on-startup>
</servlet>
D)servlet容器把请求转发给以上<servlet>元素指定的ActionServlet,ActionServlet依据用户请求路径“/HelloWorld.do”,在struts配置文件中搜索path属性为”/HelloWorld”的<Action>元素:
<!-- Say Hello! -->
<action path = "/HelloWorld"
type = "hello.HelloAction"
name = "HelloForm"
scope = "request"
validate = "true"
input = "/hello.jsp"
>
<forward name="SayHello" path="/hello.jsp" />
</action>
E)ActionServlet根据<action>元素的name属性,创建一个HelloForm对象,把客户提交的表单数据传给HelloForm对象,再把HelloForm对象保持在<action>元素的scope属性指定的request范围内。
F)由于<action>元素的validate属性为true,ActionServlet调用HelloForm对象的validate()方法执行表单验证:
HelloForm.validate()
G_1)如果HelloForm.validate()返回一个ActionErrors对象。这个对象里面保护一个ActionMessage对象,这个对象中封装了错误消息。ActionServlet把该ActionErrors对象存在request范围内,然后根据<action>元素的input属性,把客户请求转发给hello.jsp
G_2)如果HelloForm.validate()返回的ActionErrors对象中不包含任何ActionMessage对象,表示表单验证成功。
H)ActionServlet查找<action>中type对应的Action类—HelloAction 实例是否存在,如果不存在就创建一个实例。然后调用HelloAction的execute()方法。
I_1)HelloAction的execute方法先进行逻辑验证,如果没有通过逻辑验证,就创建一个ActionMessage对象,这个ActionMessage对象封装了错误消息。Execute()方法把ActionMessage对象保存在ActionMessage对象中,再把ActionMessage对象存放在request范围内。最后返回一个ActionForward对象,该对象包含的请求转发路径为<action>元素的input属性指定的hello.jsp。
I_2)HelloAction的execute通过逻辑验证。最后调用ActionMapping.findForward(“SayHello”)。
Return(mapping.findForward(“SayHello”)) ;
J)ActionMapping.findForward()方法从<action>元素中寻找name属性为”SayHello”的<forward>子元素,然后返回与之对应的ActionForward对象,它代表的请求转发路径为“/hello.jsp”
K)HelloAction的execute()方法然后把ActionForward对象返回给ActionServlet,ActionServlet再把客户请求转发给hello.jsp。
|
|
» 1 »
|