As now I've always served my images through a static path in the application.properties file:
spring.resources.staticlocations=file:/Applications/MAMP/htdocs/reportMaker/template
spring.mvc.static-path-pattern=/resources/**
Then by doing
http://localhost:8080/resources/logo.png
I'm able to reach the logo.
Now my aim is to switch with a folder path taken from my DB.
I've tried this approach:
#EnableWebMvc
#Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {
#Autowired
ConfigurationRepository confRepo;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
myConfiguration conf = confRepo.findByConfKey("downloadPath");
String path = conf.getConfValue();
if(path !=null) {
registry.addResourceHandler("/resources/**").addResourceLocations(path);
}
}
But I can't reach the logo in same way as before.
The path variable is /Applications/MAMP/htdocs/reportMaker/template.
The path variable is /Applications/MAMP/htdocs/reportMaker/template.
According to this documentation https://www.baeldung.com/spring-mvc-static-resources the path should be prefixed by file:/
I've resolved by removing: #EnableWebMvc and adding a / at the end of my path
#Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("file:/Applications/MAMP/htdocs/reportMaker/template/");
}
}
Related
I'm really new to spring and that's why it can be very stupid question, but I got troubled with serving static files. I'm creating a REST api for library app and have some logic when user tries to add a book:
I get principal user from SecurityContextHolder.
I add book and add book to user's list of books
I read the bytes from base64 encoded string and write it to pdf file, stored in /resources/static
And that works. But I don't know how to get this file. I tried to do next:
I made ResourceConfig class that extends WebMvcConfigurer, but it's not worked:
#Configuration
public class ResourceConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/static/**")
.addResourceLocations(StaticAbsolutePath.getPath());
}
}
Oh, the StaticAbsolutePath.getPath() is the metod I made to get path to static directory:
public class StaticAbsolutePath {
private static final String path = "A:\\java\\projects\\books\\src\\main\\resources\\static";
public StaticAbsolutePath() {
}
public static String getPath() {
return path;
}
}
I decided that my security config is blocking this path cuz I'm not authorized, so I added this to config class:
http.authorizeRequests().antMatchers("/static/**").permitAll();
But it'a also was useless. When I try to serf to http://localhost:8080/static/1252356147.pdf, it says that "Whitelabel Error Page".
And here is the screen of resources directory:
So if you know what can be the problem, please tell me, I'd really apreciate it!
Here is the full code of SecurityConfig:
#Configuration #EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
private final BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
CustomAuthenticationFilter customAuthenticationFilter = new CustomAuthenticationFilter(authenticationManagerBean());
customAuthenticationFilter.setFilterProcessesUrl("/api/login");
http.csrf().disable();
http.authorizeRequests().antMatchers("/api/login/**").permitAll();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers(HttpMethod.POST, "/api/users/").authenticated();
http.authorizeRequests().antMatchers(HttpMethod.GET, "/api/user/current").authenticated();
http.authorizeRequests().antMatchers(HttpMethod.POST, "/api/books/**").authenticated();
http.authorizeRequests().antMatchers(HttpMethod.GET, "/api/books/**").permitAll();
http.authorizeRequests().antMatchers(HttpMethod.PUT, "/api/books/**").authenticated();
http.authorizeRequests().antMatchers("/static/**").permitAll();
http.addFilter(customAuthenticationFilter);
http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
UPDATE
I understood that in resources/staic directory should be stored files like HTML and CSS thanks to #Akhil. And I also added the lines of code that he suggested. So my ResourceConfig class now looks like this:
private static final String[] CLASS_PATH_RESOURCE_LOCATIONS = {
"A:\\downloads\\"
};
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/pdf/**")
.addResourceLocations(CLASS_PATH_RESOURCE_LOCATIONS)
.setCacheControl(CacheControl.noCache().cachePrivate())
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
And I changed the directory to store user uploaded files:
But it still not working :(
Full project structure:
Firstly, static files mean files that rarely change for example HTML, CSS files, etc. In your case, the user can upload a pdf file anytime that indicates it's not a static file. What I would suggest is to use a different directory to store PDF and give that path in your resourceConfig. However, if you want to store it in your /resources/static directory then you can do something like this.
ResourceConfigs:
#Configuration
#EnableWebMvc
public class ResourceConfigs implements WebMvcConfigurer {
private static final String[] CLASS_PATH_RESOURCE_LOCATIONS = {
"A:\\downloads\\pdfFiles\\"
};
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pdf/**")
.addResourceLocations(CLASS_PATH_RESOURCE_LOCATIONS)
.setCacheControl(CacheControl.noCache().cachePrivate())
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
}
With this configuration, you can have links like this,
http://localhost:8080/pdf/**
You don't need to configure spring security for this
I'm running a Spring (not Boot) web app and it's finding my JSP views properly, but my CSS isn't being found for some reason. To be clear, the page is loading with the necessary elements, but any CSS styling from classes in my .css files is not being applied. The structure for the CSS file I'm trying to use is src/main/resources/css/style.css.
Below is the relevant code for my AppConfig class:
public class AppConfig implements WebMvcConfigurer {
...
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**")
.addResourceLocations("/css/");
}
...
}
And the JSP header:
<link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css"/>
I've already checked some other questions asking after this issue and have had no luck. Several of them advised checking the config file for Spring Security to ensure that permission is granted for all requests using the resource file but based on what I can see, it shouldn't be prohibiting the CSS from being loaded:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setPasswordEncoder(encoder());
authenticationProvider.setUserDetailsService(userService);
return authenticationProvider;
}
}
For a non-Spring Boot project your css folder should be not in src/main/resources but in src/main/webapp.
You need to tell spring security to ignore css files by overriding this method in WebSecurityConfigurerAdapter:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**","/vendor/**","/fonts/**").anyRequest();
}
The configuration that you posted in your question:
public class AppConfig implements WebMvcConfigurer {
...
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**")
.addResourceLocations("/css/");
}
...
}
tells Spring MVC to serve /css/style.css from the css directory in your context directory. If it doesn't exist, you get a 404.
If you want to serve the file from the classpath (which is what your question seems to imply), then you should do this instead:
public class AppConfig implements WebMvcConfigurer {
...
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**")
.addResourceLocations("classpath:/resources/css/");
}
...
}
See the documentation of ResourceHandlerRegistry for more details.
I have set the context path for tomcat as follows:
#Component
public class CustomContainer implements
WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
#Override
public void customize(TomcatServletWebServerFactory factory) {
factory.setContextPath("/capripol");
factory.setPort(8080);
}
}
Navigating to localhost:8080/capripol works fine and I am prompted with my login screen, however after logging in my forms and controllers do not append to the context path, so instead of navigating to /capripol/MainMenu etc. they navigate to /MainMenu. How do I set the context path such that my form actions and controllers will be appended do it - why is the tomcat factory context path not setting?
Edit: My Application class
#SpringBootApplication
public class CapripolApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(CapripolApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(CapripolApplication.class);
}
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/", "classpath:/images/")
.setCachePeriod(0);
}
}
}
A few ways to do it. You can add it to each controller, usefully if you want to change the context path
#Controller
#RequestMapping(value = "/foo")
public class bar{
#GetMapping(value = "/bar")
public void stuff(){
//doing stuff
}
}
Or you can put it in your application.properties / yml
server.servlet.contextPath=/foo/*
There are technically some other more round about ways to do it, especially if you are using an older version of Spring, but I would think the application properties is what you are looking for.
I have the following configuration for serving static content from Spring Boot.
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Value("${frontend.location}")
private String frontendLocation;
#Override
public void addViewControllers(ViewControllerRegistry reg) {
reg.addViewController("/").setViewName("forward:/index.html");
reg.addViewController("/{x:[\\w\\-]+}").setViewName("forward:/index.html");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations(frontendLocation);
}
}
This works fine as long as there is no server.servlet.context-path. When server.servlet.context-path is configured, it is being passed down to the frontend router as part of the URL.
The solution would be not to forward context path to index.html. How can I achieve that?
I want to add spring mvc interceptor as part of Java config. I already have a xml based config for this but I am trying to move to a Java config. For interceptors, I know that it can be done like this from the spring documentation-
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
}
}
But my interceptor is using a spring bean autowired into it like follows-
public class LocaleInterceptor extends HandlerInterceptorAdaptor {
#Autowired
ISomeService someService;
...
}
The SomeService class looks like follows-
#Service
public class SomeService implements ISomeService {
...
}
I am using annotations like #Service for scanning the beans and have not specified them in the configuration class as #Bean
As my understanding, since java config uses new for creating the object, spring will not automatically inject the dependencies into it.
How can I add the interceptors like this as part of the java config?
Just do the following:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
LocaleInterceptor localInterceptor() {
return new LocalInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeInterceptor());
}
}
Of course LocaleInterceptor needs to be configured as a Spring bean somewhere (XML, Java Config or using annotations) in order for the relevant field of WebConfig to get injected.
The documentation for general customization of Spring's MVC configuration can be found here, and specifically for Interceptors see this section
When you handle the object creation for yourself like in:
registry.addInterceptor(new LocaleInterceptor());
there is no way the Spring container can manage that object for you and therefore make the necessary injection into your LocaleInterceptor.
Another way that could be more convenient for your situation, is to declare the managed #Bean in the #Configuration and use the method directly, like so:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public LocaleInterceptor localeInterceptor() {
return new LocaleInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor( localeInterceptor() );
}
}
Try to inject your service as a constructor parameter. It is simple.
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
ISomeService someService;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor(someService));
}
}
Then reconfigure your interceptor,
public class LocaleInterceptor extends HandlerInterceptorAdaptor {
private final ISomeService someService;
public LocaleInterceptor(ISomeService someService) {
this.someService = someService;
}
}
Cheers !