准备搭建SpringBoot+FreeMarker+SiteMesh的框架,选用了springBoot2.1版本,安装一些教程无脑复制粘贴,把maven依赖和freemarker配置凑齐
pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.sitemesh/sitemesh -->
<dependency>
<groupId>org.sitemesh</groupId>
<artifactId>sitemesh</artifactId>
<version>3.0.1</version>
</dependency>
application
#server
server:
servlet:
context-path: /basis
#DB
#sqlserver
spring:
datasource: ######
driverClassName: #####
url: ####
username: ####
password: ####
mvc:
view:
prefix: classpath:/templates
suffix: ftl
freemarker:
cache: false
charset: UTF-8
content-type: text/html
suffix: .ftl
check-template-location: true
template-loader-path: classpath:/templates
#expose-request-attributes: true
#expose-session-attributes: true
#expose-spring-macro-helpers: true
#allow-request-override: true
request-context-attribute: request
settings:
default_encoding: UTF-8
output_encoding: UTF-8
url_escaping_charset: UTF-8
tag_syntax: auto_detect
locale: zh_CN
datetime_format: yyyy-MM-dd HH:mm:ss
date_format: yyyy-MM-dd
time_format: HH:mm:ss
freemarker注释掉的4行造成了给解决问题造成了很大的干扰
SiteMeshFilter
@WebFilter("/*")
public class SitemeshFilter extends ConfigurableSiteMeshFilter {
Logger logger = LoggerFactory.getLogger(SitemeshFilter.class);
@Override
protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
//设置模板装饰的请求,参数(拦截的请求(可以采用通配符方式),装饰该请求的装饰模板)
//index是一个页面模板放在src/main/resource/templates/decorators目录下
builder
.addDecoratorPath("/*", "/layouts/default")
//可设置不同请求用不同模板装饰
.addExcludedPath("/static/*") //白名单,不进行过滤的请求
.addExcludedPath("/api/*")
.addExcludedPath("/Images/*")
.addExcludedPath("/Scripts/*")
.addExcludedPath("/Styles/*")
.addExcludedPath("/AjaxHandler/*")
.addExcludedPath("/waiterChat/*")
.addExcludedPath("/statistic")
//.builder.addTagRuleBundles(new DivExtractingTagRuleBundle()) //用于添加自定义标签
;
logger.info("------------ sitemeshFilter config-----------");
}
}
粗暴的复制粘贴给后面带来了一系列的问题:
- sitemesh 模板文件 default.ftl 放在 templates/layouts 目录下找不到,报404错误
- 将 default.ftl 文件移到static 目录下则被识别为资源文件,浏览器访问变成下载保存
看源码sitemesh拦截到请求后,会在请求返回前通过forward方法请求模板文件
org.sitemesh.webapp.WebAppContext
/**
* Dispatch to the actual path. This method can be overriden to provide different ways of dispatching
* (such as cross web-app).
*/
protected void dispatch(HttpServletRequest request, HttpServletResponse response, String path)
throws ServletException, IOException {
RequestDispatcher dispatcher = servletContext.getRequestDispatcher(path);
if (dispatcher == null) {
throw new ServletException("Not found: " + path);
}
dispatcher.forward(request, response);
}
由于模板文件 default.ftl 在template 目录下,受资源访问的保护,必须提供一个访问入口
/**
*
* siteMesh decorator 访问
*
* @param decorator 模板文件名
* @return
*
* @author ###
* @date 2019年4月11日 下午4:06:15
*/
@RequestMapping(value = "/layouts/{decorator}", method = RequestMethod.GET)
public String decorator(@PathVariable String decorator) {
return "/layouts/"+decorator;
}
访问请求报错
javax.servlet.ServletException: Cannot expose request attribute 'request' because of an existing model object of the same name
将相关设置注释掉,使用默认设置,问题解决.
- 碰到新问题,使用post提交数据时,服务器端 sitemesh 进行 forward请求后报错
Request method 'POST' not supported
重新修改sitemesh模板访问入口,支持对post请求的页面进行包装
/**
*
* siteMesh decorator 访问
*
* @param decorator 模板文件名
* @return
*
* @author ###
* @date 2019年4月11日 下午4:06:15
*/
@RequestMapping(value = "/layouts/{decorator}",method = {RequestMethod.GET,RequestMethod.POST})
public String decorator(@PathVariable String decorator) {
return "/layouts/"+decorator;
}
- sitemesh3 中模板也无法加载目标body元素中的样式属性
<!-- sitemesh2中可用,但在sitemesh3无效 -->
<body <sitemesh:getProperty property="body.class" writeEntireProperty="1"/> >
<sitemesh:body/>
</body>
<!-- sitemesh3中作者推荐的处理方法-->
<body>
<input id="meta.body.id" type="hidden" value="<sitemesh:write property="body.id" />"/>
<input id="meta.body.class" type="hidden" value="<sitemesh:write property="body.class" />"/>
<script type="text/javascript">
var bodyClass = document.getElementById('meta.body.class').value;
var bodyId = document.getElementById('meta.body.id').value;
if (bodyId) {
document.body.id = bodyid;
}
if (bodyClass) {
document.body.className = bodyClass;
}
</script>
<sitemesh:write property='body' />
</body>
sitemesh3已经在2015.5.29以后停止维护了,不知道有没有同样好用的易于后端开发人员上手的前端装饰组件 (´༎ຶД༎ຶ`)
网友评论