I have this code:
package biz.tugay.springJuly18.config;
/* User: koray#tugay.biz Date: 18/07/15 Time: 15:09 */
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
#SuppressWarnings(value = "unused")
public class MyWebAppInnit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfigClass.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{ServletConfigClass.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
and the ServletConfig.class
package biz.tugay.springJuly18.config;
/* User: koray#tugay.biz Date: 18/07/15 Time: 15:10 */
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#ComponentScan(basePackages = "biz.tugay.springJuly18.web")
public class ServletConfigClass {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver =
new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
}
and finally a Controller:
package biz.tugay.springJuly18.web;
/* User: koray#tugay.biz Date: 18/07/15 Time: 12:53 */
import biz.tugay.springJuly18.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class MyWeb {
#Autowired
private MyService myService;
#RequestMapping("/test")
public ModelAndView helloWorld() {
ModelAndView mv = new ModelAndView();
mv.addObject("message", myService.sayHello());
mv.setViewName("koko");
return mv;
}
}
When I deploy this to Tomcat and go to /test I will be redirected to koko.jsp . So why does this work without #EnableWebMvc?
According to this answer here it should not?
Here is RootConfig.java
package biz.tugay.springJuly18.config;
/* User: koray#tugay.biz Date: 18/07/15 Time: 15:10 */
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = "biz.tugay.springJuly18.service")
public class RootConfigClass {
}
The DispatcherServlet has two fields
/** List of HandlerMappings used by this servlet */
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet */
private List<HandlerAdapter> handlerAdapters;
whose values decide how a request will be handled (among other things). These fields are initialized and populated with values when the DispatcherServlet is initialized by the container. The values come from the context configuration you specify. If your context configuration doesn't provide at least one value of the appropriate type, the DispatcherServlet uses some defaults.
These defaults are included in a file named DispatcherServlet.properties which is in the same package as DispatcherServlet.
For HandlerMapping, the values (class names) are
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
The javadoc of AnnotationMethodHandlerAdapter states
Implementation of the HandlerAdapter interface that maps handler
methods based on HTTP paths, HTTP methods and request parameters
expressed through the RequestMapping annotation.
In other words, this implementation also uses methods annotated with #RequestMapping.
However, AnnotationMethodHandlerAdapter is deprecated
in Spring 3.2 in favor of RequestMappingHandlerAdapter
#EnabledWebMvc instead registers a RequestMappingHandlerAdapter, which is much more sophisticated.
Related
I am trying to return a static html(index.html) page using spring boot but I am alway getting a 405 error whem I trying (http://localhost:8080/). Strange fact is that debugger enters index() method.
HomeController:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class HomeController {
#RequestMapping(value = "/", method = RequestMethod.GET)
public String index() {
return "index.html";
}
}
I have tried to return "index.html" and "index" strings.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
#SpringBootApplication
public class Application {
public static void main(String[] args) throws InterruptedException {
ConfigurableApplicationContext applicationContext
= SpringApplication.run(Application.class, args);
}
}
location of html file is:
src\main\resources\public\index.html
here goes a part of startup logger output:
INFO 8284 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/],methods=[GET]}" onto public java.lang.String com.acs.map.controller.HomeController.index()
Screanshot of an error
and i am running project with gradle: gradle bootRun
Logger message after request:
WARN 3988 --- [nio-8080-exec-6] o.s.web.servlet.PageNotFound : Request method 'GET' not supported
Also I have tried with and without this configuration:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/public/**").addResourceLocations("classpath:/public/");
registry.addResourceHandler("/resources/public/**").addResourceLocations("classpath:/resources/public/");
super.addResourceHandlers(registry);
}
#Bean
public ViewResolver viewResolver() {
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setViewClass(InternalResourceView.class);
return viewResolver;
}
}
By default Spring Boot will serve static content from a directory called /static (or /public or /resources or /META-INF/resources). I did a quick check by following the below structure and was successful.
So I believe by extending WebMvcConfigurerAdapter class like below and it should return static content using your current controller code (without the WebConfig class).You can use viewResolver as well to map between view names and actual views as well by further modifying your code.
#SpringBootApplication
public class Application extends WebMvcConfigurerAdapter{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Here are my project dependencies
So, I'm trying to learn Spring Framework, but currently I'm stuck on this problem, for some reason my mappings don't work and when I try to access that address I'm getting a 404 error.
Can someone please clarify what I'm doing wrong (both in usage of spring classes and the source of the problem I have described above)?
I'm configuring spring using the example shown in this video: YouTube Video, the code is basically the same, the only difference is package name and the location of the JSP file (could this be the source of my problem?).
The project was made in IntelliJ Idea and is attached to the following link (Google Drive): Project Link
As my servlet container I'm using Tomcat8 (tried both 9 and 8.5, no cigar).
HomeController.java
package com.demo.spring.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
package com.demo.spring.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Created by ARTERC on 1/16/2017.
*/
#Controller
public class HomeController {
#RequestMapping("/")
public String home() {
return "home";
}
}
WebInit.java
package com.demo.spring.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
#Configuration
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
WebConfig.java
package com.demo.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableWebMvc
#ComponentScan("com.demo.spring")
public class WebConfig extends WebMvcConfigurerAdapter{
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/");
resolver.setSuffix(".jsp");
return resolver;
}
}
home.jsp path: /web/home.jsp
Okay, so I found the solution.
Add war plugin to pom.xml
Fix web resource directory path (was webapp) Image Link
I'm currently new to Spring, and I'm trying to learn the pure java configuration element of it.
I'm able to run my Spring application on Tomcat with the following classes:
Config class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.inka.spring.test.maven.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
/**
*
* #author User
*/
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.inka.spring.test.maven")
public class HelloWorldConfiguration extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
Initializer class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.inka.spring.test.maven.configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
*
* #author User
*/
public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {HelloWorldConfiguration.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
Controller class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.inka.spring.test.maven.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
*
* #author User
*/
#Controller
#RequestMapping("/")
public class HelloWorldController {
#RequestMapping(method = RequestMethod.GET)
public String sayHello(ModelMap model) {
model.addAttribute("greeting", "Hello World from Spring 4 MVC");
return "welcome";
}
#RequestMapping(value = "/helloagain", method = RequestMethod.GET)
public String sayHelloAgain(ModelMap model) {
model.addAttribute("greeting", "Hello World Again, from Spring 4 MVC");
return "welcome";
}
}
This calls a .jsp page that prints the respective messages depending on the path I enter as stated above in the codes.
However, when I try this with weblogic, it doesn't work. All I get is a 403 and a 404 error.
I would have stuck with Tomcat, but we use weblogic at our organisation and I've been instructed to build my application to work with weblogic.
Please, is there some extra configuration I'm supposed to use on weblogic?
Ok, I've finally resolved the issue. Turns out, in your initializer class, no matter what class you extend, you must ALWAYS implement the WebApplicationInitializer class if you intend to deploy on weblogic. You don't have to for Tomcat (don't know about JBoss and the rest), but for weblogic, you MUST implement that class.
So, after changing this:
public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
To this:
public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer implements WebApplicationInitializer {
Everything works fine!
For more information, please visit the spring guide.
I want to retrieve the current user in my controller methods with the #AuthenticationPrincipal annotation. The docs state the following:
Annotation that binds a method parameter or method return value to the Authentication.getPrincipal().
But in fact I get the Authentication object instead of Authentication.getPrincipal().
This is my simple controller method:
#RequestMapping("/")
public #ResponseBody String index(#AuthenticationPrincipal final WindowsAuthenticationToken user) {
return String.format("Welcome to the home page, %s!", user.getName());
}
WindowsAuthenticationToken implements Authentication. In this implementation getPrincipal returns a WindowsPrincipal.
The controller method above works, but when I change the arguments type to WindowsPrincipal and try to access the website, I get the following error page:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Mar 03 15:13:52 CET 2015
There was an unexpected error (type=Internal Server Error, status=500).
argument type mismatch HandlerMethod details: Controller [pkg.HomeController] Method [public java.lang.String pkg.HomeController.index(waffle.servlet.WindowsPrincipal)] Resolved arguments: [0] [type=waffle.spring.WindowsAuthenticationToken] [value=waffle.spring.WindowsAuthenticationToken#121a2581]
This is my configuration file:
package pkg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import waffle.servlet.spi.BasicSecurityFilterProvider;
import waffle.servlet.spi.NegotiateSecurityFilterProvider;
import waffle.servlet.spi.SecurityFilterProvider;
import waffle.servlet.spi.SecurityFilterProviderCollection;
import waffle.spring.NegotiateSecurityFilter;
import waffle.spring.NegotiateSecurityFilterEntryPoint;
import waffle.windows.auth.impl.WindowsAuthProviderImpl;
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint;
#Autowired
private NegotiateSecurityFilter waffleNegotiateSecurityFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(negotiateSecurityFilterEntryPoint).and()
.addFilterBefore(waffleNegotiateSecurityFilter, BasicAuthenticationFilter.class).authorizeRequests()
.anyRequest().fullyAuthenticated();
}
#Bean
public WindowsAuthProviderImpl waffleAuthProvider() {
return new WindowsAuthProviderImpl();
}
#Bean
public NegotiateSecurityFilterProvider negotiateSecurityFilterProvider(
final WindowsAuthProviderImpl waffleAuthProvider) {
return new NegotiateSecurityFilterProvider(waffleAuthProvider);
}
#Bean
public BasicSecurityFilterProvider basicSecurityFilterProvider(final WindowsAuthProviderImpl waffleAuthProvider) {
return new BasicSecurityFilterProvider(waffleAuthProvider);
}
#Bean
public SecurityFilterProviderCollection waffleSecurityFilterProviderCollection(
final NegotiateSecurityFilterProvider negotiateSecurityFilterProvider,
final BasicSecurityFilterProvider basicSecurityFilterProvider) {
final SecurityFilterProvider[] providers = { negotiateSecurityFilterProvider, basicSecurityFilterProvider };
return new SecurityFilterProviderCollection(providers);
}
#Bean
public NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint(
final SecurityFilterProviderCollection waffleSecurityFilterProviderCollection) {
final NegotiateSecurityFilterEntryPoint entryPoint = new NegotiateSecurityFilterEntryPoint();
entryPoint.setProvider(waffleSecurityFilterProviderCollection);
return entryPoint;
}
#Bean
public NegotiateSecurityFilter waffleNegotiateSecurityFilter(
final SecurityFilterProviderCollection waffleSecurityFilterProviderCollection) {
final NegotiateSecurityFilter filter = new NegotiateSecurityFilter();
filter.setProvider(waffleSecurityFilterProviderCollection);
return filter;
}
}
Why is the behaviour different from how it should be?
My principal object did not implement UserDetails. Because WindowsPrincipal is a class of an external library I could not make any changes to it. In the end I created a new filter that wraps the WindowsPrincipal in a class that implements UserDetails. Now I get the correct principal object using #AuthenticationPrincipal.
It is because your WindowsPrincipal implements Principal. Remove the implements clause and it will work again. I had the same problem and this resolved it.
Is it possible in Spring 3.1.1 to configure a view resolver using Java annotations?
I am done with all configurations using Java annotations, but I am stuck at view resolver.
Code
package com;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
import org.springframework.web.servlet.view.JstlView;
#Configuration
#ComponentScan("com")
public class AppConfig
{
{
//Other bean declarations
}
#Bean
public UrlBasedViewResolver urlBasedViewResolver()
{
UrlBasedViewResolver res = new InternalResourceViewResolver();
res.setViewClass(JstlView.class);
res.setPrefix("/WEB-INF/");
res.setSuffix(".jsp");
return res;
}
}
I used this code and ran the application, but it's not returning the appropriate view. However, if I configure a viewresolver in the app-servlet.xml file, it works fine.
Your class should extend WebMvcConfigurerAdapter class. please have a look at below example
#Configuration
#ComponentScan(basePackages="com")
#EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter{
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
I tested your scenario with Spring 4.3.4 and it is working ok.
I would suggest double checking packages you scan and that AppConfig is properly provided.
I am attaching all files starting from your AppConfig. Yet it is good to extend WebMvcConfigurerAdapter. The source code attached is not ideal, it s simplistic and only to try to reproduce the problem you have reported.
Starting from AppConfig:
package com;
import org.springframework.context.annotation.*;
import org.springframework.web.servlet.view.*;
#Configuration
#ComponentScan("com")
public class AppConfig {
#Bean
public UrlBasedViewResolver getViewResovler() {
UrlBasedViewResolver urlBasedViewResolver = new UrlBasedViewResolver();
urlBasedViewResolver.setViewClass(JstlView.class);
urlBasedViewResolver.setPrefix("/WEB-INF/jsp/");
urlBasedViewResolver.setSuffix(".jsp");
return urlBasedViewResolver;
}
}
Then:
package com;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { AppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Finally:
package com;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class MainController {
#RequestMapping("/")
public ModelAndView asdf() {
return new ModelAndView("ABC");
}
}
The problem with the above is that the DispatcherServlet.initViewResolvers get's called before the bean getViewResolver is defined and it cannot find the bean so it never adds the view resolver.
If you move the bean definition into an xml definition, it get's picked up. For some reason the MvcConfiguration class you have defined does not trigger a DispatcherServlet refresh if there are no ViewResolvers defined in the XML.