Panduan Mengarahkan Pengalihan Semula

1. Gambaran keseluruhan

Artikel ini akan menumpukan pada pelaksanaan Redirect pada musim bunga dan akan membincangkan alasan di sebalik setiap strategi.

2. Mengapa Pengalihan?

Mari pertimbangkan terlebih dahulu sebab-sebab mengapa anda mungkin perlu melakukan pengalihan semula dalam aplikasi Spring.

Terdapat banyak contoh dan alasan yang mungkin. Satu yang mudah mungkin adalah data borang POSTing, mengatasi masalah penyerahan dua kali, atau hanya mendelegasikan aliran pelaksanaan ke kaedah pengawal yang lain.

Satu catatan ringkas di sini adalah bahawa corak Post / Redirect / Get yang biasa tidak menangani masalah penyerahan berganda dengan betul - masalah seperti memuat semula halaman sebelum penyerahan awal selesai masih boleh mengakibatkan pengiriman dua kali.

3. Redirect Dengan RedirectView

Mari mulakan dengan pendekatan mudah ini - dan teruskan 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 sebalik tabir, RedirectView akan mencetuskan HttpServletResponse.sendRedirect () - yang akan melakukan pengalihan sebenar.

Perhatikan di sini bagaimana kita memasukkan atribut pengalihan ke dalam kaedah - kerangka kerja akan melakukan pengangkatan berat di sini dan membolehkan kita berinteraksi dengan atribut ini.

Kami menambahkan atribut model model - yang akan didedahkan sebagai parameter pertanyaan HTTP. Model mesti mengandungi hanya objek - umumnya Strings atau objek yang boleh ditukar menjadi Strings.

Sekarang mari kita menguji pengalihan kami - dengan bantuan arahan ikal sederhana :

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

Hasilnya akan:

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

4. Ubah hala dengan pengalihan Awalan :

Pendekatan sebelumnya - menggunakan RedirectView - tidak optimum kerana beberapa sebab.

Pertama- kami kini digabungkan dengan Spring API kerana kami menggunakan RedirectView secara langsung dalam kod kami.

Kedua - kita sekarang harus tahu dari awal, ketika melaksanakan operasi pengawal itu - bahawa hasilnya akan selalu menjadi pengalihan - yang mungkin tidak selalu berlaku.

Pilihan yang lebih baik ialah menggunakan redirect awalan : - nama pandangan pengalihan disuntikkan ke dalam pengawal seperti nama pandangan logik yang lain. Pengawal bahkan tidak menyedari bahawa pengalihan berlaku .

Begini rupa:

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

Apabila nama pandangan dikembalikan dengan awalan redirect: - yang UrlBasedViewResolver (dan semua subkelas) akan mengiktiraf ini sebagai petunjuk khas yang satu keperluan redirect berlaku. Nama paparan selebihnya akan digunakan sebagai URL pengalihan.

Catatan ringkas tetapi penting di sini adalah bahawa - apabila kita menggunakan nama pandangan logik ini di sini - redirect: / redirectedUrl - kita melakukan pengalihan berbanding dengan konteks Servlet semasa .

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

Jadi sekarang, ketika kita melaksanakan perintah curl :

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

Kami akan segera diarahkan:

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

5. Maju dengan Awalan ke hadapan:

Sekarang mari kita lihat bagaimana melakukan sesuatu yang sedikit berbeza - ke depan.

Sebelum kodnya, mari kita kaji ikhtisar peringkat tinggi yang cepat mengenai semantik ke hadapan berbanding pengalihan :

  • pengalihan akan bertindak balas dengan 302 dan URL baru dalam tajuk Lokasi ; penyemak imbas / pelanggan kemudian akan membuat permintaan lain ke URL baru
  • ke hadapan berlaku sepenuhnya di sisi pelayan; wadah Servlet meneruskan permintaan yang sama ke URL sasaran; URL tidak akan berubah dalam penyemak imbas

Sekarang mari kita lihat kodnya:

@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 ke hadapan: awalan akan diselesaikan oleh UrlBasedViewResolver dan subkelasnya. Secara dalaman, ini akan membuat InternalResourceView yang melakukan RequestDispatcher.forward () ke paparan baru.

Apabila kita melaksanakan perintah dengan curl:

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

Kami akan mendapat HTTP 405 (Kaedah tidak dibenarkan):

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

Untuk menyelesaikannya, dibandingkan dengan dua permintaan yang kami miliki dalam hal solusi pengalihan, dalam hal ini, kami hanya memiliki satu permintaan yang keluar dari pelayar / klien ke sisi pelayan. Atribut yang sebelumnya ditambahkan oleh pengalihan tentu saja hilang juga.

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 diarahkan ke lokasi yang dituju:

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

Artikel ini menggambarkan tiga pendekatan yang berbeza untuk melaksanakan pengalihan pada musim bunga , cara menangani / lulus atribut ketika melakukan pengalihan ini serta cara menangani pengalihan permintaan HTTP POST.