When using Spring with Thymeleaf all my Cyrillic characters are shown as ????? on pages.
Using
#RequestMapping(value = "/login", method = RequestMethod.GET, produces = "text/html; charset=utf-8")
as it was suggested here: https://stackoverflow.com/a/11866822/1479414 and here: https://stackoverflow.com/a/12023816/1479414 doesn't help.
How to solve this issue?
The answer can be found here:
Property characterEncoding should be explicitly set for templateResolver and ThymeleafViewResolver:
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
...
<property name="characterEncoding" value="UTF-8"/>
...
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
...
<property name="characterEncoding" value="UTF-8"/>
...
</bean>
working for me. java config
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.projectName.controller")
public class MVCConfig implements WebMvcConfigurer, ApplicationContextAware {
#Autowired
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws
BeansException {
this.applicationContext = applicationContext;
}
#Bean
public ViewResolver viewResolver(){
ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
thymeleafViewResolver.setTemplateEngine(templateEngine());
thymeleafViewResolver.setCharacterEncoding("UTF-8");
return thymeleafViewResolver;
}
#Bean
public TemplateEngine templateEngine(){
SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.setEnableSpringELCompiler(true);
springTemplateEngine.setTemplateResolver(templateResolver());
return springTemplateEngine;
}
#Bean
public ITemplateResolver templateResolver(){
SpringResourceTemplateResolver springResourceTemplateResolver = new
SpringResourceTemplateResolver();
springResourceTemplateResolver.setApplicationContext(applicationContext);
springResourceTemplateResolver.setPrefix("/WEB-INF/views/");
springResourceTemplateResolver.setTemplateMode(TemplateMode.HTML);
springResourceTemplateResolver.setSuffix(".html");
springResourceTemplateResolver.setCharacterEncoding("UTF-8");
return springResourceTemplateResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
in Config
public class SpringConfig implements WebMvcConfigurer {
private final ApplicationContext applicationContext;
#Autowired
public SpringConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
registry.viewResolver(resolver);
}
}
In ServletInitializer
public class MySpringMvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
return new Filter[] { filter };
}
}
If you have added <property name="characterEncoding" value="UTF-8"/> in the bean configuration for view resolver and still text are not shown in correct format then the problem is in the properties/resource_bundle files.
Try encoding UTF-8 or non-English characters with native2ascii tool. (its included in the java_home/bin folder.
In my case, I put below 2 lines in application.properties file
spring.thymeleaf.enabled=true
spring.thymeleaf.encoding=UTF-8
(Korean)Reference: https://blog.thjang.net/33
With Spring WebFlux, I've restricted the view resolver to use text/html; charset=UTF-8 as the only supported content type. I've used a custom WebFluxConfigurer for that (in Kotlin):
class CustomWebFluxConfigurer(
private val viewResolver: ThymeleafReactiveViewResolver
) : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
viewResolver.supportedMediaTypes =
listOf(MediaType.parseMediaType("text/html; charset=UTF-8"))
registry.viewResolver(viewResolver)
}
}
I think in thymeleaf html page you are using th:text with html element, th:text it just display normal text,
if you want use special charter with your thymeleaf html page so just need to change for example
th:utext="${yourcontroller_var}"
or
th:utext="#{properties_var}"
For example
<div th:utext="${user.name}"> Test! </div> // for your controller variable
And
<div th:utext="#{message.username}"> UserName! </div> // for your properties variable
Nothing do other configuration for using special character with thymeleaf html page.
Hope you will fix your problem
Related
I use thymeleaf WITHOUT Spring. Configuration looks
#WebListener
public class ThymeleafConfig implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
TemplateEngine engine = templateEngine(sce.getServletContext());
TemplateEngineUtil.storeTemplateEngine(sce.getServletContext(), engine);
}
private TemplateEngine templateEngine(ServletContext servletContext) {
TemplateEngine engine = new TemplateEngine();
engine.setTemplateResolver(templateResolver(servletContext));
return engine;
}
private ITemplateResolver templateResolver(ServletContext servletContext) {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(servletContext);
resolver.setPrefix("/WEB-INF/templates/");
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
where I specify path /src/main/webapp/WEB-INF/templates as prefix /WEB-INF/templates/ for my index.html template. It works. Now I am trying to add javascrpt static resource that is located at /src/main/webapp/WEB-INF/js, so that I can import it in template, like
<script src="example.js" type="text/javascript"></script>
OR
<script th:src="#{/example.js}" type="text/javascript"></script>
How can I add javascript resource? All documentation and examples I have found are for the combination Spring+thymeleaf.
EDIT:
The project was configured incorrectly, maven plugin maven-resources-plugin was missing. Thus resources were not recognized.
I am developing a spring boot application, I am trying to use XmlViewResolver to view the pdf from predefined template using itext. Successfully getting the jsp page when I access the "/welcome" and "/invoice", but failed when I try "/pdf".
Please let me know what's wrong. Why the pdf bean is not working as expected?
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
There was an unexpected error (type=Not Found, status=404).
/WEB-INF/jsp/pdf.jsp
Below are the codes
#Controller
public class MainController {
#RequestMapping("/welcome")
public String hello(Model model) {
model.addAttribute("msg", "XmlViewResolver Demo");
return "success";
}
#RequestMapping("/invoice")
public String getInvoiceInfo() {
return "invoice";
}
#RequestMapping("/pdf")
public String getPdfInfo() {
return "pdf";
}
}
JspConfig.java
#Component
public class JspConfig {
#Bean
public ViewResolver internalResourceViewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setViewClass(JstlView.class);
bean.setPrefix("/WEB-INF/jsp/");
bean.setSuffix(".jsp");
bean.setOrder(2);
return bean;
}
}
XmlConfig.java
#Configuration
public class XmlConfig {
#Bean
public XmlViewResolver xmlViewResolver() {
XmlViewResolver resolver = new XmlViewResolver();
Resource resource = new ClassPathResource("xml/user-view.xml");
resolver.setLocation(resource);
resolver.setOrder(1);
return resolver;
}
}
user-view.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="invoice" class="org.springframework.web.servlet.view.JstlView">
<property name="url" value="WEB-INF/template/invoice.jsp" />
</bean>
<bean id="pdf" class="com.example.config.PdfView">
<property name="url" value="WEB-INF/template/invoiceTemplate.pdf" />
</bean>
PdfView.java
import com.lowagie.text.pdf.PdfStamper;
public class PdfView extends AbstractPdfStamperView implements MessageSourceAware {
#Override
protected void mergePdfDocument(Map<String, Object> model, PdfStamper stamper, HttpServletRequest request, response) throws Exception {
stamper.setFormFlattening(true);
String customerName = (String) model.get("customerName");
stamper.getAcroFields().setField("name", customerName);
stamper.close();
}
}
My question is how to add static files like CSS and image files so that I can use them. I am using Spring MVC and Thymeleaf. I looked at various posts on this subject, but they did't help me, so I am asking. As per those posts, I put my CSS and image file in the resources/static/css and resources/static/images directory.
Under templates (under webapp/WEB-INF/templates) is where all my HTML files are stored, the ones who want to use the CSS and image files.
I have the following LoginApplicationConfig file. The very two bottom methods I included so that my HTML files could use the styles and image files:
#EnableWebMvc
#Configuration
#ComponentScan({ "com.myapp.spring.*" })
#Import(value = { LoginSecurityConfig.class })
public class LoginApplicationConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware{
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
#Bean
public TemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(true);
engine.setTemplateResolver(templateResolver());
return engine;
}
private ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/templates/");
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/static/css").setCachePeriod(31556926);
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/static/images").setCachePeriod(31556926);
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Then in my index.html file, I included the following line so I could include the style file (using thymeleaf):
<link rel="stylesheet" th:href="#{css/stylesmd.css}" type="text/css">
But I keep getting the error that the stylesmd.css failed to load.
My questions:
Is the placement of my styles and image files correct. That is, what folders should I specifically put them in. I tried various location like under the webapp and WEB-INF directory but that didn't work.
Are the bottom two methods in LoginApplicationConfigrequired? In addition, I was a bit confused on what to include in the addResourceHandler(...) method and what in the addResourceLocations(...) method.
Is my reference to the style sheet (using thymeleaf) correct?
I am aware a lot of content already exists on this question, but that did't work for me, so that's why I am asking.
This is how I made it work.
Only one line suffice.
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
And
<head>
<link rel="stylesheet" type="text/css" href="/static/css/your.css" th:href="#{/static/css/your.css}"/>
</head>
If it keeps failing, try to move your "templates" folder into the resources folder as a subfolder.
I am creating a Spring social based login or my spring application with spring security.
My SecurityConfig.java looks like this:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login/authenticate")
.failureUrl("/login?error=bad_credentials")
.and()
.logout()
.deleteCookies("JSESSIONID")
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.and()
.authorizeRequests()
.antMatchers(
"/auth/**",
"/login",
"/signup/**",
"/user/register/**"
).permitAll()
.and()
.apply(new SpringSocialConfigurer()
.postLoginUrl("/")
.alwaysUsePostLoginUrl(true));
}
#Bean
public SocialUserDetailsService socialUsersDetailService() {
return new UserDetailServiceImpl(userDetailsService());
}
WebConfig.java:
#EnableWebMvc
#Configuration
#ComponentScan({ "com.spark.webcontroller" })
#Import({ SecurityConfig.class, SocialConfig.class })
#PropertySource("classpath:resources/application.properties")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/view/html/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
templateResolver.setOrder(1);
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
#Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
And finally my WebInitilizar.java
public class WebInitilizer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { RootConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
RootConfig.java is only for adding service classes.
When I am running this app on Tomcat8 I am getting
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1168)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:281)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:962)
at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:324)
at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:235)
at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:199)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:279)
at org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:109)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4615)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5222)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Any help on this will be appreciated
I'm trying to set up Spring Web Flow using only Java annotations in a Spring environment that also uses only Java annotations. However when I attempt to access my flow I get the following exception
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/forms] threw exception [Request processing failed; nested exception is org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'referral' of flow 'test-flow'] with root cause
java.lang.ClassCastException: org.springframework.context.support.GenericApplicationContext cannot be cast to org.springframework.web.context.WebApplicationContext
at org.springframework.web.servlet.support.RequestContext.initContext(RequestContext.java:235)
at org.springframework.web.servlet.support.RequestContext.<init>(RequestContext.java:202)
at org.springframework.web.servlet.view.AbstractView.createRequestContext(AbstractView.java:316)
at org.springframework.web.servlet.view.AbstractView.createMergedOutputModel(AbstractView.java:296)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:265)
at org.springframework.webflow.mvc.servlet.ServletMvcView.doRender(ServletMvcView.java:55)
at org.springframework.webflow.mvc.view.AbstractMvcView.render(AbstractMvcView.java:196)
at org.springframework.webflow.engine.ViewState.render(ViewState.java:293)
at org.springframework.webflow.engine.ViewState.refresh(ViewState.java:242)
at org.springframework.webflow.engine.ViewState.resume(ViewState.java:220)
at org.springframework.webflow.engine.Flow.resume(Flow.java:537)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259)
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:228)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2476)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2465)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
I've traced the source of the error to the instantiation of a RequestContext object, which is passed to views in order for them to access the ApplicationContext (among other things). Since Spring is able to invoke my flows I'm lead to believe that this exception is being thrown due to a bad configuration somewhere in my Web Flow files. I've reviewed them many times and can't find anything that seems glaringly obvious. You can find my Web Flow configuration files below:
DispatcherConfig
#Configuration
#ComponentScan(basePackages = "----")
public class DispatcherConfig {
#Autowired
private FlowDefinitionRegistry flowDefinitionRegistry;
#Autowired
private FlowExecutor flowExecutor;
#Autowired
private AnnotationConfigWebApplicationContext appContext;
#Bean
public FlowHandlerAdapter flowHandlerAdapter()
{
FlowHandlerAdapter flowHandlerAdapter = new FlowHandlerAdapter();
flowHandlerAdapter.setFlowExecutor(flowExecutor);
return flowHandlerAdapter;
}
#Bean
public FlowHandlerMapping flowHandlerMapping()
{
FlowHandlerMapping mapping = new FlowHandlerMapping();
mapping.setFlowRegistry(flowDefinitionRegistry);
mapping.setApplicationContext(appContext);
mapping.setOrder(-1);
return mapping;
}
}
WebFlowConfig
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
#Autowired
private List<ViewResolver> viewResolvers;
#Autowired
private ConversionService conversionService;
#Autowired
private AnnotationConfigWebApplicationContext appContext;
#Bean
public FlowDefinitionRegistry flowRegistry()
{
return getFlowDefinitionRegistryBuilder()
.setBasePath("/WEB-INF/flows")
.addFlowLocationPattern("/**/*-flow.xml")
.setFlowBuilderServices(getFlowBuilderServices())
.build();
}
#Bean
public FlowExecutor flowExecutor()
{
return getFlowExecutorBuilder(flowRegistry()).build();
}
public ExpressionParser getExpressionParser()
{
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
return new WebFlowSpringELExpressionParser(spelExpressionParser);
}
public FlowBuilderServices getFlowBuilderServices()
{
MvcViewFactoryCreator creator = new MvcViewFactoryCreator();
creator.setViewResolvers(viewResolvers);
creator.setApplicationContext(appContext);
creator.setUseSpringBeanBinding(true);
FlowBuilderServices services = new FlowBuilderServices();
services.setViewFactoryCreator(creator);
services.setConversionService(conversionService);
services.setExpressionParser(getExpressionParser());
return services;
}
}
WebMvcConfig
#EnableWebMvc
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Bean
public UrlBasedViewResolver velocityViewResolver()
{
UrlBasedViewResolver resolver = new VelocityViewResolver();
resolver.setSuffix(".vm");
resolver.setViewClass(VelocityView.class);
return resolver;
}
#Bean
public VelocityConfigurer velocityConfig()
{
VelocityConfigurer velocityConfigurer = new VelocityConfigurer();
velocityConfigurer.setResourceLoaderPath("/templates/views/");
return velocityConfigurer;
}
#Bean
public List<ViewResolver> viewResolvers()
{
List<ViewResolver> resolvers = new ArrayList<>();
resolvers.add(velocityViewResolver());
return resolvers;
}
}
The view technology I'm using is Velocity. Spring Webflow version 2.4.1.RELEASE, Spring version 4.1.2.RELEASE, Java 1.8.0_45, Tomcat 7.0.62.
Any ideas what may be causing this exception?
UPDATE: Fixed
Thanks to Roman for providing the answer. I made my FlowBuilderServices and MvcViewFactoryCreator #Bean and this got rid of the ClassCastException. However, there were still some problems with my configuration. My #Autowired List<ViewResolver> viewResolvers was not being instantiated until after the MvcViewFactoryCreator was. Thus I had to make a method that creates the ViewResolver list for the MvcViewFactoryCreator. I'm looking into ways to get the order of creation correct, but for now this works. Below are the changes I had to make to get the Web Flow functioning properly
WebFlowConfig
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
#Autowired
===
-private List<ViewResolver> viewResolvers;
====
+private UrlBasedViewResolver viewResolver
===
...
#Autowired
===
-private AnnotationConfigWebApplicationContext appContext;
===
+private MvcViewFactoryCreator mvcViewFactoryCreator;
===
...
+public List<ViewResolver> getViewResolvers()
+{
+ List<ViewResolver> resolvers = new ArrayList<>();
+ resolvers.add(viewResolver);
+
+ return resolvers;
+}
...
+#Bean
+public MvcViewFactoryCreator mvcViewFactoryCreator()
+{
+ MvcViewFactoryCreator creator = new MvcViewFactoryCreator();
+ creator.setViewResolvers(getViewResolvers());
+ creator.setUseSpringBeanBinding(true);
+ return creator;
+}
#Bean
public FlowBuilderServices flowBuilderServices()
{
===
-MvcViewFactoryCreator creator = new MvcViewFactoryCreator();
-creator.setViewResolvers(viewResolvers);
-creator.setApplicationContext(appContext);
-creator.setUseSpringBeanBinding(true);
===
FlowBuilderServices services = new FlowBuilderServices();
===
-services.setViewFactoryCreator(creator);
===
+services.setViewFactoryCreator(mvcViewFactoryCreator);
===
services.setConversionService(conversionService);
services.setExpressionParser(getExpressionParser());
return services;
}
}
FlowBuilderServices is meant to be a Spring-managed bean, but in your config it is just a new instance. It likes to be ApplicationContextAware and InitializingBean, but that is gonna work only if managed by Spring.
The solution is simple: put #Bean on getFlowBuilderServices() method. And I think you should also make MvcViewFactoryCreator a separate #Bean and not use its setApplicationContext() manually.