Spring resourceHandler pattern fails for index-page - java

I'm trying to map resourceHandlers to resourceLocations in a Spring MVC application, but somehow I can't make the mapping between /* and my index.html work.
#Configuration
#EnableWebMvc
#EnableTransactionManagement(proxyTargetClass = true)
#EnableScheduling
#ComponentScan(basePackages = {"mySpringApp.web.controller"})
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/*", "/", "").addResourceLocations("classpath:/static/index.html");
registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/static/assets/");
}
...
The requests I make returns the following:
http://localhost:8080/ - 404
http://localhost:8080/index.html - 200(returns the index-file that I wan't on /* )
http://localhost:8080/assets/main.js - 200(returns one of the files
located in my assets-folder)
Any idea why the index-mapping fails?

When http://localhost:8080/ is requested, spring is looking for a controller with a mapping looking like #RequestMapping("") or #RequestMapping("/"), which you do not have.
registry.addResourceHandler("/*", "/", "").addResourceLocations("classpath:/static/index.html");
not serving index file because:
you are simply not specifying what resource you want spring to serve.
possible solutions
Write a controller
#RequestMapping(value = "/")
public String index() {
return "redirect:index.html";
}
Refactor addResourceHandlers()
registry.addResourceHandler("*.html").addResourceLocations("/static/");
Note that addResourceHandler is adding a "pattern" while addResourceLocation is telling spring where exactly/physically to find the requested resource.

Related

Securing endpoints in Spring Boot by rights/roles

#RestController
public class AccountController {
#PermitAll
#RequestMapping(value = "/test")
public ResponseEntity<String> test() {
// ...
}
#RolesAllowed("ROLE_ADMIN)
#RequestMapping(value = "/products")
public ResponseEntity<List<Product>> products() {
// ...
}
}
How to configure Spring Boot to be able to access "/test" without authentication, but "/products" with authentication and checking rights/roles?
Is it possible without mention paths of #PermitAll(like "/test") in configuration?
Question : Spring Boot to be able to access "/test" without authentication, but "/products" with authentication
Solution :
http.authorizeRequests().antMatchers("/test").permitAll()
.antMatchers("/products").hasRole("ADMIN").anyRequest().authenticated().and().httpBasic();
Note : By default when you add spring security, it ask authentication for all the url and you need to specify the one which you do not need authentication. For Example /login should be permitAll.
Click here for Source code of security configuration
Refer Sample HttpSecurity sample for more matchers example as below,
For more details : https://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html
You can do it providing the next configuration class. In this case everything is accessible, if not restricted by the annotations.
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().permitAll();
}
}
Check SecurityConfig class here for more configuration options.

Fastest way to deliver jsp views without xml-conf using spring project stub from start.spring.io

I am using spring again after a longer period and happy to see that xml configurations are no longer required in every case.
I want to build a RESTful App, but I still have to deliver the frontend app. I figured the simplest way without using any additional template engines like thymeleaf would be serving a static jsp.
I'm using the project template from start.spring.io with just spring-mvc as dependency, thus i'm using spring boot as well.
I wrote a controller in order to deliver the jsp, but it seems that the mapping for the views has to be configured first.
#Controller
public class StaticPagesController {
#RequestMapping(value = "/")
public String index(){
return "index";
}
}
So i created a configuration class:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "de.tuberlin.sense.emp")
public class WebConfiguration {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".html");
return viewResolver;
}
}
index.html is located in main/webapp/WEB-INF/views/
When i send a request to /, I get a WARN in the logs wich states No mapping found for HTTP request with URI [/WEB-INF/views/index.html] in DispatcherServlet with name 'dispatcherServlet'
What am I missing? Can I do this without any xml configuration?
Here is my main application class code:
UPDATE:
#SpringBootApplication
public class ExperimentManagementPlatformApplication {
public static void main(String[] args) {
SpringApplication.run(ExperimentManagementPlatformApplication.class, args);
}
}
Try adding a view controller:
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
Reference
It seems to me that your controller is not being detected, I would suggest to check your file structure, is the StaticPagesController controller in the de.tuberlin.sense.emp package? (as stated in:)
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "de.tuberlin.sense.emp")
public class WebConfiguration
I was able to serve the static page without needing any controller at all by just adding the html file to the static directory. Furthermore i found out that the entire webapp directory is not included when the app is deployed as jar which explains why the files in there could not be found.
The Spring documentation
Your config class should extend WebMvcConfigurerAdapter class
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "de.tuberlin.sense.emp")
public class WebConfiguration extends WebMvcConfigurerAdapter{
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".html");
return viewResolver;
}
}

Set a Spring REST Controller welcome-file

I'm building a RESTful API and have a Spring REST Controller (#RestController) and an annotation-based configuration. I'd like to have my project's welcome-file be a .html or .jsp file with the API documentation.
In other web projects I would place a welcome-file-list in my web.xml, but in this particular project I can't seem to get it to work (preferrably using Java and annotations).
This is my WebApplicationInitializer
public class WebAppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(ApplicationConfig.class);
context.setServletContext(servletContext);
ServletRegistration.Dynamic dynamic = servletContext.addServlet("dispatcher",
new DispatcherServlet(context));
dynamic.addMapping("/");
dynamic.setLoadOnStartup(1);
}
}
This is my WebMvcConfigurerAdapter
#Configuration
#ComponentScan("controller")
#EnableWebMvc
public class ApplicationConfig extends WebMvcConfigurerAdapter {
#Bean
public Application application() {
return new Application("Memory");
}
}
And this is a small part of my REST Controller
#RestController
#RequestMapping("/categories")
public class CategoryRestController {
#Autowired
Application application;
#RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<Integer, Category>> getCategories(){
if(application.getCategories().isEmpty()) {
return new ResponseEntity<Map<Integer, Category>>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<Map<Integer, Category>>(application.getCategories(), HttpStatus.OK);
}
}
So far I've tried:
Adding just a web.xml with a <welcome-file-list> with a <welcome-file>. (no luck there)
Moving the #RequestMapping("/categories") in the Controller from the class level to all of the methods, and adding a new method with #RequestMapping("/"), which returns either a String or a ModelAndView with the view name. (the former just returned a blank page with the String, for the latter no mapping could be found)
As suggested here: a combination of both, where my web.xml <welcome-file> is "/index", combined with #RequestMapping(value="/index") returning a new ModelAndView("index"), and a ViewResolver in my configuration class. (returns a Warning: No mapping found in DispatcherServlet with name 'dispatcher', even though "/index" is successfully mapped. Manually adding "/index" to the URL successfully resolves it to index.jsp)
When specifying a controller to handle your index page you should use a #Controller not a #RestController. Although the #RestController is a #Controller it doesn't resolve to a view but returns the result as is to the client. When using a #Controller when returning a String it will resolve to the name of a view.
#Controller
public class IndexController {
#RequestMapping("/")
public String index() {
return "index";
}
}
However there is an easier way to configure this and you don't need a controller for it. Configure a view controller. In your configuration class simply override/implement the addViewControllers method.
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
That way you don't even need to create a class for it.

Spring MVC 404 Error on Certain Requests

I'm receiving a 404 error when accessing a particular page in my spring boot web application.
The strange thing is that I don't receive that error when the resource is mapped to a different location.
#RequestMapping(value="report", method = RequestMethod.GET)
public String getReportPage() {
return "templates/report.html";
}
works just fine while
#RequestMapping(value="report/{uuid}", method = RequestMethod.GET)
public String getReportPage() {
return "templates/report.html";
}
does not. I need the uuid parameter for my angular service so I cannot simply remove that from the path. I've tried adding the path variable to the model; that makes no difference.
The directory structure is set up as follows:
webapp
resources
...
templates
report.html
The configuration is pretty much an out of the box spring boot with some added resource handlers and some basic security:
#Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/", "file:resources/");
}
}
#Configuration
#EnableWebSecurity
class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and()
.csrf().disable();
}
}
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService());
auth.authenticationProvider(authProvider());
}
.... custom user details service and authentication provider ...
}
Any thoughts about what may be causing this issue?
Edit: After some further investigation, it looks like anything mapped beyond the first level doesn't work for the web controller (but the rest controllers are working just fine). For example, a mapping with the value /web/report doesn't work either.
While looking through debug messages I found that the application was looking for the pages in the wrong place:
DEBUG : Looking up handler method for path /report/templates/report.html
Which is why only top level requests were working.
Changing the mapping as such:
#RequestMapping(value="report/{uuid}", method = RequestMethod.GET)
public String getReportPage() {
return "/templates/report.html";
}
fixed the problem.

How to create a REST service with spring-boot?

I'm using spring-boot and want to integrate a simple REST service as follows.
#Controller
#RequestMapping("/content")
public class MyServiceRest extends SpringBeanAutowiringSupport {
#RequestMapping(method = RequestMethod.GET)
public String test() {
return "OK";
}
}
Result: both localhost:8080/<app-name>/services/content results "No service was found.". Why?
Do I have to explicit publish the service somehow?
Maybe it is due to my dispatcher servlet?
#Bean
public ServletRegistrationBean dispatcherServletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(new CXFServlet(), "/services/*");
registration.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
return registration;
}
Since you are using Spring Boot, make sure that your application is correctly setup by adding the correct annotations. For instance,
#EnableAutoConfiguration
#EnableWebMvc
#Configuration
#ComponentScan
/*
* Application Setups using Spring boot.
*/
public class Application{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#EnableWebMvc is the annotation to add for using Spring MVC with Spring boot.
And then you can define your controller as you did in your question.
add package with controller class to #Component scan in main class like: #ComponentScan( basePackages = { "your.package.with.controller" } ), this happens when spring didn't initialize (doesn't know about) controller
you should also add url mapping for your method
#RequestMapping(method = RequestMethod.GET, value = "url_here",
try
#RequestMapping(method = RequestMethod.POST, value = "/",
In the latest version of Spring Boot, that I am currently using, the web Service would address be http://localhost:8080/content
Also, the class I use to launch the service looks as follows:
#ComponentScan("eu.buzea")
#EnableAutoConfiguration
#EnableTransactionManagement
#SpringBootApplication
public class Application{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Source Code
https://drive.google.com/open?id=0BzBKpZ4nzNzUWmJmOTFwbTFjWWM
using Swagger
http://localhost:7070/swagger-ui.html#/
**Cheers*
As of current spring-boot.1.5.6 there is no requirement using cxf.
Just use a #RestController with #GetMapping, and be happy to access localhost:8080/content.

Categories

Resources