JSP 文件中的拦截器、图块、注释和自定义包含
Interceptor, tiles, annotations, and custom includes in JSP files
背景
在 Spring 3.x 应用程序中使用磁贴。该应用程序使用一个 standard.jsp 文件作为网站模板,它定义了典型的元素:文档类型、导航、header、body 等.
standard.jsp 文件应动态包含 page-specific 自定义。例如,如果 URL 是“http://localhost/account”,那么 <head>
元素应该包含:
<link rel="stylesheet" href="styles/account.css" />
每个tile的定义可以这样写:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions ...>
<tiles-definitions>
<definition ...>
<put-attribute name="viewName" value="account" />
</definition>
</tiles-definitions>
然后,在standard.jsp文件中:
<link rel="stylesheet" href="<tiles:insertAttribute name="viewName" />.css"/>
问题
这会产生所需的结果,但图块属性是 hard-coded,每个 tiles.xml 文件都有效复制。
问题
如何避免在各处重复 put-attribute
定义,同时仍导入与正在呈现的视图相对应的特定 CSS 文件?
想法
使用拦截器只对 /
URI 有效,对其他没有任何作用。例如:
@EnableWebMvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("intro");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(new BaseInterceptor()).addPathPatterns("/**");
}
}
配置额外的视图控制器不会触发拦截器代码:
registry.addViewController("/account").setViewName("account");
如果可行,那么我们可以通过扫描类路径来遍历所有 JSP 文件(参见 here and here)。 tiles 代码可能会干扰 JSPs:
的视图控制器注册表
@Bean
public TilesViewResolver tilesViewResolver() {
TilesViewResolver viewResolver = new TilesViewResolver();
viewResolver.setViewClass(TilesView.class);
return viewResolver;
}
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions("/WEB-INF/**/tiles.xml");
return tilesConfigurer;
}
拦截器只为/
触发,可用于注入视图名称:
public class BaseInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(BaseInterceptor.class);
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.info("BASE INTERCEPTOR POST HANDLE");
if (modelAndView != null) {
modelAndView.addObject("stylesheet", modelAndView.getViewName() + ".css");
}
super.postHandle(request, response, handler, modelAndView);
}
}
但是因为有 tiles,除了 /
.
之外,拦截器永远不会被触发
我希望我理解你的问题是正确的:你有一些可以从视图名称中派生出来的值 - 对吗?
我的解决方案(Spring 3.2,Tiles 3)是使用模式:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<!-- base - every thing that is common -->
<definition name="base" template="/WEB-INF/layouts/template.jspx">
...
</definition>
<!-- Tiles view definition for the complete backend -->
<definition name="prefix/**" extends="base">
<put-attribute name="mainPart" value="/WEB-INF/views/{1}.jsp" />
<put-attribute name="stylesheetUrl" value="/styles/{1}.css" />
</definition>
</tiles-definitions>
这是您唯一需要的 xml。当您尝试渲染名称为 prefix/x/y
的视图时,Tiles 将加载 /WEB-INF/layouts/template.jspx
模板并设置两个属性:
- 主要部分 =
/WEB-INF/views/x/y.jsp
- stylesheetUrl =
/styles/x/y.css
背景
在 Spring 3.x 应用程序中使用磁贴。该应用程序使用一个 standard.jsp 文件作为网站模板,它定义了典型的元素:文档类型、导航、header、body 等.
standard.jsp 文件应动态包含 page-specific 自定义。例如,如果 URL 是“http://localhost/account”,那么 <head>
元素应该包含:
<link rel="stylesheet" href="styles/account.css" />
每个tile的定义可以这样写:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions ...>
<tiles-definitions>
<definition ...>
<put-attribute name="viewName" value="account" />
</definition>
</tiles-definitions>
然后,在standard.jsp文件中:
<link rel="stylesheet" href="<tiles:insertAttribute name="viewName" />.css"/>
问题
这会产生所需的结果,但图块属性是 hard-coded,每个 tiles.xml 文件都有效复制。
问题
如何避免在各处重复 put-attribute
定义,同时仍导入与正在呈现的视图相对应的特定 CSS 文件?
想法
使用拦截器只对 /
URI 有效,对其他没有任何作用。例如:
@EnableWebMvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("intro");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(new BaseInterceptor()).addPathPatterns("/**");
}
}
配置额外的视图控制器不会触发拦截器代码:
registry.addViewController("/account").setViewName("account");
如果可行,那么我们可以通过扫描类路径来遍历所有 JSP 文件(参见 here and here)。 tiles 代码可能会干扰 JSPs:
的视图控制器注册表@Bean
public TilesViewResolver tilesViewResolver() {
TilesViewResolver viewResolver = new TilesViewResolver();
viewResolver.setViewClass(TilesView.class);
return viewResolver;
}
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions("/WEB-INF/**/tiles.xml");
return tilesConfigurer;
}
拦截器只为/
触发,可用于注入视图名称:
public class BaseInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(BaseInterceptor.class);
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.info("BASE INTERCEPTOR POST HANDLE");
if (modelAndView != null) {
modelAndView.addObject("stylesheet", modelAndView.getViewName() + ".css");
}
super.postHandle(request, response, handler, modelAndView);
}
}
但是因为有 tiles,除了 /
.
我希望我理解你的问题是正确的:你有一些可以从视图名称中派生出来的值 - 对吗?
我的解决方案(Spring 3.2,Tiles 3)是使用模式:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<!-- base - every thing that is common -->
<definition name="base" template="/WEB-INF/layouts/template.jspx">
...
</definition>
<!-- Tiles view definition for the complete backend -->
<definition name="prefix/**" extends="base">
<put-attribute name="mainPart" value="/WEB-INF/views/{1}.jsp" />
<put-attribute name="stylesheetUrl" value="/styles/{1}.css" />
</definition>
</tiles-definitions>
这是您唯一需要的 xml。当您尝试渲染名称为 prefix/x/y
的视图时,Tiles 将加载 /WEB-INF/layouts/template.jspx
模板并设置两个属性:
- 主要部分 =
/WEB-INF/views/x/y.jsp
- stylesheetUrl =
/styles/x/y.css