【问题标题】:Is it possible to place variables into a resource path within a sling servlet?是否可以将变量放入 sling servlet 内的资源路径中?
【发布时间】:2014-01-08 00:18:25
【问题描述】:

我们正在尝试为外部端点提供一个干净的 URI 结构,以便从 CQ5 中提取 json 信息。

例如,如果您想获取有关特定用户历史记录的信息(假设您有权限等),理想情况下,我们希望端点能够执行以下操作:

/bin/api/user/abc123/phone/555-klondike-5/history.json

在 URI 中,我们将指定 /bin/api/user/{username}/phone/{phoneNumber}/history.json 以便很容易利用调度程序使缓存更改等无效,而不会使大范围无效缓存信息。

我们想使用 sling servlet 来处理请求,但是,我不知道如何将变量放入路径中。

如果有来自 JaxRS 的 @PathParam 之类的东西可以添加到 sling 路径变量中,那就太好了,但我怀疑它不可用。

我们想到的另一种方法是使用选择器来识别我们何时访问 api,因此可以从路径中返回我们想要的任何内容,但它需要一个单一的 sling servlet 来处理所有请求,所以我对这种方法不满意,因为它将许多不相关的代码粘合在一起。

对此的任何帮助将不胜感激。


更新:

如果我们要使用 OptingServlet,然后在接受函数中添加一些逻辑,我们可以堆叠一系列 sling servlet,并使用正则表达式从路径中做出接受决定。

然后在执行过程中,可以为变量解析路径本身。

【问题讨论】:

    标签: aem sling


    【解决方案1】:

    如果您提供的数据来自 JCR 存储库,那么最好按照您希望的 URL 来构建它,这是使用 Sling 做事的推荐方式。

    如果数据是外部的,您可以创建一个自定义的 Sling ResourceProvider,挂载在 /bin/api/user 路径上,并根据路径的其余部分获取或生成相应的数据。

    Sling 测试套件的 PlanetsResourceProvider 就是一个简单的示例,请参阅 http://svn.apache.org/repos/asf/sling/trunk/launchpad/test-services/src/main/java/org/apache/sling/launchpad/testservices/resourceprovider/

    https://sling.apache.org/documentation/the-sling-engine/resources.html 的 Sling 资源文档记录了一般资源解析机制。

    【讨论】:

      【解决方案2】:

      现在可以将 jersy(JAX-RS) 与 CQ 集成。我们能够创建原始原型来向世界说“你好”。

      https://github.com/hstaudacher/osgi-jax-rs-connector

      有了这个我们可以使用@PathParam 来映射请求

      感谢和问候, 圣

      【讨论】:

        【解决方案3】:

        没有直接的方法可以创建这样的动态路径。您可以在/bin/api/user.json 下注册servlet,并将路径的其余部分提供为suffix

        /bin/api/user.json/abc123/phone/555-klondike-5/history
        ^                 ^
        |                 |
        servlet path      suffix starts here
        

        然后你可以手动解析后缀:

        @SlingServlet(paths = "/bin/api/user", extensions = "json")
        public class UserServlet extends SlingSafeMethodsServlet {
            public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
                String suffix = request.getRequestPathInfo().getSuffix();
                String[] split = StringUtils.split(suffix, '/');
                // parse split path and check if the path is valid
                // if path is not valid, send 404:
                // response.sendError(HttpURLConnection.HTTP_NOT_FOUND);
            }
        }
        

        【讨论】:

        • 您好 Tomek,感谢您的回复。不幸的是,我们的要求相当坚定,因为我们正在处理我们试图避免重写的遗留应用程序。
        • @Tomek Rękawek 我怀疑这是否是您建议的作为 CQ5 中 REST Web 服务的替代方案,假设某个外部应用程序工具想要通过 REST 访问并且我们正在提供这个 servlet,并且工具尝试为此 RESTWebservice(我们的 servlet)生成 WADL,但它失败了。那么你知道我们可以用什么方法来实现精确的 RESTful Web 服务,以便即使为该 REST URL 生成 WADL 也能成功完成?
        【解决方案4】:

        解决此问题的 RESTful 方法是将信息存储在您要使用的结构中。即 /content/user/abc123/phone/555-klondike-5/history/ 将包含该路径的所有历史节点。

        在那个用法中。您只需调用

        即可获得开箱即用的 json 响应
        /content/user/abc123/phone/555-klondike-5/history.json
        

        或者,如果您需要特定 json 格式的内容,您可以使用 sling 资源解析来使用自定义 json 响应。

        【讨论】:

        • 不幸的是,这是不可能的,因为我们正在处理将 userid 放在 restful 请求开头的遗留应用程序。我们无法将数据存储在那种图表中。
        【解决方案5】:

        很高兴分享这个!我已经工作了〜一个星期来解决这个问题,终于有了最好的答案。

        第一:尝试使用 Jersey

        kallada 建议的 osgi-jax-rs-connector 是最好的,但我无法让它在 Sling 8 上运行。我花了一整天的时间尝试,我所要展示的只是幽灵类未找到错误和依赖问题。

        解决方案:ResourceProvider

        Bertrand 的链接仅适用于尚未发布的 Sling 9。下面是您在 Sling 8 及更早版本中的操作方法!

        两个文件:

        • 资源提供者
        • 小服务程序

        资源提供者

        这样做的目的只是监听 /service 上的所有请求,然后在该虚拟路径上生成一个“资源”,而 JCR 中实际上并不存在该资源。

        @Component
        @Service(value=ResourceProvider.class)
        @Properties({
                @Property(name = ResourceProvider.ROOTS, value = "service/image"),
                @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;
        }
        }
        

        Servlet

        现在您只需编写一个 servlet 来处理来自该路径的任何资源 - 但这是通过处理具有由在该路径上侦听的 ResourceProvider 生成的资源类型的任何资源来完成的。

        @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();
                }
            }
        }
        

        显然,您的 servlet 会做一些更聪明的事情,例如更智能地处理“路径”字符串并可能生成 JSON。

        【讨论】:

          猜你喜欢
          • 2014-06-04
          • 1970-01-01
          • 1970-01-01
          • 2015-12-12
          • 1970-01-01
          • 2022-11-24
          • 2012-03-20
          • 2019-03-06
          • 1970-01-01
          相关资源
          最近更新 更多