版本控制静态资产不适用于 Spring Web Flow
Versioning static assets does not work with Spring Web Flow
资源文件的缓存过期和版本控制在所有页面上都能正常工作。但是流程似乎忽略了 Spring MVC 配置。
一个工作示例:
资源文件有版本控制
使用 Spring 网络流量:
资源文件缺少版本控制
在 WebMvcConfig class:
@Configuration
@EnableCaching
@ConfigurationProperties("message")
public class WebMvcConfig implements WebMvcConfigurer, ServletContextAware {
...
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(false)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
}
@Bean
public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
return new ResourceUrlEncodingFilter();
}
...
}
WebConfigClass:
@Configuration
@EnableWebMvc
public class WebFlowConfig extends AbstractFlowConfiguration {
@Autowired
private ViewResolver viewResolver;
@Autowired
private RequestDataInterceptor requestDataInterceptor;
@Autowired
private LocalValidatorFactoryBean validator;
// WEB FLOW
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry()).addFlowExecutionListener(new SecurityFlowExecutionListener(), "*").build();
}
@Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder(flowBuilderServices()).setBasePath("/WEB-INF/flows/").addFlowLocationPattern("/**/*-flow.xml").build();
}
@Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder().setViewFactoryCreator(mvcViewFactoryCreator()).setValidator(validator).setDevelopmentMode(true).setConversionService(getDefaultConversionService()).build();
}
private DefaultConversionService getDefaultConversionService() {
final DefaultConversionService service = new DefaultConversionService();
final FormattingConversionService delegateConversionService = (FormattingConversionService) service.getDelegateConversionService();
delegateConversionService.removeConvertible(String.class, Number.class);
delegateConversionService.addConverterFactory(new StringToNumberConverterFactory());
delegateConversionService.addConverter(new TrimStringConverter());
return service;
}
// MVC
@Bean
public FlowHandlerMapping flowHandlerMapping() {
final FlowHandlerMapping mapping = new FlowHandlerMapping();
mapping.setOrder(0);
mapping.setFlowRegistry(this.flowRegistry());
mapping.setInterceptors(requestDataInterceptor);
return mapping;
}
@Bean
public FlowHandlerAdapter flowHandlerAdapter() {
final FlowHandlerAdapter adapter = new FlowHandlerAdapter();
adapter.setFlowExecutor(this.flowExecutor());
adapter.setSaveOutputToFlashScopeOnRedirect(true);
return adapter;
}
@Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
final MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(Lists.newArrayList(this.viewResolver));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
}
在安全配置中:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
@Override
public void configure(final WebSecurity web) {
web.ignoring().antMatchers("/resources/**");
}
...
}
在jsp个文件中(包括流程):
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
...
<!-- jQuery -->
<script type="text/javascript" src="<c:url value="/resources/scripts/libs/jquery-3.3.1.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/scripts/jquery-validation/jquery.validate.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/scripts/jquery-numbers/jquery.number.min.js"/>"></script>
...
关于如何在流上应用静态资产的版本控制有什么想法吗?
我的处理方式:
<spring:eval expression="@applicationProperties.resourcesVersion" var="resourcesVersion"/>
<head>
<style type="text/css" media='screen,print'>
@import url("<c:url value="/resources/css-framework/css/tools.css?v=${resourcesVersion}" />");
</style>
<script type="text/javascript" src="<c:url value="/resources/spring/Spring.js?v=${resourcesVersion}" />"></script>
</head>
应用程序属性:
@Named
public class ApplicationProperties {
....
private Long resourcesVersion = System.currentTimeMillis();
public Long getResourcesVersion() {
return resourcesVersion;
}
}
我在 CAS 服务器中遇到了同样的问题,解决方案是添加 ResourceUrlProviderExposingInterceptor
作为 FlowHandlerMapping
的拦截器。
资源文件的缓存过期和版本控制在所有页面上都能正常工作。但是流程似乎忽略了 Spring MVC 配置。
一个工作示例:
资源文件有版本控制
使用 Spring 网络流量:
资源文件缺少版本控制
在 WebMvcConfig class:
@Configuration
@EnableCaching
@ConfigurationProperties("message")
public class WebMvcConfig implements WebMvcConfigurer, ServletContextAware {
...
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(false)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
}
@Bean
public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
return new ResourceUrlEncodingFilter();
}
...
}
WebConfigClass:
@Configuration
@EnableWebMvc
public class WebFlowConfig extends AbstractFlowConfiguration {
@Autowired
private ViewResolver viewResolver;
@Autowired
private RequestDataInterceptor requestDataInterceptor;
@Autowired
private LocalValidatorFactoryBean validator;
// WEB FLOW
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry()).addFlowExecutionListener(new SecurityFlowExecutionListener(), "*").build();
}
@Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder(flowBuilderServices()).setBasePath("/WEB-INF/flows/").addFlowLocationPattern("/**/*-flow.xml").build();
}
@Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder().setViewFactoryCreator(mvcViewFactoryCreator()).setValidator(validator).setDevelopmentMode(true).setConversionService(getDefaultConversionService()).build();
}
private DefaultConversionService getDefaultConversionService() {
final DefaultConversionService service = new DefaultConversionService();
final FormattingConversionService delegateConversionService = (FormattingConversionService) service.getDelegateConversionService();
delegateConversionService.removeConvertible(String.class, Number.class);
delegateConversionService.addConverterFactory(new StringToNumberConverterFactory());
delegateConversionService.addConverter(new TrimStringConverter());
return service;
}
// MVC
@Bean
public FlowHandlerMapping flowHandlerMapping() {
final FlowHandlerMapping mapping = new FlowHandlerMapping();
mapping.setOrder(0);
mapping.setFlowRegistry(this.flowRegistry());
mapping.setInterceptors(requestDataInterceptor);
return mapping;
}
@Bean
public FlowHandlerAdapter flowHandlerAdapter() {
final FlowHandlerAdapter adapter = new FlowHandlerAdapter();
adapter.setFlowExecutor(this.flowExecutor());
adapter.setSaveOutputToFlashScopeOnRedirect(true);
return adapter;
}
@Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
final MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(Lists.newArrayList(this.viewResolver));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
}
在安全配置中:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
@Override
public void configure(final WebSecurity web) {
web.ignoring().antMatchers("/resources/**");
}
...
}
在jsp个文件中(包括流程):
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
...
<!-- jQuery -->
<script type="text/javascript" src="<c:url value="/resources/scripts/libs/jquery-3.3.1.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/scripts/jquery-validation/jquery.validate.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/scripts/jquery-numbers/jquery.number.min.js"/>"></script>
...
关于如何在流上应用静态资产的版本控制有什么想法吗?
我的处理方式:
<spring:eval expression="@applicationProperties.resourcesVersion" var="resourcesVersion"/>
<head>
<style type="text/css" media='screen,print'>
@import url("<c:url value="/resources/css-framework/css/tools.css?v=${resourcesVersion}" />");
</style>
<script type="text/javascript" src="<c:url value="/resources/spring/Spring.js?v=${resourcesVersion}" />"></script>
</head>
应用程序属性:
@Named
public class ApplicationProperties {
....
private Long resourcesVersion = System.currentTimeMillis();
public Long getResourcesVersion() {
return resourcesVersion;
}
}
我在 CAS 服务器中遇到了同样的问题,解决方案是添加 ResourceUrlProviderExposingInterceptor
作为 FlowHandlerMapping
的拦截器。