`

tomcat 下软连接 freemark 模板文件不能访问

 
阅读更多
环境:spring mvc +freemark 。模板由另一个项目生成。利用linux 的ln -s 软连接到webapp下
错误java.lang.SecurityException  
1.tomcat默认是不允许在webapp下用软连接文件夹的。
          需要在context.xml中配置 allowLinking="true"修改之后问题依旧。
2.仔细观察错误。好像是查找模板问题。查找模板嘛肯定是 temploader,有很多实现
  1. ClassTemplateLoader
  2. FileTemplateLoader
  3. MultiTemplateLoader
  4. StringTemplateLoader
  5. URLTemplateLoader
  6. WebappTemplateLoader
为什么用FileTemplateLoader 因为我的FreeMarkerConfigurer配置如下:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value="/WEB-INF/pages/" />
        <property name="freemarkerSettings">
            <props>
                <prop key="template_update_delay">0</prop>
                <prop key="default_encoding">UTF-8</prop>
                <prop key="number_format">0.##########</prop>
                <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
                <prop key="classic_compatible">true</prop>
                <prop key="template_exception_handler">ignore</prop>
            </props>
        </property>
</bean>
 
请注意templateLoaderPath。而在FreeMarkerConfigurer的父类FreeMarkerConfigurationFactorycreateConfiguration 方法中有这样一段
        
        // Register default template loaders.
        if (this.templateLoaderPaths != null) {
            for (String path : this.templateLoaderPaths) {
                this.templateLoaders.add(getTemplateLoaderForPath(path));
            }
        }
 
getTemplateLoaderForPath这个方法的实现如下
protected TemplateLoader getTemplateLoaderForPath(String templateLoaderPath) {
        if (isPreferFileSystemAccess()) {
            // Try to load via the file system, fall back to SpringTemplateLoader
            // (for hot detection of template changes, if possible).
            try {
                Resource path = getResourceLoader().getResource(templateLoaderPath);
                File file = path.getFile();  // will fail if not resolvable in the file system
                if (logger.isDebugEnabled()) {
                    logger.debug(
                            "Template loader path [" + path + "] resolved to file path [" + file.getAbsolutePath() + "]");
                }
                return new FileTemplateLoader(file);
            }
            catch (IOException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Cannot resolve template loader path [" + templateLoaderPath +
                            "] to [java.io.File]: using SpringTemplateLoader as fallback", ex);
                }
                return new SpringTemplateLoader(getResourceLoader(), templateLoaderPath);
            }
        }
        else {
            // Always load via SpringTemplateLoader (without hot detection of template changes).
            logger.debug("File system access not preferred: using SpringTemplateLoader");
            return new SpringTemplateLoader(getResourceLoader(), templateLoaderPath);
        }
    }
 
 
查看freemarker的 FileTemplateLoader原来做了检查,就是下面的红色部分
 
// Security check for inadvertently returning something 
// outside the template directory when linking is not 
// allowed.
if(canonicalPath != null) {
           String normalized = source.getCanonicalPath();
           if (!normalized.startsWith(canonicalPath)) {
                 throw new SecurityException(source.getAbsolutePath() + " resolves to " + normalized + " which " + 
                                    " doesn't start with " + canonicalPath);
           }
}
 
解决方法:
1.修改源码------哈哈
2.忽然发现有一个构造方法是允许软连接的public FileTemplateLoader(final File baseDir, final boolean allowLinking)
所以想到用spring注入一个allowLinking =true的FileTemplateLoader。当我看到上面getTemplateLoaderForPath这个方法中的new FileTemplateLoader(file);这句话时.我尿了。这尼玛真是个坑13.不过springmvc提供了一个preferFileSystemAccess 意思是你是否喜欢FileTemplateLoader。不喜欢的用我的SpringTemplateLoader 吧。经测试这条路走不通,spring 也判断了真实路径。
3.看源码时看到支持templateLoaderPaths 注意多了一个s。多个路径。好吧。大家应该知道怎么办。
4.自定义Temploader你可以在配置FreeMarkerConfigurer时添加一个自己的preTemplateLoaders 或者postTemplateLoaders
这个很明显是前后。为什么提供前后。因为还有中间。哈哈。中间是谁。就是根据templateLoaderPath获取的。哈哈。好吧真213.
如果有多个到底用哪个呢 ?看看 createConfiguration这个方法中有这么一句
 TemplateLoader loader = getAggregateTemplateLoader(this.templateLoaders);
 protected TemplateLoader getAggregateTemplateLoader(List<TemplateLoader> templateLoaders) {
        int loaderCount = templateLoaders.size();
        switch (loaderCount) {
            case 0:
                logger.info("No FreeMarker TemplateLoaders specified");
                return null;
            case 1:
                return templateLoaders.get(0);
            default:
                TemplateLoader[] loaders = templateLoaders.toArray(new TemplateLoader[loaderCount]);
                return new MultiTemplateLoader(loaders);
        }
    }
 
那么会生成一个MultiTemplateLoader 哈哈。这货是按照顺序来的。代码很短。贴上来看看
 
public Object findTemplateSource(String name) throws IOException{
        // Use soft affinity - give the loader that last found this
        // resource a chance to find it again first.
        TemplateLoader lastLoader = (TemplateLoader)lastLoaderForName.get(name);
        if(lastLoader != null){
            Object source = lastLoader.findTemplateSource(name);
            if(source != null){
                return new MultiSource(source, lastLoader);
            }
        }
        
        // If there is no affine loader, or it could not find the resource
        // again, try all loaders in order of appearance. If any manages
        // to find the resource, then associate it as the new affine loader 
        // for this resource.
        for(int i = 0; i < loaders.length; ++i){
            TemplateLoader loader = loaders[i];
            Object source = loader.findTemplateSource(name);
            if(source != null){
                lastLoaderForName.put(name, loader);
                return new MultiSource(source, loader);
            }
        }
        
        lastLoaderForName.remove(name);
        // Resource not found
        return null;
 }
  
太明显不解释
当然你也可以不要中简单templateloader就是不定义templateLoaderPath属性。然后定义一个自己的templateloader注入到preTemplateLoaders 或者postTemplateL

 

5.好吧你可以更狠一点把FreeMarkerConfigurer也替换掉哈哈
分享到:
评论

相关推荐

    freemark模板文件样例

    通过Java将html文件内容替换成动态数据,使用freemark模板文件.

    Freemark模板使用

    Freemark是一个强大的模板引擎,它允许开发者将逻辑与展示分离,使得HTML或其他类型的文档生成变得更加简洁和灵活。本教程适用于初学者,...随着对Freemark的深入理解和实践,你将能构建出更复杂、更高效的模板系统。

    freemark模板&模版技术

    总结来说,FreeMarker模板及模版技术提供了一种强大且灵活的方式,将静态模板与动态数据相结合,生成定制化的输出。它的易用性和可扩展性使其在各种Web开发场景中得到广泛应用。通过深入了解和熟练掌握FreeMarker,...

    实现FreeMark读取模板生成HTML

    FreeMarker的工作原理是,通过读取预先定义好的模板文件,结合传入的数据模型,生成最终的输出文本。 在“实现FreeMark读取模板生成HTML”的过程中,我们需要完成以下几个关键步骤: 1. **安装与引入**: 首先,...

    freemark模板导出PDF

    - **构建数据模型**:在Java代码中准备数据,这可以是任何类型,如List、Map等,只要FreeMarker模板能识别并处理即可。 - **渲染模板**:使用FreeMarker API读取模板文件,结合数据模型渲染成HTML字符串。 - **...

    freemark制定excel下载模板示例

    当下载的excel格式内容比较复杂时,用程序生成excel文件就显得力不从心。这时采用excel模板化,更加便捷高效。本资源基于springboot+freemark模板做的示例。只需要了解下freemark基本语法即可。

    工具下载地址.txt(根据freemark模板,生成任何语言的代码)

    根据freemark模板,生成任何语言的代码。根据mysql的表设计,运用freemark模板,生成java代码,jsp代码,c#代码等等。

    springboot+mybaits+freemark+mysql

    springboot 集成mybits mysql和freemark模板引擎demo,本demo在mybaits中sql用到springboot默认注解sql以及spring的mapping映射*.xml 两种方式,而且配置操作日志(sql打印)

    FreeMark Jar包 包括 中文 官方文档

    4. **配置**:FreeMark可以通过`freemarker.properties`文件进行配置,设置如模板加载策略、日期时间格式、错误处理等。 5. **模板缓存**:FreeMark可以缓存编译后的模板,提高性能。通过配置可以调整缓存大小和...

    freemark资料及eclipse的freemark插件

    它被广泛应用于Web开发中,特别是与Java后端框架如Spring、Struts等配合使用,为前端展示提供便捷的模板渲染服务。Eclipse是流行的Java集成开发环境(IDE),为了方便开发者在Eclipse中编写和调试FreeMarker模板,有...

    Freemarker代码生成器实体映射xml的ftl模板文件

    在这个场景下,"Freemarker代码生成器实体映射xml的ftl模板文件"是指利用Freemarker模板技术来创建一个用于生成XML实体映射文件的模板。这个`XML.ftl`文件就是核心,它是Freemarker模板的实例,其中定义了如何根据...

    Freemark指南

    - **定义**:命名空间提供了一种组织和引用模板文件的方式,通常通过名称来标识一个特定的模板文件。 - **应用场景**:在复杂的项目中,通过命名空间可以方便地管理大量的模板文件。 - **示例**:定义一个名为`...

    SSM的整合+OScache页面缓存+freemark模板

    通过以上步骤,可以构建一个完整的SSM整合项目,结合OScache的页面缓存和Freemarker模板,能提供高性能、易于维护的Web应用。同时,通过RequestBody和ResponseBody,可以实现前后端的JSON数据交互,满足现代Web开发...

    基于Freemarker模板的代码生成器前台页面模板文件

    在给定的压缩包文件中,我们可以看到几个关键的FTL(FreeMarker Template Language)文件,它们是代码生成器的前台页面模板,包括Browse.ftl、EditPage.ftl、AddPage.ftl和Detail.ftl。 1. **Browse.ftl**:这个...

    Freemark标签

    主要介绍了freemark标签的相关基础知识,基本上了解Freemark标签的应用

    Struts2+Freemark

    7. 测试应用,确保请求能正确路由到Action,FreeMarker模板能正确渲染数据。 在实际开发中,这种组合提供了良好的分离关注点,让开发者可以专注于业务逻辑的实现,而FreeMarker则专注于视图的呈现。为了完成这个...

    freemark 资料学习

    这些对象的属性可以在模板中访问,如`${user.name}`表示获取`user`对象的`name`属性。 3. 控制结构: Freemarker支持条件语句(如`&lt;#if&gt;`, `&lt;#else&gt;`, `&lt;#elseif&gt;`)和循环(如`&lt;#list&gt;`)。这些结构允许根据数据...

    java freemark发送模板邮件

    要将FreeMarker模板与JavaMail结合,首先需要创建一个FreeMarker模板文件(如`.ftl`),然后在Java代码中加载该模板,用数据模型填充,最后将生成的字符串作为邮件内容。 4. **设置邮件参数**: 在Java中,需要...

    test_Freemark freemark的基础入门小程序

    在这个程序中,`Test.java`是主入口点,它负责创建数据模型,加载模板文件,然后使用Freemarker的`Template`类将数据与模板合并,最终生成`test_freemark.html`。具体步骤包括: - 加载Freemarker配置并设置模板...

    freemark 生成静态页面

    1. **配置FreeMarker**: 初始化`Configuration`对象,设置模板文件的位置,加载所需的模板文件。 2. **创建数据模型**: 根据业务需求,构建一个Java对象或Map,其中包含了要在页面上显示的数据。 3. **读取模板**: ...

Global site tag (gtag.js) - Google Analytics