Simplify ResourceHandlerRegistry.addResourceHandler(..)? - spring-mvc

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();
}

Related

Spring MVC Java WebMvcConfigurerAdapter.addResourceHandlers

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().

Change certain resource strings with robolectric

I have a working robolectric and want to test a component of my application that does HTTP request. Since I don't want these requests to go to my live server but instead to a local test server I want to override a string resources (that contains the servers hostname) during testing.
However, I'm not capable of finding anything in the robolectric documentation that goes remotely in the direction I want :(
I've faced a similar issue in Robolectric 3; you can override a resource at application level using Mockito partial mocks.
First, you tell Robolectric to used a partially mocked Application and to return that when the application context is used: (thanks to this answer: https://stackoverflow.com/a/31386831/327648)
RuntimeEnvironment.application = spy(RuntimeEnvironment.application);
when(RuntimeEnvironment.application.getApplicationContext())
.thenReturn(RuntimeEnvironment.application);
Then you partially mock the Resources object:
Resources spiedResources = spy(app.getResources());
when(app.getResources())
.thenReturn(spiedResources);
Then you can do the real override:
when(spiedResources.getString(R.string.server_address))
.thenReturn("local server address");
I hope this helps.
You can use the technique mentioned at http://robolectric.blogspot.com/2013/04/the-test-lifecycle-in-20.html
This will allow you to override getResources() and use spying to return a hardcoded String or (by default) the String loaded from res/values:
#Override
public Resources getResources() {
Resources resources = spy(super.getResources());
when(resources.getString(R.string.server_address)).thenReturn("local test server address");
return resources;
}

jboss deployment issue - can not visit servlet

I am trying to write a simple web application and deploy on jboss EAP 6. The application is named "webapp" and I was able to build and deploy it to jboss. The context root is /webapp.
I was able to then visit localhost:8080/webapp and it returns a "Hello World" printed from the defaulted index.jsp that was generated by eclipse at /src/main/webapp.
However, when I tried to actually visit the servlet at localhost:8080/webapp/sessionsetup I got the following error:
JBWEB000065: HTTP Status 404 - /webapp/sessionsetup
JBWEB000309: type JBWEB000067: Status report
JBWEB000068: message /webapp/sessionsetup
JBWEB000069: description JBWEB000124: The requested resource is not available.
Below is my simple code for the servlet:
#WebServlet("/sessionsetup")
public class SessionSetup extends HttpServlet{
private static final Logger log = LoggerFactory.getLogger(SessionSetup.class);
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
log.info(this.toString());
log.info("Do get method is called");
response.setContentType("text/xml");
PrintWriter printer = response.getWriter();
printer.println("<html>");
printer.println("<head>" + "</head>");
printer.println("<body>");
printer.println("<h1>" + "Welcome! You are in session setup" + "</h1>");
printer.println("</body>");
printer.println("</html>");
printer.close();
}
}
Could anyone comment on where I might miss something? Is there a way to find some log information no this error? I tried to look for server.log at /standalone/log but couldn't find anything.
There can be 2 reasons
(1) you can configure your standalone.xml in jboss server
virtual-server name="default-host" enable-welcome-root="false">
use false instead of true in enable-welcome-root
(2)
you have not done mapping of controller properly
Problem resolved. It appears to be an issue with the web.xml - once this is removed, the servlet is available.
The actual problem should be the way how it was deployed(Run time name) in the jboss.
So if you try to access the application on that it should works.
Runtime Name: Name by which the deployment should be known within a server's runtime. This would be equivalent to the file name of a deployment file, and would form the basis for such things as default Java Enterprise Edition application and module names. This would typically be the same as 'name', but in some cases users may wish to have two deployments with the same 'runtime-name' (e.g. two versions of "foo.war") both available in the deployment content repository, in which case the deployments would need to have distinct 'name' values but would have the same 'runtime-name'.
This is just my experience about how this problem might happen and the way I have solved issue.
This problems happens in the absence of war file. When I deployed
hawtio
to monitoring jboss which it needs
jolokia
so I just download and deployed manually the .war file into my jboss then problem has been solved.
I think you have to add WEB-INF/jboss-web.xml file in which you have set the context root
<jboss-web>
<context-root>contextroot</context-root>
</jboss-web>
Clean Server to solve this problem in many cases work..

Check for a static file during Application_BeginRequest?

I have a Global.asx file that needs to do custom authentication, auditing and profiling stuff. This is needed because it supports a SAML based SSO system and needs to override the normal .Net authentication (which doesn't support either SAML or mixed authentication)
I don't want to fire it for static files, such as .js, .css, .png, etc
In Cassini/WebDev and IIS7 it does.
What I want to have is some simple check, like a this.Request.IsStaticFile (which doesn't exist, unfortunately) to identify the static files.
I realise that this would be fairly simple to write, but it feels like something that must already exist - IIS has already applied caching policy stuff for the static files and so on.
I need a code solution, rather than an IIS config change one.
Update
This is my current workaround:
/// <summary>Hold all the extensions we treat as static</summary>
static HashSet<string> allowedExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
".js", ".css", ".png", ...
};
/// <summary>Is this a request for a static file?</summary>
/// <param name="request">The HTTP request instance to extend.</param>
/// <returns>True if the request is for a static file on disk, false otherwise.</returns>
public static bool IsStaticFile(this HttpRequest request)
{
string fileOnDisk = request.PhysicalPath;
if (string.IsNullOrEmpty(fileOnDisk))
{
return false;
}
string extension = Path.GetExtension(fileOnDisk);
return allowedExtensions.Contains(extension);
}
This works and is quick enough, but feels horribly clunky. In particular relying on extensions is going to be error prone if we add new static files not thought of.
Is there a better way without changing the IIS config?
You might be able to check which handler is dealing with the request.
In IIS6 only .net files, eg aspx are mapped to a handler that does stuff.
In IIS7 with the integrated pipeline, everything routes through .net, which is normally a good thing. Different handlers still deal with different file types though. In particular I believe the staticfilehandler is the one you need to check for. The httpcontext.handler property should allow you to figure it out.
You could create an extension method to add that IsStatic method...
Simon
There are a few options:
Adding authorization element and deny none for those paths that you do not need any authentication and contains your static files
You are using integrated pipeline. Turn it off on your IIS 7.
There is no doubt that you need to create a custom extension method because ASP.NET routing engine uses this code to decide whether a file exist,
if (!this.RouteExistingFiles)
{
string appRelativeCurrentExecutionFilePath = httpContext.Request.AppRelativeCurrentExecutionFilePath;
if (((appRelativeCurrentExecutionFilePath != "~/") && (this._vpp != null)) && (this._vpp.FileExists(appRelativeCurrentExecutionFilePath) || this._vpp.DirectoryExists(appRelativeCurrentExecutionFilePath)))
{
return null;
}
}
You will not able to decide whether the request is static in Application_BeginRequest using context.handler because Routing Module may change the handler and this module always execute after Application_BeginRequest. My suggestion is to use the similar code which ASP.NEt routing engine uses.

Controller/Routing Errors with js, img files using a CommonServiceLocator ControllerFactory

I've set up an ASP.NET MVC RC2 application to use a custom controller factory backed by a CommonServiceLocator (using StructureMap). Routing to and instantiating controllers works fine, but for some reason I'm getting exceptions when trying to access .js, .jpg, or any other static file.
Here's the ControllerFactory code:
public class CommonServiceLocatorControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
return (controllerType == null) ?
base.GetControllerInstance(controllerType) :
ServiceLocator.Current.GetInstance(controllerType) as IController;
}
}
And the exception is:
The controller for path '/someimage.jpg' could not be found or it does not implement IController.
How can I get the factory or routing engine to bypass the controller factory?
Note: I'll be using IIS7/Integrated Mode, but the error occurs with the built in web server for VS2K8.
The problem was actually due to 404 errors- the path I was requesting for the static content didn't exist, and the base controller factory couldn't handle the request because there was nothing to deliver.
I very much doubt this has anything to do with the ControllerFactory. I've just looked at the source code for DefaultControllerFactory.GetControllerInstance, and I can see no means by which this override could cause the error that you are describing. It is probably due to the way you have configured your routes. Take a look at your routing configuration, write unit tests for it, and if you still can't solve the problem, post your routes here.

Resources