Eine Anleitung zu Spring Redirects

1. Übersicht

Dieser Artikel konzentriert sich auf die Implementierung einer Weiterleitung im Frühjahr und erläutert die Gründe für jede Strategie.

2. Warum eine Weiterleitung durchführen?

Betrachten wir zunächst die Gründe, warum Sie möglicherweise eine Umleitung in einer Spring-Anwendung durchführen müssen.

Es gibt natürlich viele mögliche Beispiele und Gründe. Eine einfache Möglichkeit besteht darin, Formulardaten zu POSTEN, das Problem der doppelten Übermittlung zu umgehen oder den Ausführungsfluss einfach an eine andere Controller-Methode zu delegieren.

Eine kurze Randnotiz hier ist, dass das typische Post / Redirect / Get-Muster Probleme mit doppelter Übermittlung nicht angemessen behebt - Probleme wie das Aktualisieren der Seite vor Abschluss der ersten Übermittlung können immer noch zu einer doppelten Übermittlung führen.

3. Mit RedirectView umleiten

Beginnen wir mit diesem einfachen Ansatz - und gehen wir direkt zu einem Beispiel über :

@Controller @RequestMapping("/") public class RedirectController { @GetMapping("/redirectWithRedirectView") public RedirectView redirectWithUsingRedirectView( RedirectAttributes attributes) { attributes.addFlashAttribute("flashAttribute", "redirectWithRedirectView"); attributes.addAttribute("attribute", "redirectWithRedirectView"); return new RedirectView("redirectedUrl"); } }

Hinter den Kulissen löst RedirectView ein HttpServletResponse.sendRedirect () aus, das die eigentliche Weiterleitung ausführt.

Beachten Sie hier, wie wir die Umleitungsattribute in die Methode einfügen. Das Framework übernimmt hier das schwere Heben und ermöglicht uns die Interaktion mit diesen Attributen.

Wir fügen das Modell Attribut Attribut - die als HTTP - Abfrageparameter ausgesetzt wird. Das Modell darf nur Objekte enthalten - im Allgemeinen Strings oder Objekte, die in Strings konvertiert werden können.

Testen wir nun unsere Umleitung - mit Hilfe eines einfachen Curl- Befehls:

curl -i //localhost:8080/spring-rest/redirectWithRedirectView

Das Ergebnis wird sein:

HTTP/1.1 302 Found Server: Apache-Coyote/1.1 Location: //localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectView

4. Weiterleiten Mit der Präfixumleitung :

Der vorherige Ansatz - mit RedirectView - ist aus mehreren Gründen nicht optimal.

Erstens sind wir jetzt mit der Spring-API verbunden, da wir die RedirectView direkt in unserem Code verwenden.

Zweitens - wir müssen jetzt bei der Implementierung dieser Controller-Operation von Anfang an wissen, dass das Ergebnis immer eine Umleitung ist - was möglicherweise nicht immer der Fall ist.

Eine bessere Option ist die Verwendung der Präfixumleitung: - Der Name der Umleitungsansicht wird wie jeder andere logische Ansichtsname in den Controller eingefügt. Der Controller ist sich nicht einmal bewusst, dass eine Umleitung stattfindet .

So sieht das aus:

@Controller @RequestMapping("/") public class RedirectController { @GetMapping("/redirectWithRedirectPrefix") public ModelAndView redirectWithUsingRedirectPrefix(ModelMap model) { model.addAttribute("attribute", "redirectWithRedirectPrefix"); return new ModelAndView("redirect:/redirectedUrl", model); } } 

Wenn ein Ansichtsname mit der Präfixumleitung zurückgegeben wird : - Der UrlBasedViewResolver (und alle seine Unterklassen) erkennt dies als besonderen Hinweis darauf, dass eine Umleitung erfolgen muss. Der Rest des Ansichtsnamens wird als Umleitungs-URL verwendet.

Ein kurzer, aber wichtiger Hinweis ist, dass - wenn wir diesen logischen Ansichtsnamen hier verwenden - redirect: / redirectedUrl - wir eine Umleitung relativ zum aktuellen Servlet-Kontext durchführen .

Wir können einen Namen wie redirect: // localhost: 8080 / spring-redirect-and-forward / redirectedUrl verwenden, wenn wir zu einer absoluten URL umleiten müssen.

Wenn wir also den Befehl curl ausführen :

curl -i //localhost:8080/spring-rest/redirectWithRedirectPrefix

Wir werden sofort umgeleitet:

HTTP/1.1 302 Found Server: Apache-Coyote/1.1 Location: //localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectPrefix

5. Weiterleiten mit dem Präfix vorwärts:

Mal sehen, wie man etwas anderes macht - einen Stürmer.

Lassen Sie uns vor dem Code einen kurzen Überblick über die Semantik von Forward vs. Redirect geben :

  • Die Umleitung antwortet mit einer 302 und der neuen URL im Standort- Header. Der Browser / Client stellt dann eine weitere Anfrage an die neue URL
  • Die Weiterleitung erfolgt vollständig auf der Serverseite. Der Servlet-Container leitet dieselbe Anforderung an die Ziel-URL weiter. Die URL ändert sich im Browser nicht

Schauen wir uns nun den Code an:

@Controller @RequestMapping("/") public class RedirectController { @GetMapping("/forwardWithForwardPrefix") public ModelAndView redirectWithUsingForwardPrefix(ModelMap model) { model.addAttribute("attribute", "forwardWithForwardPrefix"); return new ModelAndView("forward:/redirectedUrl", model); } } 

Wie bei redirect: wird das Vorwärtspräfix: von UrlBasedViewResolver und seinen Unterklassen aufgelöst. Intern wird dadurch eine InternalResourceView erstellt, die einen RequestDispatcher.forward () für die neue Ansicht ausführt .

Wenn wir den Befehl mit curl ausführen :

curl -I //localhost:8080/spring-rest/forwardWithForwardPrefix 

Wir erhalten HTTP 405 (Methode nicht erlaubt):

HTTP/1.1 405 Method Not Allowed Server: Apache-Coyote/1.1 Allow: GET Content-Type: text/html;charset=utf-8

Zum Abschluss haben wir im Vergleich zu den beiden Anforderungen, die wir im Fall der Umleitungslösung hatten, in diesem Fall nur eine einzige Anforderung, die vom Browser / Client an die Serverseite gesendet wird. Das Attribut, das zuvor durch die Umleitung hinzugefügt wurde, fehlt natürlich ebenfalls.

6. Attribute mit den RedirectAttributes

Next – let's look closer at passing attributes in a redirect – making full use the framework with RedirectAttribures:

@GetMapping("/redirectWithRedirectAttributes") public RedirectView redirectWithRedirectAttributes(RedirectAttributes attributes) { attributes.addFlashAttribute("flashAttribute", "redirectWithRedirectAttributes"); attributes.addAttribute("attribute", "redirectWithRedirectAttributes"); return new RedirectView("redirectedUrl"); } 

As we saw before, we can inject the attributes object in the method directly – which makes this mechanism very easy to use.

Notice also that we are adding a flash attribute as well – this is an attribute that won't make it into the URL. What we can achieve with this kind of attribute is – we can later access the flash attribute using @ModelAttribute(“flashAttribute”)only in the method that is the final target of the redirect:

@GetMapping("/redirectedUrl") public ModelAndView redirection( ModelMap model, @ModelAttribute("flashAttribute") Object flashAttribute) { model.addAttribute("redirectionAttribute", flashAttribute); return new ModelAndView("redirection", model); } 

So, to wrap up – if we test the functionality with curl:

curl -i //localhost:8080/spring-rest/redirectWithRedirectAttributes

We will be redirected to the new location:

HTTP/1.1 302 Found Server: Apache-Coyote/1.1 Set-Cookie: JSESSIONID=4B70D8FADA2FD6C22E73312C2B57E381; Path=/spring-rest/; HttpOnly Location: //localhost:8080/spring-rest/redirectedUrl; jsessionid=4B70D8FADA2FD6C22E73312C2B57E381?attribute=redirectWithRedirectAttributes

That way, using RedirectAttribures instead of a ModelMap gives us the ability only to share some attributes between the two methods that are involved in the redirect operation.

7. An Alternative Configuration Without the Prefix

Let's now explore an alternative configuration – a redirect without using the prefix.

To achieve this, we need to use an org.springframework.web.servlet.view.XmlViewResolver:

  /WEB-INF/spring-views.xml    

Instead of org.springframework.web.servlet.view.InternalResourceViewResolver we used in the previous configuration:

We also need to define a RedirectView bean in the configuration:

Now we can trigger the redirect by referencing this new bean by id:

@Controller @RequestMapping("/") public class RedirectController { @GetMapping("/redirectWithXMLConfig") public ModelAndView redirectWithUsingXMLConfig(ModelMap model) { model.addAttribute("attribute", "redirectWithXMLConfig"); return new ModelAndView("RedirectedUrl", model); } } 

And to test it, we'll again use the curl command:

curl -i //localhost:8080/spring-rest/redirectWithRedirectView

The result will be:

HTTP/1.1 302 Found Server: Apache-Coyote/1.1 Location: //localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectView

8. Redirecting an HTTP POST Request

For use cases like bank payments, we might need to redirect an HTTP POST request. Depending upon the HTTP status code returned, POST request can be redirected to an HTTP GET or POST.

As per HTTP 1.1 protocol reference, status codes 301 (Moved Permanently) and 302 (Found) allow the request method to be changed from POST to GET. The specification also defines the corresponding 307 (Temporary Redirect) and 308 (Permanent Redirect) status codes that don't allow the request method to be changed from POST to GET.

Now let's look at the code for redirecting a post request to another post request:

@PostMapping("/redirectPostToPost") public ModelAndView redirectPostToPost(HttpServletRequest request) { request.setAttribute( View.RESPONSE_STATUS_ATTRIBUTE, HttpStatus.TEMPORARY_REDIRECT); return new ModelAndView("redirect:/redirectedPostToPost"); }
@PostMapping("/redirectedPostToPost") public ModelAndView redirectedPostToPost() { return new ModelAndView("redirection"); }

Now, let's test the redirect of POST using the curl command:

curl -L --verbose -X POST //localhost:8080/spring-rest/redirectPostToPost

Wir werden zum Bestimmungsort umgeleitet:

> POST /redirectedPostToPost HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.49.0 > Accept: */* >< HTTP/1.1 200 < Content-Type: application/json;charset=UTF-8 < Transfer-Encoding: chunked < Date: Tue, 08 Aug 2017 07:33:00 GMT {"id":1,"content":"redirect completed"}

9. Fazit

In diesem Artikel wurden drei verschiedene Ansätze zum Implementieren einer Umleitung im Frühjahr erläutert , wie Attribute bei diesen Umleitungen behandelt / übergeben werden und wie Umleitungen von HTTP-POST-Anforderungen behandelt werden.