Panduan Untuk Pengalihan Musim Semi

1. Ikhtisar

Artikel ini akan fokus pada penerapan Pengalihan di Musim Semi dan akan membahas alasan di balik setiap strategi.

2. Mengapa Melakukan Pengalihan?

Pertama-tama, pertimbangkan alasan mengapa Anda mungkin perlu melakukan pengalihan di aplikasi Spring.

Ada banyak kemungkinan contoh dan alasan tentunya. Satu yang sederhana mungkin berupa POST data formulir, mengatasi masalah pengiriman ganda, atau hanya mendelegasikan aliran eksekusi ke metode pengontrol lain.

Catatan singkat di sini adalah bahwa pola Kirim / Arahkan Ulang / Dapatkan tidak cukup mengatasi masalah pengiriman ganda - masalah seperti menyegarkan halaman sebelum pengiriman awal selesai mungkin masih mengakibatkan pengiriman ganda.

3. Redirect Dengan RedirectView

Mari kita mulai dengan pendekatan sederhana ini - dan langsung ke contoh :

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

Di balik layar, RedirectView akan memicu HttpServletResponse.sendRedirect () - yang akan melakukan pengalihan sebenarnya.

Perhatikan di sini bagaimana kita memasukkan atribut redirect ke dalam metode - framework akan melakukan pekerjaan berat di sini dan memungkinkan kita untuk berinteraksi dengan atribut ini.

Kami menambahkan atribut atribut model - yang akan diekspos sebagai parameter kueri HTTP. Model hanya boleh berisi objek - umumnya String atau objek yang dapat diubah menjadi String.

Sekarang mari kita uji pengalihan kita - dengan bantuan perintah curl sederhana :

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

Hasilnya adalah:

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

4. Redirect Dengan Prefix redirect:

Pendekatan sebelumnya - menggunakan RedirectView - kurang optimal karena beberapa alasan.

Pertama- kami sekarang digabungkan ke Spring API karena kami menggunakan RedirectView langsung di kode kami.

Kedua - kita sekarang perlu tahu dari awal, saat mengimplementasikan operasi pengontrol - bahwa hasilnya akan selalu berupa pengalihan - yang mungkin tidak selalu demikian.

Pilihan yang lebih baik adalah menggunakan pengalihan awalan : - nama tampilan pengalihan dimasukkan ke dalam pengontrol seperti nama tampilan logis lainnya. Pengontrol bahkan tidak menyadari bahwa pengalihan sedang terjadi .

Berikut tampilannya:

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

Ketika nama tampilan dikembalikan dengan awalan redirect: - yang UrlBasedViewResolver (dan semua subclass) akan mengenali ini sebagai indikasi khusus bahwa kebutuhan redirect terjadi. Nama tampilan lainnya akan digunakan sebagai URL pengalihan.

Catatan singkat namun penting di sini adalah - saat kami menggunakan nama tampilan logis di sini - redirect: / redirectedUrl - kami melakukan pengalihan relatif ke konteks Servlet saat ini .

Kita bisa menggunakan nama seperti redirect: // localhost: 8080 / spring-redirect-and-forward / redirectedUrl jika kita perlu mengalihkan ke URL absolut.

Jadi sekarang, saat kita menjalankan perintah curl :

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

Kami akan segera dialihkan:

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

5. Teruskan Dengan Awalan maju:

Sekarang mari kita lihat bagaimana melakukan sesuatu yang sedikit berbeda - penyerang.

Sebelum kode, mari kita lihat ikhtisar cepat tingkat tinggi dari semantik maju vs. pengalihan :

  • redirect akan merespon dengan 302 dan URL baru di header Lokasi ; browser / klien kemudian akan membuat permintaan lain ke URL baru
  • maju terjadi sepenuhnya di sisi server; penampung Servlet meneruskan permintaan yang sama ke URL target; URL tidak akan berubah di browser

Sekarang mari kita lihat kodenya:

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

Sama seperti redirect: , yang maju: awalan akan diselesaikan oleh UrlBasedViewResolver dan subclass. Secara internal, ini akan membuat InternalResourceView yang melakukan RequestDispatcher.forward () ke tampilan baru.

Saat kami menjalankan perintah dengan curl:

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

Kami akan mendapatkan HTTP 405 (Metode tidak diizinkan):

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

Sebagai penutup, dibandingkan dengan dua permintaan yang kami miliki dalam kasus solusi pengalihan, dalam kasus ini, kami hanya memiliki satu permintaan yang keluar dari browser / klien ke sisi server. Atribut yang sebelumnya ditambahkan oleh pengalihan, tentunya juga hilang.

6. Atribut Dengan 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

Kami dialihkan ke lokasi yang ditakdirkan:

> 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. Kesimpulan

Artikel ini mengilustrasikan tiga pendekatan berbeda untuk menerapkan pengalihan di Spring , cara menangani / meneruskan atribut saat melakukan pengalihan ini, serta cara menangani pengalihan permintaan HTTP POST.