Restlet实战(三)使用Component让不同的Application对应不同的资源
在Restlet实战(二)我给出的例子中,把Order和Customer两个资源attach到Order Application上,看如下代码:
public class OrderApplication extends Application {
@Override
public synchronized Restlet createRoot() {
Router router = new Router(getContext());
router.attach("/order/{orderId}/{subOrderId}", OrderResource.class);
router.attach("/customer/{custId}", CustomerResource.class);
return router;
}
}
这显而易见不是一个好的应用,从关注点来看,Order Resource应该attach到Order Application,那么对应Customer Resource应该有一个Customer Application与之对应。
ok,基于这样的思路,我们从OrderApplication删除如下代码:
router.attach("/customer/{custId}", CustomerResource.class);
另外我们创建一个CustomerApplication,并包含上述代码:
public class CustomerApplication extends Application{
@Override
public synchronized Restlet createRoot() {
Router router = new Router(getContext());
router.attach("/customers/{custId}", CustomerResource.class);
return router;
}
}
有了CustomerApplication,那么如何设置才能生效呢?根据之前的配制,很容易想到的是在web.xml中把CustomerApplication配制进去,事实上是不行的,看看ServerServlet类里面这段代码:
private static final String APPLICATION_KEY = "org.restlet.application";
protected Application createApplication(Context parentContext) {
Application application = null;
final String applicationClassName = getInitParameter(APPLICATION_KEY,
null);
这段代码是根据参数名org.restlet.application来获得配制在web.xml中application,而之前我们已经配制了OrderApplication,所以,我们不能再把CustomerApplication配制的参数名设置为org.restlet.application。那么在ServerServlet加载application的时候,就加载不到。
那么怎么作能让这两个Application生效呢?答案是Component,实际上,从上一篇文章中的图可以看出,一个Component可以设置多个Virtual Host,而一个Virtual Host能attach多个Application。
至于使用Component的做法有两种,一种是在web.xml中配制一个名字为“org.restlet.component”的context参数,例如:
<context-param> <param-name>org.restlet.component</param-name> <param-value>com.mycompany.MyComponent</param-value> </context-param>
另外一种是,WEB-INF/下存在restlet.xml,可以在这个xml文件里定义包含application和connector的Commponent。
下面就第二种方式来解决上面出现的问题,首先在WEB-INF/下建立一个名为restlet.xml,这个名字不能改变成别的名字,为啥呢?仍然看一下ServerServlet里面的一段代码:
protected Component createComponent() {
Component component = null;
// Look for the Component XML configuration file.
Client client = createWarClient(new Context(), getServletConfig());
Response response = client.get("war:///WEB-INF/restlet.xml");
既然不让改,不改好了,在restlet.xml里面放入配制Component的代码:
<?xml version="1.0"?> <component xmlns="http://www.restlet.org/schemas/1.1/Component" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.restlet.org/schemas/1.1/Component"> <!-- <client protocol="CLAP" /> <client protocol="FILE" /> <client protocols="HTTP HTTPS" /> <server protocols="HTTP HTTPS" port="8080"/> --> <defaultHost> <attach uriPattern="/customers/{custId}" targetClass="com.mycompany.restlet.application.CustomerApplication" /> <attach uriPattern="/orders/{orderId}/{subOrderId}" targetClass="com.mycompany.restlet.application.OrderApplication" /> <!-- <attach uriPattern="/efgh/{xyz}" targetDescriptor="clap://class/org/restlet/test/MyApplication.wadl" /> --> </defaultHost> </component>
看上面的配制文件,很清楚的我们能知道,如果在浏览器输入http://localhost:8080/restlet/customers/1,那么CustomerApplication这个类应该被访问到。
咦,好象有点不对,好像CustomerApplication里面在attach资源的时候,也指定了同样的URL(/customers/{custId}),那么是当前这两个URL定义的URL重复了?还是有别的含义?
我们可以这样理解,在restlet.xml中定义的URL附加到Context上,而在application里面定义的URL会附加到restlet.xml中定义的URL上。
例如,如果想通过http://localhost:8080/restlet/customers/1 来使用CustomerResource,则需要在CustomerApplication中有如下代码:
router.attach("", CustomerResource.class);
而如果想通过http://localhost:8080/restlet/customers/1/orders/2 来使用CustomerResource,则需要在CustomerApplication中定义如下代码:
router.attach("/orders/{orderId}", CustomerResource.class);
Ok,让我们测试一下,首先修改
CustomerApplication.java
public class CustomerApplication extends Application{
@Override
public synchronized Restlet createRoot() {
Router router = new Router(getContext());
//router.attach("", CustomerResource.class);
router.attach("/orders/{orderId}", CustomerResource.class);
return router;
}
}
CustomerResource.java
public class CustomerResource extends Resource {
String customerId;
String orderId;
public CustomerResource(Context context, Request request, Response response) {
super(context, request, response);
customerId = (String) request.getAttributes().get("custId");
orderId = (String) request.getAttributes().get("orderId");
// This representation has only one type of representation.
getVariants().add(new Variant(MediaType.TEXT_PLAIN));
}
@Override
public Representation getRepresentation(Variant variant) {
Representation representation = new StringRepresentation(
"The customer which id is " + customerId
+ " has the order which id : " + orderId,
MediaType.TEXT_PLAIN);
return representation;
}
}
输入http://localhost:8080/restlet/customers/1/orders/2,结果如下:
The customer which id is 1 has the order which id : 2
请注意,上面CustomerApplicaiton被注释的一行代码
router.attach("", CustomerResource.class);
如果反注释这行代码,则所有基于http://localhost:8080/restlet/customers/1/****(除了/customers/{custId}/orders/{orderId} )的访问都会路由到同一个资源(CustomerResource),换句话说,如果我访问一个我没有定义的URL,如/customers/{customerId}/orders,则也会被路由到CustomerResource,这是不对的。。所以,应慎用之。
总结,现在我们可以分别用不同的Application来管理不同的资源了,并采用restlet.xml这种方式来定义包含applicaiton和connector的component.
上一篇: 不同浏览器隐藏滚动条样式
下一篇: css 自定义浏览器滚动条样式