您的位置:首页 > 编程语言 > Java开发

Struts2配置文件全路径搜索的实现

2013-08-02 17:48 357 查看
我们在使用Struts2的时候,相关Action的配置文件(一般以struts.xml作为配置文件),Struts2的StrutsPrepareAndExecuteFilter过滤器会到工程类路径(WEB-INF/classes目录下)找此配置文件。

这样,在类路径下有很多的xml配置文件,不便于维护,我们一般会将自定义的struts.xml放到特别的目录下,比如放到WEB-INF/conf目录下。此时,我们在web.xml里的struts过滤器会这样配置:

<!-- 定义Struts2的核心Filter -->
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>
			org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
		</filter-class>
		<init-param>  
        	<param-name>config</param-name>  
        	<param-value>struts-default.xml,struts-plugin.xml,../conf/struts.xml</param-value>  
    	</init-param>
	</filter>
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>


之后,如果要加更多的struts配置,可以以这样的方式配置config对应的配置文件值,也可以在struts.xml中,以include标签配置额外的配置文件:

<struts>
        <include file="../conf/other-struts.xml"/><!--注意:这里也是相对类路径配置-->
	...
    </struts>


可以看出来,这样配置起来,要么struts.xml里,充斥大量的Action配置,要么就充斥很多include标签。而且还需要关注各种路径问题(尤其是,如果我们需要按照Action类的包路径关系,在config目录下也按照包路径创建文件夹,将相应的struts配置文件放到对应包下时,路径问题会令人头晕)。

对此,我们可以考虑能否从过滤器初始化配置文件的处理机制上,进行改进,来实现无需额外配置,让过滤器自动“搜索”struts配置文件。

我们先来说明一种配置文件的放置方式。在每一个Action类的包下,创建一个conf目录,专门放struts.xml配置文件。这样,我们的action类与配置文件在一起管理,十分灵活方便。接下来就是如何实现全路径搜索struts配置文件的问题了。

首先要分析下,StrutsPrepareAndExecuteFilter过滤器如何实现配置文件查找的。经分析,在org/apache/struts2/dispatcher/ng/InitOperations.java类createDispatcher方法中,做了路径查找工作。这里可以看下createDispatcher方法的实现,具体调用关系请参阅相关源码:

/**
     * Create a {@link Dispatcher}
     */
    private Dispatcher createDispatcher( HostConfig filterConfig ) {
        Map<String, String> params = new HashMap<String, String>();
        for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
            String name = (String) e.next();
            String value = filterConfig.getInitParameter(name);
            params.put(name, value);
        }
        return new Dispatcher(filterConfig.getServletContext(), params);
    }


这里会将struts的配置文件以“,”分隔放到一个字符串中,封装到params这个Map中。

在这里,我们考虑在return操作之前,再做个全路径搜索,将其他struts.xml配置文件的全路径拼装到配置文件字符串中。直接修改InitOperations.java类的方式不利于lib库的管理,因此考虑使用继承的手段,重写StrutsPrepareAndExecuteFilter过滤器init方法,和InitOperations.java类的createDispatcher方法。

继承InitOperations的类(不妨命名为MyInitOperations),覆盖private Dispatcher createDispatcher( HostConfig filterConfig )方法,参考实现如下:

/**
     * 覆盖原方法
     */
    private Dispatcher createDispatcher(HostConfig hostConfig)
    {
        Map<String, String> params = new HashMap<String, String>();
        String name;
        String value;
	//原逻辑保留
        for (Iterator< ? > e = hostConfig.getInitParameterNames(); e.hasNext(); params.put(name,
            value))
        {
            name = (String) e.next();
            value = hostConfig.getInitParameter(name);
        }
        parseStrutsConfig(hostConfig, params);
        return new Dispatcher(hostConfig.getServletContext(), params);

    }

    /**
     * 获取所有配置文件的路径
     */
    private void parseStrutsConfig(HostConfig hostConfig, Map<String, String> m)
    {
        String home = hostConfig.getServletContext().getRealPath("/");
        home.replace("//", "/");
        if (home.startsWith("/"))
        {
            home = home + "/";
        }
	//初始化
        StringBuilder strutsPath = new StringBuilder("struts-default.xml,struts-plugin.xml");
        getStrutsPath(new File(home), strutsPath);
        m.put("config", strutsPath.toString());
    }

    /**
     * 获取工程下所有的struts配置文件
     */
    private void getStrutsPath(File file, StringBuilder pathBuilder)
    {
        //file为空,则不操作
	if (null == file)
        {
            return;
        }
        File[] files = file.listFiles();
        for (int i = 0; i < files.length; i++)
        {
            File f = files[i];
	    //如果为目录文件,递归调用本方法
            if (f.isDirectory())
            {
                getStrutsPath(f, pathBuilder);
                continue;
            }
	    //解析文件名:以struts.xml结尾,则拼接到路径字符串中
            String fName = files[i].getName();
            if (fName.endsWith("struts.xml"))
            {
                pathBuilder.append(",");
		//绝对路径
                pathBuilder.append(files[i].getAbsolutePath());
            }
        }
    }


StrutsPrepareAndExecuteFilter类init方法源码如下:

public void init(FilterConfig filterConfig) throws ServletException {
        InitOperations init = new InitOperations();
        Dispatcher dispatcher = null;
        try {
            FilterHostConfig config = new FilterHostConfig(filterConfig);
            init.initLogging(config);
            dispatcher = init.initDispatcher(config);
            init.initStaticContentLoader(config, dispatcher);

            prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
            execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
            this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

            postInit(dispatcher, filterConfig);
        } finally {
            if (dispatcher != null) {
                dispatcher.cleanUpAfterInit();
            }
            init.cleanup();
        }
    }


继承类(假设为MyStrutsPrepareAndExecuteFilter)重写此方法,InitOperations init = new InitOperations();操作改为MyInitOperations init = new MyInitOperations();即可。

这里有几点使用说明:

1. web.xml的struts核心过滤器需配置为MyStrutsPrepareAndExecuteFilter这个继承类;

2. struts配置文件必须以"struts.xml"结尾,用以区分其它配置文件;

3. 只要绝对路径不同,配置文件使用相同的文件名(如,都以"struts.xml"作为配置文件名)没有影响;

4. 配置文件在类加载路径即其子路径下,都可以解析得到;

5. 若需要解析非类加载路径目录,需要参考此方式,根据相对路径思想,得到新的目录file,再次调用getStrutsPath(File file, StringBuilder pathBuilder)方法即可。

使用继承和全路径遍历的思想来实现,看起来还是比较简单易懂的。这样,我们的类加载路径下,全路径搜索struts配置文件就实现了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: