How to Configure Servlet Mapping and Resource Handler in Spring MVC - spring

I have created sample Spring MVC REST Maven project with following folder structure
ResourceHandlerRegistry configuration as follows
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.raju.spring_app")
public class RootConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static_res/*").addResourceLocations("/WEB-INF/html/static_res/");
}
//Other methods
}
Servlet mapping as follows
public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected String[] getServletMappings() {
return new String[] { "/", "/static_res/*" };
}
//Other Methods
}
The problem is whenever I tried to access resource
http://localhost:8080/spring4_rest_angular_demo/static/css/app.css
I got 404 error.
I want to keep this folder structure to get css IntelliSense suggestions
in index.jsp file.
<link href="static_res/css/app.css" rel="stylesheet"></link>

Few corrections :
Replace
return new String[] { "/", "/static_res/*" };
with
return new String[] { "/" };
and
registry.addResourceHandler("/static_res/*")
with
registry.addResourceHandler("/static_res/**")
Also, the right path is
http://localhost:8080/spring4_rest_angular_demo/static_res/css/app.css
and not
http://localhost:8080/spring4_rest_angular_demo/static/css/app.css

With Spring 3.0.4.RELEASE and higher you can use
<mvc:resources mapping="/resources/**" location="/public-resources/"/>
As seen in http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-static-resources
Also, you should avoid putting pages in WEB-INF. Put the folder with html/css/js higher in hierarchy, under the web app folder. Generally, in WEB-INF there should be only configuration xml files.

Related

best way to dynamically populate .js properties from spring boot runtime application.properties?

tldr
How to best "put" runtime application.properties values from a spring boot app in a javascript file
[Admittedly this is probably a stupid question for the experienced spring dev...so please share how to solve this problem "the spring way"]
Context
We have tiny app which a front-end developer put together and "threw over the wall"..It defines a properties file settings.js:
var SERVERROOT = 'http://solr:8983/solr/operations/select/';
referenced by html :
<script type='text/javascript' src="js/settings.js"></script>
I would like to define the solr path in application.yml at runtime as follows:
app:
solr:
path: 'http://solr:8983/solr/operations/select/'
Question
What is the best way to "populate" this settings.js value from application.properties (or equivalent, i.e. command line arguments, e.g.:
-Dapp.solr.path=...
)
Possible
I thought about putting 'settings.js' as a thymeleaf template (settings.js.html) and having a spring controller populate the model from application.properties.
I didn't know if a more "native spring" method existed.
Thanks!
You could use a ResourceTransformer:
#Component
public class InjectSolrPathResourceTransformer implements ResourceTransformer {
private final MySetting settings; // inject via constructor
#Override
public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) throws IOException {
if (request.getServletPath().equals("/js/settings.js")) {
byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
String content = new String(bytes, StandardCharsets.UTF_8);
content = content.replace("var SERVERROOT = SERVERROOT_VALUE",
"var SERVERROOT = '" + settings.getSolrPath() + "'");
return new TransformedResource(resource, content.getBytes(StandardCharsets.UTF_8));
} else {
return resource;
}
}
}
This assumes that you change settings.js to be:
var SERVERROOT = SERVERROOT_VALUE
To use the ResourceTransformer, register it in your WebMvcConfigurer:
#Configuration
public class WebConfig implements WebMvcConfigurer {
// inject this via constructor
private final InjectSolrPathResourceTransformer resourceTransformer;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**")
.addResourceLocations("classpath:/public/js/")
.addTransformer(resourceTransformer);
}
}
The answer of #Wim above is correct but with new spring boot edition use the below code to register your transformer;
#Configuration
public class WebConfig implements WebMvcConfigurer {
// inject this via constructor
private final InjectSolrPathResourceTransformer resourceTransformer;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**")
.addResourceLocations("classpath:/public/js/")
.resourceChain(false)
.addTransformer(resourceTransformer);
}
}

how to specify welcome-file-list in WebApplicationInitializer.onStartup()

Currently I have a web application where we are using web.xml to configure the application. The web.xml has welcome-file-list.
<web-app>
...
<welcome-file-list>
<welcome-file>home.html</welcome-file>
</welcome-file-list>
</web-app>
We are planning to use spring framework and use java class for application configuration.
class MyApplication extends WebApplicationInitializer {
public void onStartUp(ServletContext context){
...
}
}
How do I specify welcome-file-list in this java class?
While developing Spring MVC application with pure Java Based Configuration, we can set the home page by making our application configuration class extending the WebMvcConfigurerAdapter class and override the addViewControllers method where we can set the default home page as described below.
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.myapp.controllers" })
public class ApplicationConfig extends WebMvcConfigurerAdapter {
#Bean
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
It returns home.jsp view which can be served as home page. No need to create a custom controller logic to return the home page view.
The JavaDoc for addViewControllers method says -
Configure simple automated controllers pre-configured with the
response status code and/or a view to render the response body. This
is useful in cases where there is no need for custom controller logic
-- e.g. render a home page, perform simple site URL redirects, return a 404 status with HTML content, a 204 with no content, and more.
2nd way - For static HTML file home page we can use the code below in our configuration class. It will return index.html as a home page -
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.html");
}
3rd way - The request mapping "/" below will also return home view which can be served as a home page for an app. But the above ways are recommended.
#Controller
public class UserController {
#RequestMapping(value = { "/" })
public String homePage() {
return "home";
}
}
You can't
As specified in Java Doc
public interface WebApplicationInitializer
Interface to be implemented
in Servlet 3.0+ environments in order to configure the ServletContext
programmatically -- as opposed to (or possibly in conjunction with)
the traditional web.xml-based approach.
but you still need minimal configuration in web.xml , such as for
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
#EnableWebMvc
#Configuration
#ComponentScan("com.springapp.mvc")
public class MvcConfig extends WebMvcConfigurerAdapter {
...
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/*.html").addResourceLocations("/WEB-INF/pages/");
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.html");
}
...
}
This might help.
this works for me...
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.html");
}

Spring serving static content while having wildcard controller route

My application is build using backbone on frontend and spring framework on backend. It is a single html application. Routes are handled by backbone, so I have a backend route with the next structure:
#RequestMapping(value="/**", method=RequestMethod.GET)
public String Pages()
{
return "index";
}
To point everything to my index.html. The thing is that the static content
files are pointed to this route too, and I don't want this. I've tried to
config WebMvcConfigurerAdapter by overriding addResourceHandler method for
static content, but it doesn't work.
#Configuration
public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("/resources/js");
}
}
How can I point every route to my index.html except /js/** and /assets/** ?
Thank you
The first thing is that your controller method that's mapped to /** will be taking priority over any resource requests. You can address this by increasing the precedence of ResourceHandlerRegistry. Add a call to registry.setOrder(Ordered.HIGHEST_PRECEDENCE) in the addResourceHandlers method of StaticResourceConfiguration:
#Configuration
public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
registry.addResourceHandler("/js/**").addResourceLocations("/resources/js");
}
}
The second thing is that, by default, Spring Boot configures two resource handlers for you by default, one mapped to /** and one mapped to /webjars/**. Due to the change described above, this will now take priority over the method in your controller that's also mapped to /**. To overcome this, you should turn off default resource handling via a setting in application.properties:
spring.resources.addMappings=false

META-INF/resources not works properly with #EnableWebMVC in Spring Boot

1.
I'm working with Spring Boot. My Main class very simple
#ComponentScan
#EnableAutoConfiguration
#Configuration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#2. Now I would like to make my static content externalised into a jar file. So, below is the jar project
/pom.xml
/src/main/resources/META-INF/resources/hello.json // here is my resource
I do maven install and put the dependency into the main app, run the app normally. Now I can invoke http://localhost:8080/hello.json to get my hello.json file
#3. Then, the next step is using the Apache Tiles for my main web project, so I create a #EnableWebMvc class to configure the tilesViewResolver
#Configuration
#EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
public #Bean TilesViewResolver tilesViewResolver() {
return new TilesViewResolver();
}
public #Bean TilesConfigurer tilesConfigurer() {
TilesConfigurer ret = new TilesConfigurer();
ret.setDefinitions(new String[] { "classpath:tiles.xml" });
return ret;
}
}
Then I started again the application and try the hello.json to ensure everything still works properly. But, the 404 page appear. Delete the WebMvcConfiguration give back my hello.json.
What configuration I should do to resolve this issue?
Thanks a lot.
In Spring MVC, using XML configuration, you have to have a tag like the following to service static content:
<mvc:resources mapping="/js/**" location="/js/"/>
This insinuates that Spring Boot is doing something to automatically guess that you have static content and properly setup the above example in META-INF/resources. It's not really "magic", but rather that they have a default Java Configuration using #EnableWebMvc that has some pretty reliable default values.
When you provide your own #EnableWebMvc, my guess is you are over-writting their "default" one. In order to add back a resource handler, you would do something like this:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
}
This is equivalent to the XML above.

Spring boot for Spring mvc and Angular JS not refreshing static resources

I am running Spring boot in IntelliJ idea and have found that spring boot is no longer refreshing my changes to the resources which is where i have the html and js files. It was working fine but now only seems to detect changes on system reboot.
Is there a way to prevent caching of files ?
let assume you cached the required files like below code :
#SpringBootApplication
public class App extends SpringBootServletInitializer {
#Bean
public WebMvcConfigurerAdapter webConfigurer () {
return new WebMvcConfigurerAdapter() {
#Override
public void addResourceHandlers (ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/js/**")
.addResourceLocations("/static/js/")
.setCacheControl(CacheControl.maxAge(300, TimeUnit.DAYS));
registry.addResourceHandler("/static/images/**")
.addResourceLocations("/static/images/")
.setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
registry.addResourceHandler("/static/css/**")
.addResourceLocations("/static/css/")
.setCacheControl(CacheControl.maxAge(300, TimeUnit.DAYS));
}
};
}
}
add new folder like "nonCached" folder and include your non Cached files like below :

Resources