使用struts2注解(struts2-convention-plugin-2.1.8.1)无配置开发的web项目,在tomcat里面运行没有问题,移植到jboss后出现:no result defined for action异常,无法访问action,上google查询资料,找到相应解决方案。 Jboss使用了vfs,于是于是URL的protocol都变成了vfsfile, vfszip等等。 查看xword的源码,在类com.opensymphony.xwork2.util.finder.ClassFinder的 122行左右,里面是写死的,"jar".equals(location.getProtocol(), "file".equals(location.getProtocol()。 解决方法:由于不能影响到非jboss server,如tomcat,所以不好改写ClassFinder。采用改写struts2 convention插件的方案,替换org.apache.struts2.convention.ActionConfigBuilder 如下:
<bean type="org.apache.struts2.convention.ActionConfigBuilder" name="convention" class="com.sunyard.ices.web.actions.jxc.MyActionConfigBuilder"/>
MyActionConfigBuilder类的内容如下:
package com.sunyard.ices.web.actions.jxc; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts2.convention.PackageBasedActionConfigBuilder; import com.opensymphony.xwork2.ObjectFactory; import com.opensymphony.xwork2.config.Configuration; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.finder.ClassFinder; import com.opensymphony.xwork2.util.finder.Test; public class MyActionConfigBuilder extends PackageBasedActionConfigBuilder { private static Log log = LogFactory.getLog(MyActionConfigBuilder.class); private static final String BASE_FILE = "struts.xml"; private String[] actionPackages; private String[] packageLocators; public static String classPath = ""; /** * * @param configuration * @param container * @param objectFactory * @param redirectToSlash * @param defaultParentPackage */ @Inject public MyActionConfigBuilder(Configuration configuration, Container container, ObjectFactory objectFactory, @Inject("struts.convention.redirect.to.slash") String redirectToSlash, @Inject("struts.convention.default.parent.package") String defaultParentPackage) { super(configuration, container, objectFactory, redirectToSlash, defaultParentPackage); } /** * * @param actionPackages * (Optional) An optional list of action packages that this * should create * * configuration for. * */ @Inject(value = "struts.convention.action.packages", required = false) public void setActionPackages(String actionPackages) { super.setActionPackages(actionPackages); if (!"".equals(actionPackages.trim())) { this.actionPackages = actionPackages.split("\\s*[,]\\s*"); } } /** * * @param packageLocators * (Optional) A list of names used to find action packages. * */ @Inject(value = "struts.convention.package.locators", required = false) public void setPackageLocators(String packageLocators) { super.setPackageLocators(packageLocators); this.packageLocators = packageLocators.split("\\s*[,]\\s*"); } @Override @SuppressWarnings("unchecked") protected Set<Class> findActions() { Set<Class> classes = new HashSet<Class>(); try { // ClassFinder finder = new ClassFinder(getClassLoaderForFinder(), buildUrls(), true); ClassFinder finder = new ClassFinder(getClassLoaderInterface(), buildUrls(), true); if (actionPackages != null) { for (String packageName : actionPackages) { Test<ClassFinder.ClassInfo> test = getPackageFinderTest(packageName); classes.addAll(finder.findClasses(test)); } } // package locators if (packageLocators != null) { for (String packageLocator : packageLocators) { Test<ClassFinder.ClassInfo> test = getPackageLocatorTest(packageLocator); classes.addAll(finder.findClasses(test)); } } } catch (Exception ex) { if (log.isErrorEnabled()) { log.error("Unable to scan named packages", ex); } } return classes; } private List<URL> buildUrls() throws MalformedURLException { List<URL> urls = new ArrayList<URL>(); URL classesUrl = getClassLoader().getResource(BASE_FILE); if (classesUrl == null) { throw new IllegalStateException("File " + BASE_FILE + " was not found. The folder WEB-INF/classes discovery base on file classes/" + BASE_FILE + "."); } String baseFilePath = classesUrl.getFile(); URL url = new URL("file", "", baseFilePath.substring(0, baseFilePath.indexOf(BASE_FILE))); System.out.println(url); if (log.isInfoEnabled()) { classPath = url.getFile(); log.info("Struts2 ActionConfigBuilder, classes directory: " + classPath); } System.out.println("classPath = " + classPath); System.out.println(url.toExternalForm()); urls.add(url); return urls; } /*private ClassLoader getClassLoader() { return Thread.currentThread().getContextClassLoader(); }*/ }
,
上述解决了struts2注解开发方式无法访问action的问题
但是jboss对spring的支持也有问题,解决方案
需引入jboss-spring-int-vfs.jar
在web.xml 加入配置:
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.jboss.spring.vfs.context.VFSXmlWebApplicationContext
</param-value>
</context-param>
这样就不会有问题,如果要在tomcat运行需要去掉web的配置