Get Root/Base Url In Spring MVC - spring-mvc

What is the best way to get the root/base url of a web application in Spring MVC?
Base Url = http://www.example.com or http://www.example.com/VirtualDirectory

I prefer to use
final String baseUrl =
ServletUriComponentsBuilder.fromCurrentContextPath().build().toUriString();
It returns a completely built URL, scheme, server name and server port, rather than concatenating and replacing strings which is error prone.

If base url is "http://www.example.com", then use the following to get the "www.example.com" part, without the "http://":
From a Controller:
#RequestMapping(value = "/someURL", method = RequestMethod.GET)
public ModelAndView doSomething(HttpServletRequest request) throws IOException{
//Try this:
request.getLocalName();
// or this
request.getLocalAddr();
}
From JSP:
Declare this on top of your document:
<c:set var="baseURL" value="${pageContext.request.localName}"/> //or ".localAddr"
Then, to use it, reference the variable:
Go Home

You can also create your own method to get it:
public String getURLBase(HttpServletRequest request) throws MalformedURLException {
URL requestURL = new URL(request.getRequestURL().toString());
String port = requestURL.getPort() == -1 ? "" : ":" + requestURL.getPort();
return requestURL.getProtocol() + "://" + requestURL.getHost() + port;
}

Explanation
I know this question is quite old but it's the only one I found about this topic, so I'd like to share my approach for future visitors.
If you want to get the base URL from a WebRequest you can do the following:
ServletUriComponentsBuilder.fromRequestUri(HttpServletRequest request);
This will give you the scheme ("http" or "https"), host ("example.com"), port ("8080") and the path ("/some/path"), while fromRequest(request) would give you the query parameters as well. But as we want to get the base URL only (scheme, host, port) we don't need the query params.
Now you can just delete the path with the following line:
ServletUriComponentsBuilder.fromRequestUri(HttpServletRequest request).replacePath(null);
TLDR
Finally our one-liner to get the base URL would look like this:
//request URL: "http://example.com:8080/some/path?someParam=42"
String baseUrl = ServletUriComponentsBuilder.fromRequestUri(HttpServletRequest request)
.replacePath(null)
.build()
.toUriString();
//baseUrl: "http://example.com:8080"
Addition
If you want to use this outside a controller or somewhere, where you don't have the HttpServletRequest present, you can just replace
ServletUriComponentsBuilder.fromRequestUri(HttpServletRequest request).replacePath(null)
with
ServletUriComponentsBuilder.fromCurrentContextPath()
This will obtain the HttpServletRequest through spring's RequestContextHolder. You also won't need the replacePath(null) as it's already only the scheme, host and port.

request.getRequestURL().toString().replace(request.getRequestURI(), request.getContextPath())

Simply :
/*
* Returns the base URL from a request.
*
* #example: http://myhost:80/myapp
* #example: https://mysecuredhost:443/
*/
String getBaseUrl(HttpServletRequest req) {
return ""
+ req.getScheme() + "://"
+ req.getServerName()
+ ":" + req.getServerPort()
+ req.getContextPath();
}

In controller, use HttpServletRequest.getContextPath().
In JSP use Spring's tag library: or jstl

Either inject a UriCompoenentsBuilder:
#RequestMapping(yaddie yadda)
public void doit(UriComponentBuilder b) {
//b is pre-populated with context URI here
}
. Or make it yourself (similar to Salims answer):
// Get full URL (http://user:pwd#www.example.com/root/some?k=v#hey)
URI requestUri = new URI(req.getRequestURL().toString());
// and strip last parts (http://user:pwd#www.example.com/root)
URI contextUri = new URI(requestUri.getScheme(),
requestUri.getAuthority(),
req.getContextPath(),
null,
null);
You can then use UriComponentsBuilder from that URI:
// http://user:pwd#www.example.com/root/some/other/14
URI complete = UriComponentsBuilder.fromUri(contextUri)
.path("/some/other/{id}")
.buildAndExpand(14)
.toUri();

In JSP
<c:set var="scheme" value="${pageContext.request.scheme}"/>
<c:set var="serverPort" value="${pageContext.request.serverPort}"/>
<c:set var="port" value=":${serverPort}"/>
base url
reference https://github.com/spring-projects/greenhouse/blob/master/src/main/webapp/WEB-INF/tags/urls/absoluteUrl.tag

#RequestMapping(value="/myMapping",method = RequestMethod.POST)
public ModelandView myAction(HttpServletRequest request){
//then follow this answer to get your Root url
}
Root URl of the servlet
If you need it in jsp then get in in controller and add it as object in ModelAndView.
Alternatively, if you need it in client side use javascript to retrieve it:
http://www.gotknowhow.com/articles/how-to-get-the-base-url-with-javascript

I think the answer to this question: Finding your application's URL with only a ServletContext shows why you should use relative url's instead, unless you have a very specific reason for wanting the root url.

If you just interested in the host part of the url in the browser then directly from request.getHeader("host")) -
import javax.servlet.http.HttpServletRequest;
#GetMapping("/host")
public String getHostName(HttpServletRequest request) {
request.getLocalName() ; // it will return the hostname of the machine where server is running.
request.getLocalName() ; // it will return the ip address of the machine where server is running.
return request.getHeader("host"));
}
If the request url is https://localhost:8082/host
localhost:8082

Here:
In your .jsp file inside the [body tag]
<input type="hidden" id="baseurl" name="baseurl" value=" " />
In your .js file
var baseUrl = windowurl.split('://')[1].split('/')[0]; //as to split function
var xhr = new XMLHttpRequest();
var url='http://'+baseUrl+'/your url in your controller';
xhr.open("POST", url); //using "POST" request coz that's what i was tryna do
xhr.send(); //object use to send```

Related

AEM Servlet not getting executed

I have a servlet with OSGI annotation like below
#Component( immediate = true, service = Servlet.class, property = { "sling.servlet.extensions=json",
"sling.servlet.paths=/example/search", "sling.servlet.methods=get" } )
public class SearchSevrlet
extends SlingSafeMethodsServlet {
#Override
protected void doGet( final SlingHttpServletRequest req, final SlingHttpServletResponse resp )
throws ServletException, IOException {
log.info("This is not getting called ");
}
}
But When i try to hit the servlet with JQuery
$.get( "/example/search.json", function( data ) {
$( ".result" ).html( data );
alert( "Load was performed." );
});
I am getting below information rather than servlet getting executed.
{"sling:resourceSuperType":"sling/bundle/resource","servletClass":"com.group.aem.example.servlet.SearchSevrlet","sling:resourceType":"/example/search.servlet","servletName":"com.group.aem.example.servlet.SearchSevrlet"}
Please let me know if i need to make any other configuration.
The info that you are getting is the answer of the Default JSON Servlet
Please read this: Servlets and Scripts
You are registering the "SearchServlet" with the property "sling.servlet.paths". This property is defined as:
sling.servlet.paths: A list of absolute paths under which the servlet is accessible as a Resource. The property value must either be a single String, an array of Strings...
That means that your servlet will be only triggered if you request the same exact path, in this case "/example/search", like this:
GET /example/search
I would recommend you to use the properties "resourceTypes" and "selectors" in your Servlet rather than "paths". For example, a better configuration could be:
property = {
"sling.servlet.resourceTypes=/example/search.servlet",
"sling.servlet.selectors=searchselector",
"sling.servlet.extensions=json",
"sling.servlet.methods=GET"
}
With this config, your SearchServlet should be triggered with a GET request to a resource with resourceType="/example/search.servlet", with the selector "searchselector" and the extension "json". For example:
GET /corcoran/search.searchselector.json
I had a similar problem with yours.
To find out what is wrong, I checked "Recent Requests" page.
(at http://localhost:4502/system/console/requests.)
In my case, there was a log saying, "Will not look for a servlet at (my request path) as it is not in the list of allowed paths".
So I moved to "Config Manager" page(at http://localhost:4502/system/console/configMgr), and searched for "Apache Sling Servlet/Script Resolver and Error Handler".
It has a list named "Execution Paths", and I added my request path to the list.
After adding my path to the list, the problem is solved.

Access Denied when trying to forward the request in CQ

All, I'm trying to upload a file in dam in CQ using assestManager and then trying to set values in metadata. Then I'm retrieving all the data one by one and storing in a list, and set it to request object and pass it to new jsp page using 'rd.forward(request, response);' but I'm getting error as:
javax.jcr.AccessDeniedException: Access denied.
even though all the access are given.
Code:-
String redirect = request.getParameter(":redirect"); //content/nextgen/marine/podupload.html
RequestDispatcher rd = request.getRequestDispatcher(redirect);
rd.forward(request, response); // throws me error as access denied
I'm assuming your initial request is a POST?
If so, try the following:
SlingHttpServletRequest newRequest = new SlingHttpServletRequestWrapper(request) {
public String getMethod() {
return "GET";
}
};
newRequest.getRequestDispatcher("/content/nextgen/marine/podupload.html")
.forward(newRequest, response);
If this is a GET request that you are trying to forward then it's a permission issue. If this is a POS or PUT request then you will need a SlingHttpServletRequestWrapper to wrap and modify your request as a GET request forward.
This is simply because sling cannot forward POST requests.

Passing in a date to WebAPI - No HTTP resource was found that matches the request URI

I have a GET request that I make in Chrome Postman. It looks like the following:
http://localhost/WCAPI/Lookup/WCClassDesc/State/AL/Class/7230/DescCode/00/EffDate/2016-04-13
Can anybody see why I would get this response in Postman?
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost/WCAPI/Lookup/WCClassDesc/State/AL/Class/7230/DescCode/00/EffDate/2016-04-13'.",
"MessageDetail": "No action was found on the controller 'WCClassDesc' that matches the request."
}
My code is:
using System;
using System.Web.Http;
/// <summary>
/// API for loading WCClassDescription which is shown on the PremByClass page.
namespace WCAPI.Controllers.Lookup {
[RoutePrefix("Lookup/WCClassDesc")]
public class WCClassDescController : ApiController {
[Route("State/{State}/Class/{Class}/DescCode/{DescCode}/EffDate/{EffDate}")]
public Models.Lookup.WCClassDesc Get(string ClassState, string ClassCode, string DescCode, DateTime EffDate) {
var desc = (new Premium.BLL.WCClassDesc()).GetCurrentWCClassDesc(ClassState, ClassCode, DescCode, EffDate);
var WC = AutoMapper.Mapper.Map<Models.Lookup.WCClassDesc>(desc);
return WC;
}
}
}
Any help or direction would be greatly appreciated.
Jason
There are multiple problems with your code, let's start from the URI:
Assuming you are testing your application using the root path of your host (localhost) and following your definition of RoutePrefix and Route attributes, the correct URI for your resource is the following:
http://localhost/Lookup/WCClassDesc/State/AL/Class/7230/DescCode/00/EffDate/2016-04-13
That's because there is no WCAPI defined in your RoutePrefix attribute.
The other problem is related to the route parameter mapping, you defined you parameters as {State} and {Class}, but then you are asking for ClassState and ClassCode inside your method.
Rename those parameters to match the ones defined in your route, or else Web API will not map them to your method parameters.

Matching a URL to a route in Symfony

We have files behind authentication, and I want to do different things for post-authentication redirect if the user entered the application using a URL of a file versus a URL of an HTML resource.
I have a URL: https://subdomain.domain.com/resource/45/identifiers/567/here/11abdf51e3d7-some%20file%20name.png/download. I want to get the route name for this URL.
app/console router:debug outputs this: _route_name GET ANY subdomain.domain.{tld} /resource/{id2}/identifiers/{id2}/here/{id3}/download.
Symfony has a Routing component (http://symfony.com/doc/current/book/routing.html), and I'm trying to call match() on an instance of Symfony\Bundle\FrameworkBundle\Routing\Router as provided by Symfony IOC. I have tried with with the domain and without the domain, but they both create a MethodNotAllowed exception because the route cannot be found. How can I match this URL to a route?
Maybe a bit late but as I was facing the same problem, what I come to is something like
$request = Request::create($targetPath, Request::METHOD_GET, [], [], [], $_SERVER);
try {
$matches = $router->matchRequest($request);
} catch (\Exception $e) {
// throw a 400
}
The key part is to use $_SERVER superglobal array in order to have all things setted straight away.
According to this, Symfony uses current request's HTTP method while matching. I guess your controller serves POST request, while your download links are GET.
The route name is available in the _route_name attribute of the Request object: $request->attributes->get('_route_name').
You can do something like this ton get the route name:
public/protected/private function getRefererRoute(Request $request = null)
{
if ($request == null)
$request = $this->getRequest();
//look for the referer route
$referer = $request->headers->get('referer');
$path = substr($referer, strpos($referer, $request->getBaseUrl()));
$path = str_replace($request->getBaseUrl(), '', $lastPath);
$matcher = $this->get('router')->getMatcher();
$parameters = $matcher->match($path);
$route = $parameters['_route'];
return $route;
}
EDIT:
I forgot to explain what I was doing. So basicly you are getting the page url ($referer) then taking out your website's base url with str_replace and then trying to match the remaining part of the path with a know route pattern using route matcher.
EDIT2:
Obviously you need to have this inside you controller if you want to be able to use $this->get(...)

How to prevent static resources from being handled by front controller servlet which is mapped on /*

I have a servlet which acts as a front controller.
#WebServlet("/*")
However, this also handles CSS and image files. How can I prevent this?
You have 2 options:
Use a more specific URL pattern such as /app/* or *.do and then let all your page requests match this URL pattern. See also Design Patterns web based applications
The same as 1, but you want to hide the servlet mapping from the request URL; you should then put all static resources in a common folder such as /static or /resources and create a filter which checks if the request URL doesn't match it and then forward to the servlet. Here's an example which assumes that your controller servlet is a #WebServlet("/app/*") and that the filter is a #WebFilter("/*") and that all your static resources are in /resources folder.
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());
if (path.startsWith("/resources/")) {
chain.doFilter(request, response); // Goes to default servlet.
} else {
request.getRequestDispatcher("/app" + path).forward(request, response); // Goes to your controller.
}
See also How to access static resources when mapping a global front controller servlet on /*.
I know this is an old question and I guess #BalusC 's answer probably works fine. But I couldn't modify the URL for the JSF app am working on, so I simply just check for the path and return if it is to static resources:
String path = request.getRequestURI().substring(request.getContextPath().length());
if (path.contains("/resources/")) {
return;
}
This works fine for me.

Resources