struts2中Convention plug-in中的那些事情

struts2中Convention plug-in中的那些事儿

 

哈哈,一颗好奇心、一颗永不满足的心让我终于解决了这个问题。

解决问题来源:官方的教程(英文的,虽然英语不咋地,还是硬着头皮给看完了。(*^__^*) 嘻嘻……),获取办法google搜索struts2然后找到带有apache的网址,也就是在www.apache.org中的一个分支了。

下面就说一下里面的具体问题吧:

当我们需要用到注解的时候,需要引入一个jar包,名字为:struts2-convention-plugin-2.3.1.2.jar,先提示一下,千万别小看这个包哦,这个包可是很“智能”的,如果你很想自己手工完成某些操作,而你引入了这个包,它很可能破坏你的打算哦。下面就看一下这个包的作用了:

默认情况下Convention plugin监听包名含有:strustruts2action或者actions这些包中的action类,也就是说如果你建立的包名最后包含上述这几个类型,那么action就会自动的将它作为你的action处理类所在的包。

那么我们自己编写的action呢就应该实现action接口或者以action结尾,那么Convention plugin就会自动识别这些类。

并且啊,这个Convention plugin还会用类的名字去匹配URL,也就是说:如果你发出的一个请求是请求hello.action,如果你有一个类名为HelloAction(可以不实现Action接口)或者类名为Hello(实现Action接口),那么你就可以不进行任何的配置(指的是struts.xml中配置actionURL的映射,并且也没有采用注解方式配置)就可以形成一个ActionURL的映射。神奇吧,这个就是Convention plugin的智能,别急,不要急着去实践,下面还有呢。。。

此刻Convention plugin已经知道了如何的将请求和Action对应起来,那么它是否可以智能的将结果和结果页面对应呢。当你看到这个问题的时候估计和我的想法一样:这怎么可能呢,返回的结果有那么多的情况:inputerrorsuccess等等,它怎么可以自动的寻找映射呢。(*^__^*) 嘻嘻……那你也太小看Convention plugin这个包了,它的确可以形成映射,但是前提就是你的结果页面必须的符合一定的命名规则,并且存储的路径也不能随便存储哦。它的具体规则为:1、通常情况下Convention plugin包会默认为处理的结果页面位于WEB-INF/content这个路径下(此路径可以在struts.properties中进行修改,要修改的属性为:上struts.convention.result.path );2、结果的命名也就是在你请求的页面后面加上结果信息了,例如:刚刚请求的是Hello,那么你可以在前面要求的路径下建立一个hello.jsp(返回success时会执行)hello-success.jsp(返回success时会执行)、hello-input.jsp(返回input的时候会执行),剩下的就依葫芦画瓢了,也就是你的请求”+”-”+”结果类型”.jsp,当然还可以有其它的类型,例如:freeMaker等。

看到这儿,基本上那个问题都已经解决了。

那么下面,我们就看一下官方提供的一个示例源代码了:

在看源代码前,先看一下整体的命名规则及其所需要引入的库:


struts2中Convention plug-in中的那些事情

先看一下Web.xml中的配置吧

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>Struts2Example1</display-name>
  <filter>
		<filter-name>struts2</filter-name>
		<filter-class>
			org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

 

 

 

再看一下Index.jsp

 

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@taglib uri="/struts-tags" prefix="s" %>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Hello World</title>
    </head>
    <body>
        <s:form action="welcome-user" >
            <s:textfield name="userName" label="User Name" />
            <s:submit />
        </s:form>
    </body>
</html>
 

 

下面的是URL对应的action

 

package com.vaannila.action;

import com.opensymphony.xwork2.ActionSupport;

public class WelcomeUser extends ActionSupport{
	private String userName;
	private String message;

	public String execute() {
		message = "Welcome " + userName;
		return SUCCESS;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public String getUserName() {
		return userName;
	}

	public String getMessage() {
		return message;
	}
}

   <!--[endif]-->下面的是用来显示结果的页面:

 

 

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Welcome User</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>

 至此已经完成了。。。。

 

还有一个顺便提醒一下:不知大家有没有留意什么时候保存.java文件的时候服务器会自动重启。。。我的观察结果:如果你的类不是重要的类(处理用户请求的类为重要类)或者文件不是重要的配置文件,那么服务器就不会重启,因为此刻牵扯到如果你的action放在一个包名不为convention plugin所自动化解析的包中的时候,并且你采用的是注解方式配置(因为我只做了这个测试,所以此处只说这种情况,其它的大家可以自己测试),那么你修改了action类,服务器不会重启。

 

觉得还是分析一下源代码比较好。。。。要不然总感觉到有些玄乎。。。

此刻我没有采用单步调试,只是简单的看了一下convention plug-in包中的部分代码,如果谁进行单步调试并分析了结果还希望可以分享一下哦。。。

下面总结一下看的结果:

org.apache.struts2.convention. DefaultResultMapBuilder这个类中有一个函数就实现了结果页面的自动映射,其实看这个类的名字也很容易发现的:默认生成结果映射

 

 /**
     * Makes all the results for the given path.
     *
     * @param   actionClass The action class the results are being built for.
     * @param   path The path to build the result for.
     * @param   resultPrefix The is the result prefix which is the result location plus the action name.
     *          This is used to determine if the path contains a result code or not.
     * @param   results The Map to place the result(s)
     * @param   packageConfig The package config the results belong to.
     * @param   resultsByExtension The map of extensions to result type configuration instances.
     */
    protected void makeResults(Class<?> actionClass, String path, String resultPrefix,
            Map<String, ResultConfig> results, PackageConfig packageConfig,
            Map<String, ResultTypeConfig> resultsByExtension) {
        if (path.startsWith(resultPrefix)) {
            int indexOfDot = path.indexOf('.', resultPrefix.length());

            // This case is when the path doesn't contain a result code
            if (indexOfDot == resultPrefix.length() || !flatResultLayout) {
                if (LOG.isTraceEnabled()) {
                    LOG.trace("The result file [#0] has no result code and therefore" +
                        " will be associated with success, input and error by default. This might" +
                        " be overridden by another result file or an annotation.", path);
                }
				//下面就是分析是否包含有返回结果类型的页面了
                if (!results.containsKey(Action.SUCCESS)) {
                    ResultConfig success = createResultConfig(actionClass,
                        new ResultInfo(Action.SUCCESS, path, packageConfig, resultsByExtension),
                        packageConfig, null);
                    results.put(Action.SUCCESS, success);
                }
                if (!results.containsKey(Action.INPUT)) {
                    ResultConfig input = createResultConfig(actionClass,
                        new ResultInfo(Action.INPUT, path, packageConfig, resultsByExtension),
                        packageConfig, null);
                    results.put(Action.INPUT, input);
                }
                if (!results.containsKey(Action.ERROR)) {
                    ResultConfig error = createResultConfig(actionClass,
                        new ResultInfo(Action.ERROR, path, packageConfig, resultsByExtension),
                        packageConfig, null);
                    results.put(Action.ERROR, error);
                }

            // This case is when the path contains a result code
            } else if (indexOfDot > resultPrefix.length()) {
                if (LOG.isTraceEnabled()) {
                    LOG.trace("The result file [#0] has a result code and therefore" +
                        " will be associated with only that result code.", path);
                }

                String resultCode = path.substring(resultPrefix.length() + 1, indexOfDot);
                ResultConfig result = createResultConfig(actionClass,
                    new ResultInfo(resultCode, path, packageConfig, resultsByExtension),
                    packageConfig, null);
                results.put(resultCode, result);
            }
        }
    }

 ..................................