Adobe CQ5 custom servlet path

泪湿孤枕 提交于 2019-12-11 09:52:53

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!