通过Restlet提供静态文件证明比它应该的更难。我怀疑与上下文初始化有一些深层次的问题,但我可能是错的。基本上,我还没有能够通过Directory
获得任何实际内容,尽管所有路由和所有经典的restlet工作正常。
核心问题看起来像是在日志消息中显示的:
WARNING: No client dispatcher is available on the context. Can't get the target URI: war:///
我尝试过一堆不同的基本网址,但这些网址似乎都没有区别。当我调试时,确定getClientDispatcher()
返回null。
当我修改Spring初始化(错误地)以使用原始上下文而不是子上下文时,我没有收到此警告,并且显示了目录列表,但它也显示了大约7条SEVERE
条消息关于这是一个安全风险。
My Spring XML看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="trackerComponent" class="org.restlet.ext.spring.SpringComponent">
<property name="defaultTarget" ref="trackerApplication" />
</bean>
<bean id="trackerComponentChildContext" class="org.restlet.Context">
<lookup-method name="createChildContext" bean="trackerComponent.context" />
</bean>
<bean id="trackerApplication" class="ca.uhnresearch.pughlab.tracker.application.TrackerApplication">
<property name="root" ref="router" />
</bean>
<!-- Define the router -->
<bean name="router" class="org.restlet.ext.spring.SpringRouter">
<constructor-arg ref="trackerComponentChildContext" />
<property name="attachments">
<map>
<entry key="/" value-ref="staticsDirectory" />
</map>
</property>
</bean>
<bean id="staticsDirectory" class="ca.uhnresearch.pughlab.tracker.resource.SpringDirectory">
<constructor-arg ref="router" />
<constructor-arg value="war:///" />
<property name="listingAllowed" value="true" />
</bean>
...
我的类SpringDirectory只是一个从父Context
提供Router
的包装器,就像其他Spring助手一样,它似乎工作正常:传递相同的上下文 - 和没有任何子上下文有getClientDispatcher()
有效。
如果需要,请参阅web.xml
的部分相关部分。我不完全确定为什么我需要添加FILE以允许客户端访问(我想通过Web容器提供服务)但我确实尝试使用文件:URL也没有我能看到的任何差异,除了我必须在不寻常的地方添加额外的设置。
<servlet>
<servlet-name>tracker</servlet-name>
<servlet-class>org.restlet.ext.spring.SpringServerServlet</servlet-class>
<init-param>
<param-name>org.restlet.clients</param-name>
<param-value>HTTP HTTPS FILE</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>tracker</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
我真的很感激这方面的建议 - 我实际上花了更多的时间试图获得一个index.html,而不是我在所有Restlets上的组合,所以任何想法或指针都会是非常欢迎。
更新
Thierry的回复很有帮助,但我仍然遇到一些问题,仍然无法提供静态文件。唯一不同的是,我没有test.CustomSpringServerServlet
- 而且我并不完全清楚我需要一个,因为额外的init-param
似乎被默认接受。
当使用Jetty JAR文件(mvn jetty:run-war
)运行时,我现在得到一个堆栈回溯:
WARNING: Exception or error caught in status service
java.lang.NoSuchMethodError: org.restlet.Context.getClientDispatcher()Lorg/restlet/Restlet;
at ca.uhnresearch.pughlab.tracker.restlets.DirectoryFactoryBean$1.getContext(DirectoryFactoryBean.java:16)
at org.restlet.Restlet.handle(Restlet.java:220)
at org.restlet.resource.Finder.handle(Finder.java:449)
at org.restlet.resource.Directory.handle(Directory.java:245)
at org.restlet.routing.Filter.doHandle(Filter.java:156)
...
这个堆栈回溯很容易是我更新的结果 - 我现在正在使用Restlets 2.3.1和Spring 3.1.4,因为它与之前的警告非常相似。
奇怪的是,我没有从mvn jetty:run
得到这个,现在矛盾的是现在在顶层提供目录列表,但仍拒绝提供任何文件。这样就可以确认WAR协议能够访问某些内容。 war://协议没有高度记录,因此我猜测它只是从战争内容中提供服务,而且它当然还不能做到。
我仍然希望file://
协议能够正常工作 - 说实话,任何静态文件的服务都会非常棒,我无法理解。但是,尝试这仍然会导致错误:
WARNING: The protocol used by this request is not declared in the list of client connectors. (FILE). In case you are using an instance of the Component class, check its "clients" property.
我真的不明白,因为它位于web.xml
的客户列表中,而且其他任何地方我都无法理解。
这已证明足够严重,我觉得我应该把Github回购一起放给人们玩。
答案 0 :(得分:1)
编辑:我完全更新了我的答案,描述了如何解决问题
我更深入地研究了你的问题,我可以重现它。实际上,在Spring中配置目录本身时会出现问题。事实上,它位于负责带来客户调度员的环境中。
以下是更多详情。事实上,在默认或Spring servlet中创建Restlet组件时,会自动注册客户端协议WAR
。请参阅方法ServerServlet#init(Component)
。因此,相应的客户机调度程序在组件的上下文中设置。
因此,在实例化它时,需要在Directory
的构造函数中传递此上下文。我重新设计了Spring配置,以展示如何解决您的问题:
public class DirectoryFactoryBean implements FactoryBean<Directory> {
private Component component;
@Override
public Directory getObject() throws Exception {
Directory directory = new Directory(component.getContext(), "war:///") {
@Override
public Context getContext() {
// Display if the client dispatcher is correctly set!
System.out.println(">> getContext().getClientDispatcher() = "+super.getContext().getClientDispatcher());
return super.getContext();
}
};
directory.setListingAllowed(true);
return directory;
}
@Override
public Class<?> getObjectType() {
return Directory.class;
}
@Override
public boolean isSingleton() {
return true;
}
public Component getComponent() {
return component;
}
public void setComponent(Component component) {
this.component = component;
}
}
这是类``:
的内容public class CustomSpringServerServlet extends SpringServerServlet {
@Override
protected void init(Application application) {
super.init(application);
}
@Override
protected void init(Component component) {
super.init(component);
ClientList list = component.getClients();
for (Client client : list) {
System.out.println(">> client = "+client);
}
}
}
以下是web.xml
文件中的配置:
<web-app>
<context-param>
<param-name>org.restlet.application</param-name>
<param-value>org.restlet.tutorial.MyApplication</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>tracker</servlet-name>
<servlet-class>test.CustomSpringServerServlet</servlet-class>
<init-param>
<param-name>org.restlet.component</param-name>
<param-value>myComponent</param-value>
</init-param>
<init-param>
<param-name>org.restlet.clients</param-name>
<param-value>HTTP HTTPS FILE</param-value>
</init-param>
</servlet>
</web-app>
以下是相应的Spring配置:
<bean id="myComponent" class="org.restlet.ext.spring.SpringComponent">
<property name="defaultTarget" ref="router" />
</bean>
<bean name="router" class="org.restlet.ext.spring.SpringRouter">
<property name="attachments">
<map>
<entry key="/dir" value-ref="staticsDirectory" />
</map>
</property>
</bean>
<bean id="staticsDirectory" class="test.DirectoryFactoryBean">
<property name="component" ref="myComponent" />
</bean>
希望它有所帮助, 亨利