0

I have inherited a JAVA Spring MVC web app. I'm totally new to Spring MVC and very much a novice at JAVA. But my first task is to add the application's URL into an email that is already generated through code.

It is basically a way for the user to click the link and go directly to a specific page. But when I try all the various things I have seen on here that involve HttpServletRequest and more importantly getRequestURL().

I can only get the URL after the Controller takes over. What I need is the what I will refer to as the referring URL--the application URL I see in the browser.

The Controller is a REST service and returns localhost:8181/etc/etc which doesn't even include the domain for the site. I have tried the various methods like getHeader("Referer") etc. Again, they just return the post-Controller URL. I've tried added the code to get the correct URL pre-Controller and then pass it to the Controller method. Still gives me the post-Controller URL.

Rmahajan
  • 1,311
  • 1
  • 14
  • 23
STP
  • 51
  • 8
  • For getting the request before the controllers start processing it use a [HttpFilter](https://javaee.github.io/javaee-spec/javadocs/javax/servlet/http/HttpFilter.html). For getting the domain try read the `Host` header of the request (`request.getHeader("Host")`) –  Feb 12 '19 at 22:57
  • @ValentinCarnu the HttpFilter is a low level concept. Let it stay on pure Servlets applications. Using Spring we can use more abstracted approaches. – LppEdd Feb 12 '19 at 23:06
  • @LppEdd Filters offers more options when it comes to processing the request, on [Spring HandlerInterceptor vs Servlet Filters](https://stackoverflow.com/a/8006367/10386912) thread there are some details about the differences. Spring framework also leverages the use of filters along with Interceptors –  Feb 12 '19 at 23:37

2 Answers2

0

You need some kind of HandlerInterceptorAdapter / HandlerInterceptor.
Inside the preHandle method, you can get a hold on the HttpServletRequest object.

@Override
public boolean preHandle(
        final HttpServletRequest request,
        final HttpServletResponse response,
        final Object handler
) throws Exception {
   // Obtain only the hostname, with the associated port
   final String hostOnly = request.getHeader("Host");

   // Obtain the request URL, excluding query parameters
   final String completeUrl = request.getRequestURL().toString();

   // ... Continue towards the method handler
}

request.getRequestURL() returns a StringBuffer, which you can use to manipulate the URL, before building a String from it.


The same URL retrieval concept can be applied to a @Controller/@RestController handler method, if you need it there. Just insert an HttpServletRequest as input parameter.

@GetMapping
public ResponseEntity<?> myHandlerMethod(
          final HttpServletRequest request, 
          /* other parameters */) {
   ... 
}

You can even accept a WebRequest or NativeWebRequest

@GetMapping
public ResponseEntity<?> myHandlerMethod(
          final WebRequest request, 
          /* other parameters */) {
   final String host = request.getHeader("host");
   ...
}

@GetMapping
public ResponseEntity<?> myHandlerMethod(
          final NativeWebRequest request, 
          /* other parameters */) {
   final HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class);
   final String host = request.getHeader("host");
   ...
}

Edit, based on your comment.

@PostMapping(value = "myurl/{x}/(y)", produces = ...")
public ResponseEntity<String> doSomething(
         final HttpServletRequest request,
         @PathVariable("x") final String x,
         @PathVariable("y") final String y) {
   final String hostOnly = request.getHeader("Host");  // http://yourdomain.com:80

   if (service.sendEmail(x, y, hostOnly)) {
      return new ResponseEntity<>("...");
   } 

   ...
LppEdd
  • 20,274
  • 11
  • 84
  • 139
  • thanks @LppEdd. But I am back to square one . . . the wrong url . . . the localhost one. . . not the one from the intercepter. – STP Feb 14 '19 at 19:26
  • @STP what do you mean "the one from the interceptor"? Tell me exactly which URL you are expecting – LppEdd Feb 14 '19 at 19:27
  • this the why I posted this question. before I ever added the intercepter that you helped me with I was getting "localhost:8181/etc/etc/etc" as the URL from the request the post controller mapping. I need the one before the controller takes over which the intercepter gives me once I set it up. . . inside the preHandle . . . which is like "myapp.mydomain.com/etc/etc/etc". I need access to this preHandle variable from within the controller as a variable to pass to my service to print to this email that is generated. – STP Feb 14 '19 at 19:41
  • @STP if you're testing your application at "localhost", you'll get "localhost". Are you testing your app locally? – LppEdd Feb 14 '19 at 19:43
  • no I'm not. I want the browser url which is a domain url. – STP Feb 14 '19 at 19:49
  • and the intercepter gets the browser domain url because I am printing that to the err log and clearly see it in there which is why I continued down this path . . . of your solution to my question – STP Feb 14 '19 at 19:50
  • @STP it is **not** possible for the HandlerInterceptor to display "yourdomain.com:80" and for the handler method to display "localhost:80". They'll always display the same thing. I'd like to see a screenshot while debugging. – LppEdd Feb 14 '19 at 20:02
  • well it is. unfortunately I cannot provide actual code or screen shots or access etc. – STP Feb 14 '19 at 20:14
  • @STP you must be doing something wrong. I work daily on this and I assure you the HttpServletRequest is shared between the Interceptor and the handler method on each call. – LppEdd Feb 14 '19 at 20:18
  • LOL Sorry after working days on this I am just about done with it. I have tried everything. Just tried setting and getting the session. It comes out with localhost too. So I have no idea. – STP Feb 14 '19 at 20:35
  • @STP the thing is you're dealing with code, not something that changes over time. Place a breakpoint on the Interceptor, take a screenshot of the URL value, place another breakpoint just when you enter the controller method during the same call and take a screenshot of the URL value there. Then post them. I'm curious, not becase I don't "trust" you, but because I trust the code. – LppEdd Feb 14 '19 at 20:39
  • I cannot share those details as I said. And I have printed out to System.err.println like I said above inside the intercepter when I get the URL and then again inside the controller when I get it again. It is the domain in the intercepeter and localhost in the intercepter. I will just have to ask them to explain to me what the finer details of the architecture is. This shouldn't be this hard. I was excited to the see what I was looking for from inside the intercepter in the error log after setting it up. But since I cannot persist that value in anyway then it does me no good. – STP Feb 14 '19 at 21:21
  • @STP check this answer tomorrow morning (I'm on GMT +2). I'll post a **temporary** workaround. Anyway I'm only asking you to screenshot a URL, not your code. – LppEdd Feb 14 '19 at 21:23
  • I asked the two ppl on this project about the architecture. Inside this controller the program reaches out to another application with a soap envelope. The other application returns it to the application--the response. THis obviously is where the breakdown takes place. The other application was apparently hardocded to return to localhost as they are both on the same server. So I asked that they fix this. So I appreciate your help here though. I will revisit it after they do their part. I didn't think this should take this much effort even if I am new to Spring MVC. – STP Feb 15 '19 at 15:32
0

Pass a parameter of type UriComponentsBuilder into your controller method, and it will be pre-populated with the base context that the user originally used to make the request. Then you can do this:

String uri = MvcUriComponentsBuilder.relativeTo(uriBuilder)
        .withMethodName(MyController.class, "someMethod", parameterValue)
        .toUriString();
chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
  • Thanks but it gave me the post-Controller@RequestMapping URL like all the other attempts. :-( – STP Feb 13 '19 at 02:13
  • @STP You'll need to add more detailed information, then. Perhaps your service is living behind a proxy that's not correctly forwarding `Forwarded` or `X-Forwarded-For` headers. – chrylis -cautiouslyoptimistic- Feb 13 '19 at 02:54