Adding patterns to addResourceHandler always returned error when want to serve static content - spring

I went through all question here, all docs according to Spring and couldn't find solution which make my case work.
The case is that I would like to secure my application (Spring Boot with Angular 4) by Spring Security. So the first things which I did was to add two Configuration classes, ex:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.anyRequest().permitAll().and().httpBasic();
}
#Configuration
#EnableWebMvc
#ComponentScan("com.inventory")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/", "/#/", "/resources/static/**")
.addResourceLocations("/resources/static/index.html", "/resources/static/index.html", "/resources/static/index.html");
}
}
#Controller
public class ViewController {
#RequestMapping(value = "/#/")
public String index() {
return "forward:/resources/static/index.html";
}
#RequestMapping(value = "/")
public String home() {
return "index.html";
}
}
As you see in Controller I tried to use to diffrent attempts to serve static content. Unfortunately all this returns:
There was an unexpected error (type=Internal Server Error, status=500).
Could not resolve view with name 'index.html' in servlet with name 'dispatcherServlet'
What am I doing wrong? Why I can't get this static content? Of course my static content is under resources/static and there are .js files and ex. index.html.

Related

Spring boot: Log file has get requests to static files

I have configured my app using
#Configuration
#EnableWebSecurity
#Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {...}
Inside configure method, allowed the static content.
http .httpBasic().and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/**/*.js", "/resources/static/**", "/static/**", "/**/*.jpg", "/**/*.svg", "/**/*.ico", "/**/*.gif", "/**/*.css", "/register")
.permitAll()
application.properties :
logging.level.web=debug
logging.level.org.springframework.web=debug
The problem i am having is that my log file is crowded by get requests to the static resources
I am just interested in logging access to controllers and not static files.
Is there something i need to configure to exclude the logging of access to static resources?
I have also tried
#Configuration
public class StaticConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern("/static/**")) {
registry.addResourceHandler("/static/**")
.addResourceLocations("/static/");
}
}
}
Issue
You have enabled debug level logging for org.springframework.web package, so it will log everything
Try this solution
Remove the debug level logging for org.springframework.web
Create a subclass of CommonsRequestLoggingFilter
public class CustomRequestLoggingFilter extends CommonsRequestLoggingFilter {
#Override
protected boolean shouldLog(HttpServletRequest request) {
return logger.isDebugEnabled() &&
!request.getRequestURL().toString().contains("/static")
}
}
Create that filter as a bean
#Configuration
public class RequestLoggingFilterConfig {
#Bean
public CustomRequestLoggingFilter logFilter() {
CustomRequestLoggingFilter filter
= new CustomRequestLoggingFilter();
filter.setIncludeQueryString(true);
filter.setIncludePayload(false);
filter.setMaxPayloadLength(10000);
filter.setIncludeHeaders(false);
filter.setAfterMessagePrefix("REQUEST DATA : ");
return filter;
}
}
Add the following to application.properties
logging.level.<package of your filter>.CustomRequestLoggingFilter=DEBUG

Multiple forward slashes in request mapping in spring

#RestController
#RequestMapping("/api")
public class AbcController {
#RequestMapping(value = "/abc", method = RequestMethod.GET)
public String abc(){
return "Hello";
}
}
Valid URL: http://localhost:8080/api/abc
Invalid URls:
http://localhost:8080////api/abc
http://localhost:8080/////api////abc
http://localhost:8080/////////api/////abc
Problem: My controller is accepting all above urls. I want to restrict it and accept only valid url and throw error on invalid urls.
Note: I'm not using any custom routing. It's default spring has.
The simplest way is to add custom handler interceptor to validate the url.
public class ValidateURLInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (isValidUrl(request.getRequestURI())) {
return true;
}
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid URL");
return false;
}
private static boolean isValidUrl(String url) {
return !url.contains("//");
}
}
And then update the MVC configuration
#Configuration
public class AppConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ValidateURLInterceptor());
}
}
Add maven dependency for spring security and use below code to allow access to all the paths without logging in.
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
public void configure(WebSecurity web) throws Exception
{
web
.ignoring()
.antMatchers("/**");
}
}

Spring Boot and GlassFish

I actually have a spring boot application that i deployed on glassfish server 5.0 .
The probleme is that the jsp pages are not showing when i type the link.
I correctly configured the main class:
#SpringBootApplication
public class CaisseApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(CaisseApplication.class, args);
}
}
the controller looks like this:
#Controller
#RequestMapping("/imports_caisses_et_grandsLivres/")public class controller {
#RequestMapping(value = "")
public String index(Map<Object, Object> model) {
return "index";
}
}
The jsp pages are correctly created, and to acces them, i'm using application.properties:
spring.mvc.view.prefix= /WEB-INF/views/
spring.mvc.view.suffix= .jsp
Sorry, the brackets {} was missing in:
#Controller
#RequestMapping({"/imports_caisses_et_grandsLivres/"})

Configure spring boot to redirect 404 to a single page app [duplicate]

This question already has answers here:
Spring Boot with redirecting with single page angular2
(12 answers)
Closed 2 years ago.
I want to configure my Spring Boot app to redirect any 404 not found request to my single page app.
For example if I am calling localhost:8080/asdasd/asdasdasd/asdasd which is does not exist, it should redirect to localhost:8080/notFound.
The problem is that I have a single page react app and it runs in the root path localhost:8080/. So spring should redirect to localhost:8080/notFound and then forward to / (to keep route).
This is the full Spring Boot 2.0 example:
#Configuration
public class WebApplicationConfig implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/notFound").setViewName("forward:/index.html");
}
#Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> containerCustomizer() {
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/notFound"));
};
}
}
This should do the trick: Add an error page for 404 that routes to /notFound, and forward that to your SPA (assuming the entry is on /index.html):
#Configuration
public class WebApplicationConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/notFound").setViewName("forward:/index.html");
}
#Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/notFound"));
};
}
}
In case anyone stumbles here looking for how to handle Angular/React/other routes and paths in a Spring Boot app - but not always return index.html for any 404 - it can be done in a standard Spring controller RequestMapping. This can be done without adding view controllers and/or customizing the container error page.
The RequestMapping supports wild cards, so you can make it match against a set of well known paths (ie. angular routes etc.) in your application and only then return forward index.html:
#Controller
public class Html5PathsController {
#RequestMapping( method = {RequestMethod.OPTIONS, RequestMethod.GET}, path = {"/path1/**", "/path2/**", "/"} )
public String forwardAngularPaths() {
return "forward:/index.html";
}
}
Another option (borrowed from an old Spring article here: https://spring.io/blog/2015/05/13/modularizing-the-client-angular-js-and-spring-security-part-vii) is to use a naming convention:
#Controller
public class Html5PathsController {
#RequestMapping(value = "/{[path:[^\\.]*}")
public String redirect() {
return "forward:/index.html";
}
}
The above configuration will match all paths that do not contain a period and are not already mapped to another controller.
//add this controller : perfect solution(from jhipster)
#Controller
public class ClientForwardController {
#GetMapping(value = "/**/{path:[^\\.]*}")
public String forward() {
return "forward:/";
}
}
Here the security configuration (SecurityConfig.java)
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private Environment env;
#Autowired
private UserSecurityService userSecurityService;
private BCryptPasswordEncoder passwordEncoder() {
return SecurityUtility.passwordEncoder();
}
private static final String[] PUBLIC_MATCHERS = {
"/css/**",
"/js/**",
"/data/**",
"/sound/**",
"/img/**",
"/",
"/login",
"/logout,
"/error",
"/index2",
};
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().
/* antMatchers("/**").*/
antMatchers(PUBLIC_MATCHERS).
permitAll().anyRequest().authenticated();
//.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login");
http
.csrf().disable().cors().disable()
.formLogin().failureUrl("/login?error")
.defaultSuccessUrl("/index2")
.loginPage("/login").permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/?logout").deleteCookies("remember-me").permitAll()
.and()
.rememberMe()
.and()
.sessionManagement().maximumSessions(3600)
.and().
invalidSessionUrl("/login");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userSecurityService).passwordEncoder(passwordEncoder());
}
}
If not found any resource redirect to error page
#Controller
public class IndexController implements ErrorController{
private static final String PATH = "/error";
#RequestMapping(value = PATH)
public String error() {
return PATH;
}
#Override
public String getErrorPath() {
return PATH;
}
}
Error page like
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1000/xhtml"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<meta http-equiv="refresh" content="5;url=/login" />
<body>
<h1>Page not found please login the system!</h1>
</body>
</html>
Simply implementing the org.springframework.boot.web.servlet.error.ErrorController did the trick for me. I use SpringBoot 2.0 with React. (If you are interested in how to do that here is a boilerplate project made by me: https://github.com/archangel1991/react-with-spring)
#Controller
public class CustomErrorController implements ErrorController {
#Override
public String getErrorPath() {
return "/error";
}
}
I am not sure why is this working though.

Spring boot single page application - forward every request to index.html

I have a Spring Boot (v1.3.6) single page application (angular2) and i want to forward all request to the index.html.
A request to http://localhost:8080/index.html is working (200 and i get the index.html) but http://localhost:8080/home is not (404).
Runner.class
#SpringBootApplication
#ComponentScan({"packagea.packageb"})
#EnableAutoConfiguration
public class Runner {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext run = SpringApplication.run(Runner.class, args);
}
}
WebAppConfig.class
#Configuration
#EnableScheduling
#EnableAsync
public class WebAppConfig extends WebMvcConfigurationSupport {
private static final int CACHE_PERIOD_ONE_YEAR = 31536000;
private static final int CACHE_PERIOD_NO_CACHE = 0;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.setOrder(-1);
registry.addResourceHandler("/styles.css").addResourceLocations("/styles.css").setCachePeriod(CACHE_PERIOD_ONE_YEAR);
registry.addResourceHandler("/app/third-party/**").addResourceLocations("/node_modules/").setCachePeriod(CACHE_PERIOD_ONE_YEAR);
registry.addResourceHandler("/app/**").addResourceLocations("/app/").setCachePeriod(CACHE_PERIOD_NO_CACHE);
registry.addResourceHandler("/systemjs.config.js").addResourceLocations("/systemjs.config.js").setCachePeriod(CACHE_PERIOD_NO_CACHE);
registry.addResourceHandler("/**").addResourceLocations("/index.html").setCachePeriod(CACHE_PERIOD_NO_CACHE);
}
}
styles.css, /app/third-party/xyz/xyz.js,.. are working (200 and i get the correct file). Only /** to index.html is not working.
You can also add a forwarding controller like:
#Controller
public class ForwardingController {
#RequestMapping("/{path:[^\\.]+}/**")
public String forward() {
return "forward:/";
}
}
The first part {path:[^\\.]+} matches one or more of any character other than .. This makes sure request for a file.ext doesn't get handled by this RequestMapping. If you need to support sub-paths to also be forwarded, put /** outside of the {...}.
This one didn't work for me:
return "forward:/";
Thanks to Spring MVC #RestController and redirect I found a nicely working solution:
#RequestMapping(value = "/{[path:[^\\.]*}")
public void redirect(HttpServletResponse response) throws IOException {
response.sendRedirect("/");
}
Without looking at logs I'm not entirely sure why its not being mapped correctly, however if you want to map URLs to a view (HTML) then you will probably be better off using the viewController mechanism spring provides http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-config-view-controller. e.g.
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
(taken from spring docs linked above - this is how you should map a url to a view rather than re-purposing the mapping for static resources.)
I'm not sure if there is any kind of suffix filtering for the resource mapping - e.g. I don't know how spring decides to map requests to the ResourceHttpRequestHandler - have you tried (just to confirm or deny) whether something like http://localhost:8080/home.html amps to anything?
It's also possible that the html mapping you have defined above is just being ignored and the index.html is just working because of Spring-Boot's default home page behaviour: https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java#L108
I had the same problem and the following worked for me. My html files are inside src/main/resources/static/app
The key was to remove #EnableWebMvc and add "classpath:/static/app/" to addResourceLocations! Hope this helps.
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/","classpath:/static/app/", "classpath:/public/" };
#Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern("/webjars/**")) {
registry.addResourceHandler("/webjars/**").addResourceLocations(
"classpath:/META-INF/resources/webjars/");
}
if (!registry.hasMappingForPattern("/**")) {
registry.addResourceHandler("/**").addResourceLocations(
CLASSPATH_RESOURCE_LOCATIONS);
}
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
// forward requests to /admin and /user to their index.html
registry.addViewController("/portal").setViewName(
"forward:/app/index.html");
}
};
}

Resources