I encounter this problem while I am trying to duplicate a simple spring OAuth project, sparklr2. source code here
https://github.com/spring-projects/spring-security-oauth/tree/master/samples/oauth2/sparklr
the source code runs perfectly, when I debug it with tomcat, it initialize all #Bean inside WebMvcConfigurerAdapter, including controllers. but noted that #ComponentScan() is not being used.
then I create my own MVC project, copy almost 100% of code, but I am using WebApplicationInitializer instead of AbstractDispatcherServletInitializer. I use WebApllicationInitializer because I have only learned this way to code MVC.
then I run the project, #Bean initialized. then I check /login with my browser, get 404. this could be caused by spring not knowing I have controllers, then I add #ComponentScan to my configuration class, /login now shows up.
but the weird thing is, all #Bean related to Controller, are not initialized. so, when I call any method to those controller, since their attributes are not initialized, gives me no object or null exception.
So, my point is, how does that sample works, I mean controller and jsp correctly handle and response without using #ComponentScan?
and look at it from different angle, why does #ComponentScan stop #Bean from being initialize in my project?
my WebApplicationInitializer
#Configuration
#EnableWebMvc
#ComponentScan("umedia.test.oauth.controller")
public class MvcConfig extends WebMvcConfigurerAdapter {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public ContentNegotiatingViewResolver contentViewResolver()
throws Exception {
ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
contentNegotiationManager.addMediaType("json",
MediaType.APPLICATION_JSON);
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
MappingJackson2JsonView defaultView = new MappingJackson2JsonView();
defaultView.setExtractValueFromSingleKeyModel(true);
ContentNegotiatingViewResolver contentViewResolver = new ContentNegotiatingViewResolver();
contentViewResolver
.setContentNegotiationManager(contentNegotiationManager
.getObject());
contentViewResolver.setViewResolvers(Arrays
.<ViewResolver> asList(viewResolver));
contentViewResolver.setDefaultViews(Arrays.<View> asList(defaultView));
return contentViewResolver;
}
#Bean
public PhotoServiceImpl photoServices() {
List<PhotoInfo> photos = new ArrayList<PhotoInfo>();
photos.add(createPhoto("1", "marissa"));
photos.add(createPhoto("2", "paul"));
photos.add(createPhoto("3", "marissa"));
photos.add(createPhoto("4", "paul"));
photos.add(createPhoto("5", "marissa"));
photos.add(createPhoto("6", "paul"));
PhotoServiceImpl photoServices = new PhotoServiceImpl();
photoServices.setPhotos(photos);
return photoServices;
}
// N.B. the #Qualifier here should not be necessary (gh-298) but lots of
// users report needing it.
#Bean
public AdminController adminController(
TokenStore tokenStore,
#Qualifier("consumerTokenServices") ConsumerTokenServices tokenServices,
SparklrUserApprovalHandler userApprovalHandler) {
AdminController adminController = new AdminController();
adminController.setTokenStore(tokenStore);
adminController.setTokenServices(tokenServices);
adminController.setUserApprovalHandler(userApprovalHandler);
return adminController;
}
// this url, do I need to change it?
private PhotoInfo createPhoto(String id, String userId) {
PhotoInfo photo = new PhotoInfo();
photo.setId(id);
photo.setName("photo" + id + ".jpg");
photo.setUserId(userId);
photo.setResourceURL("/org/springframework/security/oauth/examples/sparklr/impl/resources/"
+ photo.getName());
return photo;
}
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public PhotoServiceUserController photoServiceUserController(
PhotoService photoService) {
PhotoServiceUserController photoServiceUserController = new PhotoServiceUserController();
return photoServiceUserController;
}
#Bean
public PhotoController photoController(PhotoService photoService) {
PhotoController photoController = new PhotoController();
photoController.setPhotoService(photoService);
return photoController;
}
#Bean
public AccessConfirmationController accessConfirmationController(
ClientDetailsService clientDetailsService,
ApprovalStore approvalStore) {
AccessConfirmationController accessConfirmationController = new AccessConfirmationController();
accessConfirmationController
.setClientDetailsService(clientDetailsService);
accessConfirmationController.setApprovalStore(approvalStore);
return accessConfirmationController;
}
/* #Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}*/
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations(
"/resources/");
}
}
so, you have #ComponentScan which interacts with #Controller on your controllers + still create #Bean's with those?
As a first step try to remove #Beans and try to inject dependencies using #Autowired on controllers' constructors. Then #ComponentScan should recognize #Controller, inject dependencies and use #RequestMapping without issues.
Related
I've tried to configure controllers for thymeleaf views resolver, but it doesn't work. I made controller test and they passed so i think it is servlets configuration problem.
My WebConfig looks like this:
#Configuration
#EnableWebMvc
#ComponentScan("springmvccommerce.web")
public class WebConfig implements WebMvcConfigurer{
#Bean
ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(true);
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Edit:
HomeController:
#Controller
public class HomeController {
#GetMapping("/")
public String home() {
return "home";
}
}
And productController:
#Controller
public class ProductController {
#Autowired
private ProductRepository productRepository;
#GetMapping("/products")
public String products(Model model) {
model.addAttribute("productList", productRepository.findProduct(Long.MAX_VALUE, 20));
return "products";
}
}
If it is not enough, I've added link to repo in comment.
It seems spring boot haven't support for tomcat 10 due to the jakarta namespace, switch to tomcat 9 and retry.
Here are some links related:
https://github.com/spring-projects/spring-framework/issues/25354
Deploying Spring 5.x on Tomcat 10.x with jakarta.* package
I'm using Spring mvc, and wanna make web app which send some json data to client and client should visualized them using js.
I have some questions:
1-My project have some *.html beside *.jsp file how can I handle both without web.xml. the code that i had written work fine with *.jsp but give "The requested resource is not available." error for mapping html files.
2-As i said My service have to send a list of object in json form to client, when i want to parse the json string on server in *.jsp file with the code like
MyClass data = new Gson().fromJson(MyList.get(0).toString(), listType)
,I face with to many problems, so i decide to do this job in client Side in *.html file, i want to know how should i handle this parsing job when i don't want that client know about the structure my class? OR plz tell if have to share my class with client, how should i send stucture of it to html file?
3-How should i access to data that i created in restapi.jsp on the UserSideApp.html file?
these are some my files:
AppInitializer.java
public class AppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(container);
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
} }
AppConfig.java
public class AppConfig {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix("");
return viewResolver;
} }
the part of my AppContoller.java
#Controller
#RequestMapping("/")
public class AppController {
#Autowired
HackDataService service;
#RequestMapping(value = "/restapi", method = RequestMethod.GET)
public String jsonAPI(ModelMap model) {
List<HackData> newList = service.findAllNewData();
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json="";
try {
json = ow.writeValueAsString(newList);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
model.addAttribute("List", json);
String newjson = new Gson().toJson(newList);
model.addAttribute("newList", newjson);
return "newTest.jsp";
}
#RequestMapping(value = "/app", method = RequestMethod.GET)
public String htmlapp() {
return "UserSideApp.html";
} }
and my both .html and .jsp files are in "/WEB-INF/views/"
After spending almost a day on first problem, i find the answer of it,
first of all instead of implementing WebApplicationInitializer, I extend AbstractAnnotationConfigDispatcherServletInitializer and for java Configing i extends WebMvcConfigurerAdapter.
Then i create a pages folder in WEB-INF and my codes changes to these:
AppInitializer became like other internet's samples.
AppConfig.java
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.attackmap" })
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/WEB-INF/pages/");
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix("");
return viewResolver;
}
}
AppController.java
#Controller
#RequestMapping("/")
public class AppController {
#RequestMapping(value = { "/", "/info" }, method = RequestMethod.GET)
public String welcome(ModelMap model) {
model.addAttribute("message", "home page with info about site");
return "homepage.jsp";
}
#RequestMapping(value = "/finalapp", method = RequestMethod.GET)
public String test() {
return "redirect:/pages/final.htm";
} }
there was another way
Creating a "resources" directory in "src/main/webapp"
add bellow cod in AppConfig.java
registry.addResourceHandler("/WEB-INF/views/resources/*.html").addResourceLocations("/resources/");
and for viewResolving use the code like bellow:
#RequestMapping(value = "/newapp", method = RequestMethod.GET)
public String test2() {
return "/resources/UserSideAppNew.html";
}
but still my two other questions are unsolved, the main problem was first one but if you know sth, about these two plz tell me about them
Most of my #Controllers are picked up through component scanning. However, a few, such as those I use with Spring Social are created as #Beans. I just migrated from mostly xml to JavaConfig only and upgraded to Spring 4.1.9.
However, the Controller endpoints that are created as #Beans are creating 404s.
Any ideas?
package nl.project.webapp.config;
#Order(1)
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{WebAppConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{ServletConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
[...]
}
package nl.project.webapp.config;
#Configuration
#ComponentScan(basePackages = {"nl.project.webapp"},excludeFilters={
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=Controller.class),
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=RestController.class)
})
#Import({AppConfig.class,JPAConfig.class})
#PropertySource("classpath:msa.properties")
public class WebAppConfig {
[...]
}
package nl.project.webapp.config;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"nl.project.webapp.controller"},includeFilters={
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=Controller.class),
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=RestController.class)
})
public class ServletConfig extends WebMvcConfigurerAdapter{
[...]
}
package nl.project.webapp.social.config;
#Configuration
public class SocialConfig{
#Bean
public MyConnectController connectController(MessageSource messages, UsorManager userMgr, PhotoManager photoMgr) {
MyConnectController connectController = new MyConnectController(connectionFactoryLocator, connectionRepository);
connectController.setConnectInterceptors(Arrays.asList(new ConnectInterceptor<?>[]{
new TwitterConnectInterceptor(userMgr, photoMgr, messages),
new FacebookConnectInterceptor(userMgr, photoMgr, messages),
new LinkedInConnectInterceptor(userMgr, photoMgr, messages),
new GoogleConnectInterceptor(userMgr, photoMgr, messages),
}));
return connectController;
}
#Bean
public MySignInController signinController(MessageSource messages, UsorManager userMgr, PhotoManager photoMgr){
MySignInController signinController = new MySignInController(connectionFactoryLocator, usersConnectionRepository, new SimpleSigninAdapter(userMgr));
signinController.setSignInInterceptors(Arrays.asList(new ProviderSignInInterceptor<?>[]{
new FacebookSigninInterceptor(userMgr, photoMgr, messages),
new LinkedInSigninInterceptor(userMgr, photoMgr),
new GoogleSigninInterceptor(userMgr, photoMgr)
}));
return signinController;
}
}
package nl.project.webapp.social.controller;
#Controller
#RequestMapping("/signin")
public class MySignInController extends ProviderSignInController {
public MySignInController(
ConnectionFactoryLocator connectionFactoryLocator,
UsersConnectionRepository usersConnectionRepository,
SignInAdapter signInAdapter) {
super(connectionFactoryLocator, usersConnectionRepository, signInAdapter);
this.connectionFactoryLocator = connectionFactoryLocator;
}
[...]
The problem was caused by SocialConfig being imported by the WebAppConfig in stead of the ServletConfig. Although the documentation suggests that any Controller bean available in the context will be picked up by using '#EnableWebMVC', it is not very clear that this does not apply to Controller beans loaded through the webapp context.
This is my AppInitializer:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.project.app")
public class AppInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer implements
WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(container);
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
And this is my AppConfig:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.acfcm.app")
#Import({ SecurityConfig.class })
public class AppConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolverForClasses() {
ResourceBundleViewResolver viewResolver = new ResourceBundleViewResolver();
viewResolver.setOrder(1);
viewResolver.setBasename("views");
return viewResolver;
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setOrder(2);
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations(
"/resources/");
}
}
What I want is how to change the AppConfig to put .jsp in differents foldes into the project because right now only can save it in /WEB-INF/views/ and there is a lot of .jsp!! I want to have two more folders to see my project like:
WEB-INF/views/moduleOne/
WEB-INF/views/moduleTwo/
...
Thanks!
I think your code is all fine; it will look for your JSPs starting in /WEB-INF/views/
Most people do like you say and break up JSP views under folders like /admin, /common, etc.
The way you do this is to specify the subfolder in the controller. For example, in your controller, you could return:
#RequestMapping(value = "/admin/index.htm", method = RequestMethod.GET)
public ModelAndView index(HttpServletRequest request,
HttpServletResponse response)
{
Map<String, Object> myModel = new HashMap<String, Object>();
myModel.put("someValues", new ArrayList());
ModelAndView mv = new ModelAndView("admin/index","model", myModel);
return mv;
}
Doing it like the above, you can put your JSP under
/WEB-INF/views/admin/index.jsp
Of course, your mappings (/admin) doesn't have to match the directory structure (/WEB-INF/views/admin) but we chose to make both match, to make it faster to find the code (if controller mapping matches the dir structure).
The important thing to remember is that whatever you put in that ModelAndView first param, Spring will prepend and append the values you defined in your code:
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
So, if you return ModelAndview("/pierre/was/here/something"), Spring will try to find the JSP at location: "/WEB-INF/views/pierre/was/here/something.jsp"
The common practice is to have the configuration as yours, and in the request handler controller methods, use the view names as moduleOne/view1, moduleTwo/view2 etc.
I have a Spring MVC application with Thymeleaf configured to use fragments (NO tiles!) and all files have .html extension. Everything is working fine.
Now i'm trying to setup Webflow but, when i call my webflow url, i get 404 error as he tries to load a JSP view instead of html (outside flow, everything is fine):
HTTP Status 404 - /app/WEB-INF/views/contest/contest-step1.jsp
I know that put kilometers of line of code isn't good, but honestly i don't know which pieces are interesting and which no.
ThymeleafConfig:
#Configuration
public class ThymeleafConfig {
#Bean
public TemplateResolver templateResolver() {
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
/**
* only on development machine
*/
templateResolver.setCacheable(false);
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
Set<IDialect> dialects = new HashSet<IDialect>();
dialects.add(springSecurityDialect());
templateEngine.setAdditionalDialects(dialects);
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
return resolver;
}
#Bean
public SpringSecurityDialect springSecurityDialect(){
SpringSecurityDialect dialect = new SpringSecurityDialect();
return dialect;
}
}
WebAppConfig:
#Configuration
#EnableWebMvc
#ComponentScan("com.myapp")
public class WebAppConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
// Maps resources path to webapp/resources
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
/**************************************************
*
* Web Flow: wizard contest
*
*/
#Autowired
private WebFlowConfig webFlowConfig;
/**
* Maps request paths to flows in the flowRegistry;
* e.g. a path of /hotels/booking looks for a flow with id "hotels/booking"
*
* Configuring this mapping allows the Dispatcher to map application resource paths
* to flows in a flow registry.
* For example, accessing the resource path /hotels/booking would result in a
* registry query for the flow with id hotels/booking.
* If a flow is found with that id,
* that flow will handle the request. If no flow is found, the next handler mapping in the
* Dispatcher's ordered chain will be queried or a "noHandlerFound" response will be returned.
*/
#Bean
public FlowHandlerMapping flowHandlerMapping() {
FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
handlerMapping.setOrder(-1); //0 ?
handlerMapping.setFlowRegistry(this.webFlowConfig.flowRegistry());
return handlerMapping;
}
#Bean
public FlowHandlerAdapter flowHandlerAdapter() {
FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter();
handlerAdapter.setFlowExecutor(this.webFlowConfig.flowExecutor());
handlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
return handlerAdapter;
}
#Bean(name="contest/add") //defined in in WebFlowConfig
public ContestFlowHandler ContestFlowHandler() {
return new ContestFlowHandler();
}
/* TODO
#Bean
public AjaxThymeleafViewResolver tilesViewResolver() {
AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver();
viewResolver.setViewClass(FlowAjaxThymeleafTilesView.class);
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
} */
}
WebFlowConfig:
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
#Autowired
private ThymeleafConfig thymeleafConfig;
//private WebFlowConfig WebAppConfig;
#Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/views/gare/gare-add-flow.xml", "gare/add")
.build();
}
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.setMaxFlowExecutions(5)
.setMaxFlowExecutionSnapshots(30)
.build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.build();
}
#Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(Arrays.<ViewResolver>asList(this.thymeleafConfig.thymeleafViewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
}
I found a trick that gives me a quick solution, but honestly i would like don't do this, but correctly configure the resolver. The trick is to set the view file in flow xml file:
<view-state id="contest-step1" model="contest" view="/WEB-INF/views/contest/contest-step1.html"></view-state>
thanks
Try the following in flowRegistry method.
return getFlowDefinitionRegistryBuilder(flowBuilderServices())
instead of
return getFlowDefinitionRegistryBuilder()
Hope this helps.
I am not sure but kindly look into the following part of your code
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
it is pointing to .jsp whatever you call in controller it will append .jsp
Also your controller code is not here url mapping should be like /login.html
I am not much familier with thymeleaf and spring-webflow-2