Spring MVC Java WebMvcConfigurerAdapter.addResourceHandlers - spring-mvc

I'm looking at a project with the following Java Configuration file:
#Configuration
#EnableWebMvc
#ComponentScan("spittr.web")
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
}
}
The project has some static resources in the webapps/resources directory that are being served up. My question is I'm not sure why. It seems for this to work, the above call to addResourceHandlers(...) should be
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources");
}
I tried to look for something in the Spring documentation possibly indicating default values but could not, so I'm not sure why the project works.

The project can serve static resources thanks to DefaultServletHandlerConfigurer:
Configures a request handler for serving static resources by forwarding the request to the Servlet container's "default" Servlet.
I use Jetty in the following example, but other servlet containers (e.g. Tomcat) should behave similarly. Download the Jetty 9 distribution, then inside webapps, create these files:
example/
hello.txt
Start the Jetty server. We have deployed the simplest application imaginable. You should be able to access the file at:
http://localhost:8080/example/hello.txt
The servlet container can serve static resources without any extra configurations. This behavior is suppressed as soon as Spring MVC comes into play. Spring MVC will create a front controller, DispatcherServlet, and park it at "/". Every incoming request will go through this single servlet, and the servlet will find the appropriate component in the app to actually process the request (e.g. a #RequestMapping method in a #Controller class). If no handlers for the request can be found, we have 404s.
The handler DefaultServletHandlerConfigurer has the lowest precedence. If enabled, it allows the front controller to handle the request first. When that fails, it forwards the request to the servlet container, where the request is treated as a static resource read.
This is a quick and dirty way of serving static files. In practice, you don't want anything off the beaten path to be available via a GET. You want to allow only specific files and folders, and you would use WebMvcConfigurerAdapter.addResourceHandlers().

Related

TestRestTemplate and spring security

I am learning spring rest. I am slowly building an application. I had full integration testing working well using TestRestTemplate.
However, I just started adding spring security to my application. Literally as soon as I add the spring security dependency, my testing fails.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
I get these errors like so:
Error while extracting response for type [class [Lcom.myproject.model.viewobjects.AView;] and content type [application/json]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `[Lcom.myproject.model.viewobjects.AView;` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `[Lcom.myproject.model.viewobjects.AView;` out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 1]
When I debug, the object it returns which it is trying deserialize is null. If I put a breakpoint on the rest controller it doesn't even get there.
It seems like just adding the dependency turns a lot of defaults on. How do I test with security on?
1)Can I disable the security for testing somehow?
2)Can I somehow allow no credentials or send acceptable fake credentials? (I did see examples of #WithMockUser but that doesn't work with TestRestTemplate)
Edit:
I tried adding a security implementation to my test class to enable anonymous access and permitall:
#EnableWebSecurity
class TestSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.anonymous().and().authorizeRequests().antMatchers("/**").permitAll();
}
}
The result of this is that #GetMapping work. I can trace that the calls reach the controller. But #PostMapping still do not work. The calls never reach the controller.
The post calls look like so:
updatedAView = restTemplate.postForObject(create_aview_url, aView, AView.class);
Why would get work but not post???
Also, to make sure there wasn't something else, I again went and removed the spring-boot-starter-security dependency and all the code that relates. Suddenly everything works. So it is definitely the security config that does this.
If you include the spring-boot-starter-security dependency, spring security is enabled by default. TestRestTemplate requests will be processed through the security system.
If you want to test without authentication, you can configure a version of WebSecurityConfigurerAdapter with #EnableWebSecurity for testing only that is permissive. You may need to exclude other configurations so they don't override this.
Here is an example:
#EnableWebSecurity
class TestSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.anonymous().and().csrf().disable().authorizeRequests().antMatchers("/**").permitAll();
}
}
This allows you to make requests without user credentials
http.anonymous()
If you don't include the:
csrf().disable()
#GetMapping will work but no PostMapping or requests that change data as that is when csrf comes into play and it is enabled by default.
This permits you to access all the URLs in your application. You can of course limit this if you like:
authorizeRequests().antMatchers("/**").permitAll()

Simplify ResourceHandlerRegistry.addResourceHandler(..)?

Every time I want to use ResourceHandlerRegistry.addResourceHandler(..) to tell Spring a certain directory is resource, I need to specify a path for the handler and a path for resource location, for instance.
registry.addResourceHandler("/javascript/**").addResourceLocations("/javascript/");
registry.addResourceHandler("/html/**").addResourceLocations("/html/");
This gets very repetitive when I have more than one resource directory. Is it possible to tell Spring MVC, "/html" or "/javascript" are resource directories?
Every directory is a directory in spring.
To exclusively specify resource folder you have to have this configuration.
Otherwise for all resource requests spring will start finding out controller mapping.
Found the answer from this other StackOverflow question https://stackoverflow.com/a/31349904/1772825
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}

Grails 3 and Spring #RequestMapping

In Grails 3 I'm trying to use spring-security-oauth, which provides a few endpoints via the #RequestMapping I can see in the mbeans that the path is configured but any request always hits grails and returns a 404.
The requests never seem to hit any of the endpoints configured by the spring-security-oauth lib. Is there anyway to insure the requests hit the endpoints in the jar?
To make sure the endpoints configured by #RequestMapping show in a Grails 3 app using Java config you have to use the following set up in Application.groovy
#ComponentScan("my.org.config")
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application)
}
}
Do not use application.yml in the following way:
grails:
profile: web
spring:
bean:
packages:
- my.org.config
While the beans will be picked up anything with #RequestMapping will not be accessible.

how to call a sling servlet through osgi bundle inside CQ5

I just created a Sling servlet through maven.packaging as - "bundle", then I installed it inside system console of CQ5.
My bundle shows me Active state and all the required packages ..exported successfully.
but I when I call this bundle to use the servlet... nothing happened.
It doesn't give me response.
Is there a better way..to create a sling servlet and create a OSGI bundle,so that I can install it as a bundle in CQ5 to call the servlet from the component.
You can create SlingSerlvet like this.
#SlingServlet(
paths={"/services/myapp/LoginController/validateUser","/services/myapp/LoginController/logout"})
#Properties({
#Property(name="service.pid", value="com.xxx.xxx.controller.LoginController",propertyPrivate=false),
#Property(name="service.description",value="Validates the user", propertyPrivate=false),
#Property(name="service.vendor",value="xxx Tech", propertyPrivate=false)
})
public class LoginController extends SlingAllMethodsServlet{
private static final long serialVersionUID = 1L;
#Override
protected void doPost(SlingHttpServletRequest request,
SlingHttpServletResponse response) throws ServletException,
IOException {
}
#Override
protected void doGet(SlingHttpServletRequest request,
SlingHttpServletResponse response) throws ServletException,
IOException {
}
}
To Call this servlet in browser just type the URLS "/services/myapp/LoginController/validateUser"
And "/services/myapp/LoginController/logout" As you may already know that a serlvet can have multiple URLS.
This is a working piece of Code.
Make sure that your URL Mappings i.e paths(in Sling/CQ5) starts with /services
also you can also create bundle using a dedicated Eclipse for CQ5 CRXDE Eclipse instead of Maven bundle.
It's much easier to use but it is a bit slow. Download Here
Bingo.. finally I am able to call a sling sevlet bundled as OSGI bundle and deployed in CQ's system console.
later I called this OSGI bundle fire a post request and this time able to get the response.
here is a very nice and very explanatory tutorial from Scott that explain every and each steps of my problem.
http://scottsdigitalcommunity.blogspot.in/2013/06/posting-form-data-to-adobe-cq-using.html
and the sample code or sample application link can be found from here -
http://helpx.adobe.com/experience-manager/using/custom-sling-servlets.html
follow the above link step by step and you end up with the victory.
I followed each steps and successfully called OSGI bundle's servlet through component inside CRXDE.
and finally not to forget to thanks Scott.... thanks Scott for the explanation !!!

How do I get Web.xml context-param values in controller action method?

This feels like a basic question, but I haven't had much luck Googling.
My app connects to an SMTP server and sends mail through it. I need this SMTP server to be configurable based on which environment the app is deployed to.
How can I specify the specify the SMTP server name in my web.xml config file and access it from my Spring MVC 3.0 controller?
The controller does not extend or implement anything. It is completely annotation driven with #Controller and #RequestMapping. From what I have seen online, people access context-params via the servlet API. Being annotation driven, I do not have access to the servlet object.
I solved this.
Make your controller implement ServletContextAware, which requires a method called
setServletContext(ServletContext servletContext)
Spring MVC will inject the servlet context into this method if your controller is ServletContextAware.
Create a private variable on your controller to store the servletController that is injected into the above method. You can now use servletContext just as you would if you were using a regular servlet.
hth.
Adding an instance of Servletcontext and autowiring it worked for me
#Controller
public MyController {
// other instances relevant to your requirement
#Autowired
private ServletContext sCtx;
//other methods relevant to your requirement
}
I suppose following also should work:
void action(final HttpServletRequest request) {
final paramValue = request.getSession().getServletContext().getInitParameter("paramName");
...
}

Resources