问题
I am trying to add some functionality to json processing for some nodes. So I wrote custom servlet extended from SlingSafeMethodsServlet
which I need to be executed when user makes GET for the following url : /data/events/any_sequence/any_sequence.json or /data/events/any_sequence/any_sequence.infinity.json or for example /data/events/any_sequence/any_sequence.2.json where any_sequence of course means any valid sequence of symbols.
The problem is that I cannot find in the sling docs how to map this template like urls.
I've been trying to set properties like this:
@Component
@Service
@Properties({
@Property(name = "sling.servlet.resourceTypes", value = "data/events/-/-"),
@Property(name = "sling.servlet.extensions", value = "json"),
@Property(name = "sling.servlet.methods", value = "GET"),
@Property(name = "service.description", value = "JSON advanced renderer")
})
But it didn't help. I checked felix console and found out that my service had started and running, so the problem is how to set url mappings. So my question is how to set url mapping in my case to invoke doGet of my custom servlet ?
Thanks.
回答1:
As far as I understand CQ5 does not provide ability to map custom servlets on wildcard urls. The only way to accomplish goal similiar to one I needed is to use some unique for this servlet selector like this:
@Component
@Service
@Properties({
@Property(name = "sling.servlet.resourceTypes", value = "sling/servlet/default"),
@Property(name = "sling.servlet.extensions", value = "json"),
@Property(name = "sling.servlet.selectors", value = "advanced"),
@Property(name = "sling.servlet.methods", value = "GET"),
@Property(name = "service.description", value = "JSON advanced renderer")
})
This code means that if I'll try to make GET on some node with *.advanced.json
selector and extension then request will be forwarded to my custom servlet.
See http://apache-sling.73963.n3.nabble.com/Register-servlet-for-subtree-td84106.html
回答2:
I've solved this, exactly as the original poster was hoping. All other answers are effectively "it can't be done" or "here's a way to do it if you're willing to dirty up your clean RESTful API with selectors"
If you want to keep the clean API you envisioned, here's how. This works also for Apis without extensions, like /myservice/mythings/123123 , where 123123 is some dynamic ID
Create Two Files:
- ResourceProvider
- Servlet
The ResourceProvider
The purpose of this is only to listen to all requests at /data/events and then produce a "Resource" at that virtual path, which doesn't actually exist in the JCR.
@Component
@Service(value=ResourceProvider.class)
@Properties({
@Property(name = ResourceProvider.ROOTS, value = "data/events"),
@Property(name = ResourceProvider.OWNS_ROOTS, value = "true")
})
public class ImageResourceProvider implements ResourceProvider {
@Override
public Resource getResource(ResourceResolver resourceResolver, String path) {
AbstractResource abstractResource;
abstractResource = new AbstractResource() {
@Override
public String getResourceType() {
return TypeServlet.RESOURCE_TYPE;
}
@Override
public String getResourceSuperType() {
return null;
}
@Override
public String getPath() {
return path;
}
@Override
public ResourceResolver getResourceResolver() {
return resourceResolver;
}
@Override
public ResourceMetadata getResourceMetadata() {
return new ResourceMetadata();
}
};
return abstractResource;
}
@Override
public Resource getResource(ResourceResolver resourceResolver, HttpServletRequest httpServletRequest, String path) {
return getResource(resourceResolver , path);
}
@Override
public Iterator<Resource> listChildren(Resource resource) {
return null;
}
}
The Servlet
Now you just write a servlet which handles any of the resources coming from that path - but this is accomplished by handling any resources with the resource type which is produced by the ResourceProvider listening at that path.
@SlingServlet(
resourceTypes = TypeServlet.RESOURCE_TYPE,
methods = {"GET" , "POST"})
public class TypeServlet extends SlingAllMethodsServlet {
static final String RESOURCE_TYPE = "mycompany/components/service/myservice";
@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
final String [] pathParts = request.getResource().getPath().split("/");
final String id = pathParts[pathParts.length-1];
response.setContentType("text/html");
PrintWriter out = response.getWriter();
try {
out.print("<html><body>Hello, received this id: " + id + "</body></html>");
} finally {
out.close();
}
}
}
回答3:
This is the syntax I have used to accomplish similar tasks:
@Component(immediate = true, description = "JSON advanced renderer")
@Service(value = javax.servlet.Servlet.class)
@Properties(value = {
@Property(name = "sling.servlet.extensions", value = { "json" }),
@Property(name = "sling.servlet.methods", value = { "GET" }),
@Property(name = "sling.servlet.paths", value = {
"/data/events/any_sequence/any_sequence",
"/data/events/any_sequence/any_sequence.infinity",
"/data/events/any_sequence/any_sequence.2"
})
})
回答4:
I had a similar problem and I needed wildcards I used
@Service
@Component
@Properties({
@Property(name = "sling.servlet.paths", value = "/bin/resolver/gb"),
@Property(name = "sling.servlet.extensions", value = "*")
})
public class Test extends SlingAllMethodsServlet {
@Override
public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.print("The path you used is:" + request.getPathInfo());
}
}
Call is [server]:[port]/bin/resolver/gb.[wildcard]
So what can be done is : [server]:[port]/bin/resolver/gb.en/something
Everything after "." is considered an extension so need to be handled in the servlet, but helped me achieve my requirement
回答5:
It seems that the path of your servlet is same.Just selectors are varying. When used with path, other things are ignored in SlingServlet. So using something like this should serve the purpose: @SlingServlet(paths = " /data/events/any_sequence/any_sequence", extensions = "json")
You would need to add /data in execution paths from Felix console(/system/console/configMgr) as is it not there by default in Apache Sling Servlet Resolver property
回答6:
This can be accomplished using the desired external URI pattern by constructing a Sling mapping or Apache rewrite to effectively move the JSON extension to just after "data" in the URI, so the single servlet at "/data" ends up receiving the arbitrary path via the suffix of the request. If you are also using data from selectors, you'll need to move them along with the extension.
来源:https://stackoverflow.com/questions/11194586/adobe-cq5-custom-servlet-path