环境:spring mvc +freemark 。模板由另一个项目生成。利用linux 的ln -s 软连接到webapp下
错误java.lang.SecurityException
1.tomcat默认是不允许在webapp下用软连接文件夹的。
需要在context.xml中配置 allowLinking="true"修改之后问题依旧。
2.仔细观察错误。好像是查找模板问题。查找模板嘛肯定是 temploader,有很多实现
- ClassTemplateLoader
- FileTemplateLoader
- MultiTemplateLoader
- StringTemplateLoader
- URLTemplateLoader
- 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的父类FreeMarkerConfigurationFactory 的createConfiguration 方法中有这样一段
// 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也替换掉哈哈
相关推荐
通过Java将html文件内容替换成动态数据,使用freemark模板文件.
freemark模板&模版技术&freemark模板&模版技术
使用freemark模板导出pdf
适用于初学者快速掌握Freemark的使用(内附代码)。
实现FreeMark读取到json数据绑定到特定的模板
根据freemark模板,生成任何语言的代码。根据mysql的表设计,运用freemark模板,生成java代码,jsp代码,c#代码等等。
springboot 集成mybits mysql和freemark模板引擎demo,本demo在mybaits中sql用到springboot默认注解sql以及spring的mapping映射*.xml 两种方式,而且配置操作日志(sql打印)
当下载的excel格式内容比较复杂时,用程序生成excel文件就显得力不从心。这时采用excel模板化,更加便捷高效。本资源基于springboot+freemark模板做的示例。只需要了解下freemark基本语法即可。
SSM的整合+OScache页面缓存+freemark模板。这是一个很牛比的东西。看看啊
freemark 模板引擎 概述 教程 5分钟入门 pdf
freemark开发指南详解freemark开发指南详解freemark开发指南详解freemark开发指南详解freemark开发指南详解
一些很不错的freemark资料及eclipse的freemark插件
主要介绍了freemark标签的相关基础知识,基本上了解Freemark标签的应用
易语言模块freemark模块_取文件.rar 易语言模块freemark模块_取文件.rar 易语言模块freemark模块_取文件.rar 易语言模块freemark模块_取文件.rar 易语言模块freemark模块_取文件.rar 易语言模块freemark模块_取...
freemark ,
SpringMVC+Freemark简单整合 不含lib下的jar。
freemark中文资料 freemark教程 freemark基础和高级教程
通过freemark模板构建mybatis的相关数据库表的javabean,xml文件,service,dao层自动生成代码,通过freemark模板构建mybatis的相关数据库表的javabean,xml文件,service,dao层自动生成代码
Freemark指南:全面介绍Freemark的使用方法,让你的页面已程序完美的结合!