基于GraphQL Java实现Sling Servlet:构建AEM数据查询接口
实现基于GraphQL Java的AEM Sling Servlet
以下是实现你需求的完整步骤,从Schema定义到Servlet开发,直接对接AEM数据:
1. 定义GraphQL Schema
先写出匹配你查询结构的Schema,明确查询字段、参数和返回类型:
type Query { content(path: String!): Content } type Content { pageTitle: String resourceType: String }
2. 实现DataFetcher(从AEM拉取数据核心逻辑)
这个类负责接收GraphQL查询的path参数,通过Sling的ResourceResolver从AEM中获取对应资源,提取所需属性:
import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import java.util.HashMap; public class ContentDataFetcher implements DataFetcher<Object> { private final ResourceResolver resourceResolver; public ContentDataFetcher(ResourceResolver resourceResolver) { this.resourceResolver = resourceResolver; } @Override public Object get(DataFetchingEnvironment env) throws Exception { String path = env.getArgument("path"); Resource targetResource = resourceResolver.getResource(path); if (targetResource == null) { return null; } // 提取AEM资源的属性,这里用HashMap封装返回,也可以用自定义POJO return new HashMap<String, Object>() {{ put("pageTitle", targetResource.getValueMap().get("jcr:title", String.class)); put("resourceType", targetResource.getResourceType()); }}; } }
3. 编写Sling Servlet处理GraphQL请求
Servlet负责接收POST请求、解析查询、执行GraphQL逻辑并返回JSON结果:
import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.servlets.HttpConstants; import org.apache.sling.api.servlets.SlingSafeMethodsServlet; import org.osgi.service.component.annotations.Component; import graphql.GraphQL; import graphql.schema.GraphQLSchema; import graphql.schema.idl.RuntimeWiring; import graphql.schema.idl.SchemaGenerator; import graphql.schema.idl.SchemaParser; import graphql.schema.idl.TypeDefinitionRegistry; import javax.servlet.Servlet; import java.io.BufferedReader; import java.io.IOException; import java.util.Map; import com.fasterxml.jackson.databind.ObjectMapper; @Component( service = Servlet.class, property = { "sling.servlet.methods=" + HttpConstants.METHOD_POST, "sling.servlet.paths=/bin/graphql/custom-content" // 自定义的Servlet访问路径 } ) public class CustomGraphQLServlet extends SlingSafeMethodsServlet { private volatile GraphQL graphQLInstance; private final ObjectMapper objectMapper = new ObjectMapper(); @Override protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException { // 懒加载GraphQL实例,避免启动时的资源依赖问题 if (graphQLInstance == null) { synchronized (this) { if (graphQLInstance == null) { graphQLInstance = buildGraphQL(request.getResourceResolver()); } } } // 读取请求体中的GraphQL查询语句 StringBuilder queryBuilder = new StringBuilder(); String line; BufferedReader reader = request.getReader(); while ((line = reader.readLine()) != null) { queryBuilder.append(line); } String graphqlQuery = queryBuilder.toString(); // 执行查询并获取结果 Map<String, Object> result = graphQLInstance.execute(graphqlQuery).toSpecification(); // 返回JSON格式响应 response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); objectMapper.writeValue(response.getWriter(), result); } private GraphQL buildGraphQL(ResourceResolver resourceResolver) { // 加载Schema定义(复杂场景建议从JCR文件或外部配置读取,这里硬编码做示例) String schemaDef = """ type Query { content(path: String!): Content } type Content { pageTitle: String resourceType: String } """; TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(schemaDef); RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring() .type("Query", wiring -> wiring .dataFetcher("content", new ContentDataFetcher(resourceResolver))) .build(); GraphQLSchema graphQLSchema = new SchemaGenerator().makeExecutableSchema(typeRegistry, runtimeWiring); return GraphQL.newGraphQL(graphQLSchema).build(); } }
4. 测试验证
发送POST请求到/bin/graphql/custom-content,请求体使用你提供的查询:
query { content(path: "/content/test/en") { pageTitle resourceType } }
返回结果会和你期望的格式完全一致:
{ "data": { "content": { "pageTitle": "English", "resourceType": "/apps/testproject/components/page" } } }
注意事项
- 权限控制:确保Servlet使用的
ResourceResolver有目标AEM路径的访问权限,必要时配置OSGi权限映射或调整Servlet的资源解析策略。 - 错误处理:可以在
ContentDataFetcher中添加异常捕获,返回GraphQL标准错误格式,比如资源不存在时返回明确的错误提示。 - 性能优化:对于高并发场景,建议缓存GraphQL实例,避免每次请求重复构建Schema和RuntimeWiring。
内容的提问来源于stack exchange,提问作者Prince Shivhare
相关产品推荐
相关产品推荐

