You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AEM内容即服务:Java模型下URL链接映射的处理方案咨询

解决AEM Java模型JSON Exporter中的自动链接映射问题

这确实是AEM Content as a Service开发里的高频痛点——总不想在每个模型的每个链接字段里都重复写ResourceResolver.map(request, path)对吧?给你几个优雅的自动化方案,彻底摆脱重复代码:

方案1:自定义Jackson序列化器(最推荐)

利用Jackson的自定义序列化能力,给所有需要映射的链接字段自动处理路径转换,不用在模型里写任何额外逻辑。

步骤1:编写自定义序列化器

创建一个继承JsonSerializer<String>的类,在序列化时自动调用当前请求的ResourceResolver.map():

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import org.apache.sling.api.resource.ResourceResolver;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.apache.sling.models.annotations.injectorspecific.Self;

public class MappedLinkSerializer extends JsonSerializer<String> {

    @Self
    private HttpServletRequest request;

    @Override
    public void serialize(String path, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (path == null || path.isEmpty()) {
            gen.writeNull();
            return;
        }

        ResourceResolver resolver = request.getResourceResolver();
        // 处理页面路径或资源路径
        String mappedPath = resolver.map(request, path);
        // 若需外部化绝对URL,可结合Externalizer
        // Externalizer externalizer = resolver.adaptTo(Externalizer.class);
        // String externalUrl = externalizer.publishLink(resolver, mappedPath);
        gen.writeString(mappedPath);
    }
}

步骤2:在模型字段上添加注解

在你的Java模型中,给需要映射的链接字段加上@JsonSerialize注解,指定用上面的序列化器:

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;

@Model(adaptables = Resource.class, resourceType = "your-project/components/content/link-component")
public class LinkModel {

    @ValueMapValue
    private String pagePath;

    @JsonSerialize(using = MappedLinkSerializer.class)
    public String getPagePath() {
        return pagePath;
    }
}

这样当你访问.model.json时,pagePath字段会自动被转换成映射后的URL,完全不用在模型里手动调用map()。

方案2:扩展AbstractModelExporter做全局处理

如果你的项目里大部分模型都需要处理链接,可以扩展AEM的AbstractModelExporter,在序列化前统一扫描并处理所有符合规则的字段(比如字段名包含"link"或"path"):

import com.adobe.cq.export.json.AbstractModelExporter;
import com.adobe.cq.export.json.ExporterConstants;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Model(adaptables = Resource.class)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class GlobalMappedModelExporter extends AbstractModelExporter {

    @Override
    protected Map<String, Object> exportModel(Object model, HttpServletRequest request) {
        Map<String, Object> exportMap = super.exportModel(model, request);
        ResourceResolver resolver = request.getResourceResolver();

        // 遍历所有字段,自动处理包含"link"或"path"的字段
        for (Map.Entry<String, Object> entry : exportMap.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value instanceof String && (key.contains("link") || key.contains("path"))) {
                String mappedPath = resolver.map(request, (String) value);
                entry.setValue(mappedPath);
            }
        }
        return exportMap;
    }
}

之后让你的所有模型继承这个自定义Exporter,就能全局自动处理链接映射了。

方案3:自定义注解+注入处理器

创建一个自定义注解@MappedLink,然后通过Sling Models的注解处理器,在模型初始化时就把路径转换成映射后的URL:

步骤1:定义自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MappedLink {
}

步骤2:编写注解处理器

import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import org.apache.sling.models.spi.injectorspecific.AbstractInjectAnnotationProcessor2;
import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor2;
import org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Type;

public class MappedLinkInjector implements StaticInjectAnnotationProcessorFactory {

    @Override
    public InjectAnnotationProcessor2 createAnnotationProcessor(Class<?> adapterClass, Type type, java.lang.annotation.Annotation annotation, InjectionStrategy injectionStrategy) {
        return new AbstractInjectAnnotationProcessor2() {
            @Override
            public Object postProcess(Object value, String name, Object declaredType, InjectionStrategy injectionStrategy) {
                if (value instanceof String && !((String) value).isEmpty()) {
                    // 获取当前请求的ResourceResolver
                    HttpServletRequest request = (HttpServletRequest) org.apache.sling.api.request.RequestContext.getRequest();
                    ResourceResolver resolver = request.getResourceResolver();
                    return resolver.map(request, (String) value);
                }
                return value;
            }
        };
    }
}

步骤3:在模型中使用注解

import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;

@Model(adaptables = Resource.class, resourceType = "your-project/components/content/button")
public class ButtonModel {

    @ValueMapValue
    @MappedLink
    private String linkPath;

    public String getLinkPath() {
        return linkPath; // 这里已经是映射后的URL了
    }
}

关键注意事项

  • 必须使用当前请求的ResourceResolver:绝对不能用全局的ResourceResolverFactory获取的resolver,因为不同请求(比如作者/发布、不同域名)的映射规则可能不同,必须从当前HttpServletRequest中获取。
  • 外部化链接:如果需要生成发布环境的绝对URL,可以结合AEM的Externalizer服务,在序列化或注入时调用externalizer.publishLink(resolver, mappedPath)。

内容的提问来源于stack exchange,提问作者Dr. Hans-Peter Störr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:19:15