Mapowanie requestów HTTP

Mapowanie żądań to bardzo ważna funkcjonalność, umożliwiająca skierowanie przetwarzania żądań HTTP do odpowiednich metod w języku Java. Aby to osiągnąć, niezbędne są informacje o ścieżce (path), na którą skierowano żądanie, oraz o typie metody HTTP użytej podczas jego wysyłania. Te dane pozwalają frameworkowi na precyzyjne dopasowanie żądania do właściwej metody obsługującej, zapewniając tym samym efektywne i zorganizowane przetwarzanie żądań w aplikacjach webowych.

Adnotacje mapujące

Zgodnie z tym co opisujemy w tekście Starter REST, wyróżniamy kilka metod, które uczestniczą w obsłudze żądań. Najważniejsze z nich to: GET, PUT, POST, DELETE. To właśnie one muszą znaleźć swoje odpowiedniki po stronie frameworka, aby Spring mógł uruchomić właściwą metodę. Jak wiążemy metody Java z konkretnymi metodami HTTP?

Używamy w tym celu adnotacji, których lista wygląda następująco:
  • Adnotacja @GetMapping

    Dawniej, przed Springiem w wersji 4.3 adnotacja występowała tylko pod postacią:
    @RequestMapping(method = RequestMethod.GET)

    Obecnie adnotacja ta jest częścią adnotacji @GetMapping, której użycie powoduje że kod jest nieco bardziej przejrzysty (wspominamy o tym nieco szerzej w dalszej części rozdziału).

    Adnotacją oznaczamy metodę, która ma przyjąć nasze żądanie GET, np.:
    @GetMapping(value = "/image/{appaItemId}/{imageName:.+}")
    public void getImage(@PathVariable Long appaItemId, 
                            @PathVariable String imageName, ...) throws Exception {
    
        imageLoader.copyImage(imageName, appaItemId, request, response);
    }
    
    Jak widać adnotacja @GetMapping przyjmuje jako parametr value ścieżkę, którą framework dopasowuje do ścieżki (path), na którą zotało wysłane żądanie. Jeśli ścieżki się zgadzają następuje uruchomienie metody i wykonanie jej kodu.

    Reasumując, jeśli wysłaliśmy na serwer (na którym działa Spring MVC) żądanie HTTP za pomocą metody HTTP GET oraz zdefiniowaliśmy URL tego żądania, na przykład: "/image/17/obrazek.jpg", to wówczas Spring przechwyci takie żądanie i uruchomi metodę getImage.

    Co oznacza adnotacja @PathVariable oraz jak interpretować fragment mapowania ścieżki "/{appaItemId}/{imageName:.+}" ?
    Zainteresowanych odpowiedzią na to pytanie zapraszamy do rozdziału Spring MVC - Mapowanie danych w requestach HTTP.
  • Adnotacja @PostMapping

    Dawniej: @RequestMapping(method = RequestMethod.POST)

    Obecnie adnotacja ta jest częścią adnotacji @PostMapping.
    Adnotacją oznaczamy metodę, która ma przyjąć nasze żądanie POST, np.:
    @PostMapping(value = "/xls")
    public ResponseEntity<Void> importAppaItems(@RequestParam MultipartFile file)
    		throws Exception {
    
        ...
        return new ResponseEntity<Void>(HttpStatus.OK);
    }
    
    Jak widać adnotacja @PostMapping również przyjmuje jako parametr value ścieżkę, którą framework dopasowuje do ścieżki (path), na którą zotało wysłane żądanie. Tak samo jak w przypadku adnotacji @GetMapping jeśli ścieżki się zgadzają następuje uruchomienie metody i wykonanie jej kodu. Podobnie będzie to wyglądać dla pozostałych adnotacji.

    O adnotacji @RequestParam piszemy w rozdziale Spring MVC - Mapowanie danych w requestach HTTP.
  • Adnotacja @PutMapping

    Dawniej: @RequestMapping(method = RequestMethod.PUT)

    Obecnie adnotacja ta jest częścią adnotacji @PutMapping.
    Adnotacją oznaczamy metodę, która ma przyjąć nasze żądanie PUT, np.:
    @PutMapping("/current/roles/{newRoleName}")
    public ResponseEntity<Void> updateCurrentUserRole(@PathVariable("newRoleName") ...
    
        ...
        return new ResponseEntity<Void>(HttpStatus.OK);
    }
    
  • Adnotacja @DeleteMapping

    Dawniej: @RequestMapping(method = RequestMethod.DELETE)

    Obecnie adnotacja ta jest częścią adnotacji @DeleteMapping.
    Adnotacją oznaczamy metodę, która ma przyjąć nasze żądanie DELETE, np.:
    @DeleteMapping("/{appaItemId}")
    public ResponseEntity<Void> delete(@PathVariable Long appaItemId) throws Exception {
    
        appaItemService.deleteAppaItem(appaItemId);
        
        return ResponseEntity.noContent().build();
    }
    
  • Adnotacja @PatchMapping

    Dawniej: @RequestMapping(method = RequestMethod.PATCH)

    Obecnie adnotacja ta jest częścią adnotacji @PatchMapping.
    Adnotacją oznaczamy metodę, która ma przyjąć nasze żądanie PATCH, np.:
    @PatchMapping("/{id}")
    public ResponseEntity<Void> updatePart(@RequestBody User userPart,
                                                    @PathVariable("id") Long id) {
    
        ...
        
        return new ResponseEntity<Void>(HttpStatus.OK);
    }
    


    O adnotacji @RequestBody piszemy w rozdziale Spring MVC - Mapowanie danych w requestach HTTP.

Składanie ścieżek

Jak już wiesz, dedykowane adnotacje w pewien sposób poprawiają nasz kod, ponieważ staje się on bardziej przejrzysty. No dobrze, ale czy możemy się pozbyć całkowicie adnotacji @RequestMapping? Okazuje się, że nie, ponieważ nadal będziemy używać tej adnotacji, aby zmapować całą klasę (a nie tylko metodę) naszego kontrolera na konkretną scieżkę. Zobaczmy rozwinięcie naszego pierwszego przykładu o adnotacji @GetMapping:
@RestController
@RequestMapping("/api/appaform/appaimages")
public class ImageController {

    ...
    
    @GetMapping(value = "/image/{appaItemId}/{imageName:.+}")
    public void getImage(@PathVariable Long appaItemId, 
                            @PathVariable String imageName, ...) throws Exception {
    
    	imageLoader.copyImage(imageName, appaItemId, request, response);
    }
}
Jak widać adnotacja @RequestMapping określa ścieżkę w postaci "/api/appaform/appaimages". Oznacza to, że Spring próbując dopasować ścieżkę z przychodzącego żądania będzie rozpoczynał dopasowywanie od "neutralnej" adnotacji na klasie, a później skleji ją ze ścieżką określoną dla adnotacji dedykowanej na metodzie. Jeśli całość będzie się zgadzała, wówczas wybrana metoda zostanie uruchomiona.

Mając teraz wszystkie dane o kontrolerze już wiemy, że jeśli wysłaliśmy na serwer żądanie HTTP za pomocą metody HTTP GET oraz zdefiniowaliśmy URL tego żądania, na przykład: "/api/appaform/appaimages/image/17/obrazek.jpg", to wówczas Spring przechwyci takie żądanie i uruchomi metodę getImage.

Metoda HEAD

Na koniec jeszcze jedna kwestia, która z pewnością nie daje żyć czytelnikom dążącym do porządku idealnego. Mowa o braku adnotacji @HeadMapping, która mogłaby odpowiadać metodzie HTTP HEAD. Dlaczego Spring MVC nie definiuje w ogóle takiej adnotacji?

Otóż zgodnie ze specyfikacją, żądanie HEAD jest podobne do GET, ale nie wymaga od serwera zwracania treści odpowiedzi, tylko nagłówków. Spring MVC automatycznie obsługuje żądania HEAD dla każdego endpointu zdefiniowanego przez @GetMapping, co może tłumaczyć brak potrzeby definiowania oddzielnej adnotacji @HeadMapping. Mimo to, można argumentować, że wprowadzenie takiej adnotacji mogłoby przyczynić się do większej czytelności w definicjach endpointów.
Rekomendacja
Kluczowym aspektem, na który należy zwrócić uwagę podczas pracy z Spring MVC, jest odpowiedni dobór metod HTTP oraz związanych z nimi adnotacji, dostosowanych do realizowanego zadania. Zachęcamy do zapoznania się z ogólnymi zasadami dotyczącymi metod HTTP dostępnymi w sekcji Starter REST. Szczególnie polecamy zwrócić uwagę na koncepcję idempotentności. Jest to nie tylko istotny aspekt przy wyborze odpowiedniej metody HTTP, ale również popularny temat podczas rozmów kwalifikacyjnych. Zrozumienie i stosowanie tych zasad jest kluczowe dla efektywnego i profesjonalnego tworzenia aplikacji webowych.
Praktyka


Prawie wszystkie przykłady przytoczone wyżej (poza Patch Mapping) pochodzą z kodu aplikacji.
Zdjęcie autora
Autor: Jarek Klimas
Data: 03 stycznia 2024
Labele: Backend, Podstawowy, Java
Topowe Materiały
Spring IO: Mapping Requests
Baeldung: Spring Web Annotations
Baeldung: Guide to Spring Handler Mappings
Baeldung: Spring RequestMapping

Udemy: [NEW] Spring Boot 3, Spring 6 & Hibernate for Beginners  —  polskie napisy

Stale się rozwijamy, a więc bądź na bieżąco!
Na ten adres będziemy przesyłać informacje o ważniejszych aktualizacjach, a także o nowych materiałach pojawiających się na stronie.
Polub nas na Facebooku:
Nasi partnerzy: stackshare
Javappa to również profesjonalne usługi programistyczne oparte o technologie JAVA. Jeśli chesz nawiązać z nami kontakt w celu uzyskania doradztwa bądź stworzenia aplikacji webowej powinieneś poznać nasze doświadczenia.
Kliknij O nas .


Pozycjonowanie stron: Grupa TENSE