Freemarker Fallback 无法在 Spring Boot 中使用多个模板加载器

问题描述 投票:0回答:1

我正在开发一个 Spring Boot 项目,我使用 Freemarker 进行模板化。我在 Freemarker 的配置中配置了多个 TemplateLoader,以从两个不同的 CDN URL 加载模板:baselineUrl 和dynamicUrl。这个想法是,如果在baselineUrl中找不到模板,它应该回退到dynamicUrl。

这是我的配置:

@Slf4j
@Configuration
@ConfigurationProperties("email")
@Data
public class FtlConfiguration {
  // https://dynamic/bhnpay-static/notification-template/ftl
  private String baselineUrl;
  // https://baseline/bhnpay-static/notification-template/ftl
  private String dynamicUrl;
  private long retentionTimeMillis;

  @Bean("emailConfiguration")
  public freemarker.template.Configuration createFtlConfigBean() throws IOException {
    freemarker.template.Configuration cfg = new freemarker.template.Configuration(
        freemarker.template.Configuration.VERSION_2_3_31);
    cfg.setDefaultEncoding(NotificationConstants.UTF_8);
    cfg.setLogTemplateExceptions(false);
    cfg.setWrapUncheckedExceptions(true);
    cfg.setFallbackOnNullLoopVariable(false);
    cfg.setLocalizedLookup(false);
    List<TemplateLoader> loaders = new ArrayList<>();
    // CloudTemplateLoader is just a wrapper on UrlTemplateLoader
    loaders.add(new CloudTemplateLoader(new URL(baselineUrl)));
    loaders.add(new CloudTemplateLoader(new URL(dynamicUrl)));
    cfg.setTemplateLoader(
        new MultiTemplateLoader(loaders.toArray(new TemplateLoader[0])));
    cfg.setCacheStorage(new MruCacheStorage(5000, Integer.MAX_VALUE));
    cfg.setTemplateUpdateDelayMilliseconds(retentionTimeMillis);
    return cfg;
  }

}

以下是我尝试加载模板的方式:

@Component
@Slf4j
public class FtlTemplateHandler {

    private final Configuration configuration;

    @Autowired
    public FtlTemplateHandler(@Qualifier("emailConfiguration") Configuration configuration) {
        this.configuration = configuration;
    }

    public String getTemplateAsHtml(String emailTemplateUrl) {
        try {
            Template template = configuration.getTemplate(emailTemplateUrl);
            // Process the template
        } catch (IOException e) {
           try {
             log.info("removing template from cache {}", emailTemplateUrl);
             configuration.removeTemplateFromCache(emailTemplateUrl);
             Thread.sleep(10000);
           } catch (IOException | InterruptedException ex) {
             // process exception
           }
       }
    }
}

我的云模板加载器:

@Slf4j
public class CloudTemplateLoader extends URLTemplateLoader {
  private URL root;
  public CloudTemplateLoader(URL root) {
    super();
    this.root = root;
  }
  public URL getRoot() {
    return root;
  }
  public void setRoot(URL root) {
    this.root = root;
  }
  @Override
  protected URL getURL(String template) {
    try {
      return new URL(root, template);
    } catch (MalformedURLException e) {
      log.error("Error while loading templates from cloud.");
    }
    return null;
  }
}

出现以下错误:

Caused by: java.io.IOException: Server returned HTTP response code: 403 for URL: https://baseline/bhnpay-static/notification-template/ftl/en-US/b9b09aa4-fd39-4812-924e-1fe7f6d4ed51.ftl
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:2000)
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1589)
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getHeaderField(HttpURLConnection.java:3256)
    at java.base/java.net.HttpURLConnection.getHeaderFieldDate(HttpURLConnection.java:601)
    at java.base/java.net.URLConnection.getLastModified(URLConnection.java:567)
    at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getLastModified(HttpsURLConnectionImpl.java:392)
    at freemarker.cache.URLTemplateSource.lastModified(URLTemplateSource.java:94)
    at freemarker.cache.URLTemplateLoader.getLastModified(URLTemplateLoader.java:50)
    at freemarker.cache.MultiTemplateLoader$MultiSource.getLastModified(MultiTemplateLoader.java:142)
    at freemarker.cache.MultiTemplateLoader.getLastModified(MultiTemplateLoader.java:99)
    at freemarker.cache.TemplateCache.getTemplateInternal(TemplateCache.java:439)

但是模板存在于动态 url 中,这意味着在查看基线 cdn 后,它不会检查动态 cdn。

我已验证 URL 正确且可访问。 我尝试清除缓存以确保这不是缓存问题,但回退仍然不起作用。

spring-boot freemarker cdn
1个回答
0
投票

在返回之前验证与 url 的连接实际上对我有用。

@Override
  protected URL getURL(String template) {
    try {
      URL url = new URL(root, template);

      if (isTemplateAvailable(url)) {
        return url;
      } else {
        log.warn("Template not found or inaccessible at URL: {}", url);
      }
    } catch (MalformedURLException e) {
      log.error("Malformed URL when loading template {}: ", template, e);
    } catch (IOException e) {
      log.error("IOException when checking template availability: ", e);
    }

    return null;
  }

  private boolean isTemplateAvailable(URL url) throws IOException {
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("HEAD");
    connection.connect();
    int responseCode = connection.getResponseCode();
    connection.disconnect();
    return responseCode == HttpURLConnection.HTTP_OK;
  }
© www.soinside.com 2019 - 2024. All rights reserved.