Spring

What are @RequestBody and @ResponseBody for?
  1. They are annotations of the spring MVC framework and can be used in a controller to implement smart object serialization and deserialization. 
  2. They help you avoid boilerplate code by extracting the logic of message conversion and making it an aspect.
  3. If you annotate a method with @ResponseBody, spring will try to convert its return value and write it to the HTTP response automatically. 
  4. If you annotate a methods parameter with @RequestBody, spring will try to convert the content of the incoming request body to your parameter object on the fly.

Here is an example:-
@Controller
@RequestMapping(value = "/bookcase")
public class BookCaseController {
    private BookCase bookCase;
    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public BookCase getBookCase() {
        return this.bookCase;
    }
    @RequestMapping(method = RequestMethod.PUT)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void setBookCase(@RequestBody BookCase bookCase) {
        this.bookCase = bookCase;
    }
}


So what is Spring doing behind the scenes when we are using those Annotations?

1.  Depending on your configuration, spring has a list of HttpMessageConverters registered in the background. 
2.  A HttpMessageConverters responsibility is to convert the request body to a specific class and back to the response body again, depending on a predefined mime type
3.       Every time an issued request is hitting a @RequestBody or @ResponseBody annotation spring loops through all registered HttpMessageConverters seeking for the first that fits the given mime type and class and then uses it for the actual conversion.
How can i add a custom HttpMessageConverter?

By adding @EnableWebMvc respectively <mvc:annotation-driven />, spring registers a bunch of predefined messageconverters for JSON/XML and so on. 
You can add a custom converter like the following:-
@Configuration
@EnableWebMvc
@ComponentScan
public class WebConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> httpMessageConverters) {
        httpMessageConverters.add(new BookCaseMessageConverter(new MediaType("text", "csv")));
    }
}


In this example i’ve written a converter that handles the conversion of a BookCase, which is basically a List of Books. The converter is able to convert csv content to a BookCase and vice versa. I used opencsv to parse the text.

Here is the model:-
public class Book {
    private String isbn;
    private String title;
    public Book(String isbn, String title) {
        this.isbn = isbn;
        this.title = title;
    }
    // ...
}
public class BookCase extends ArrayList<Book> {
    public BookCase() {
    }
    public BookCase(Collection<? extends Book> c) {
        super(c);
    }
}


and the actual converter:-

public class BookCaseMessageConverter extends AbstractHttpMessageConverter<BookCase> {

    public BookCaseMessageConverter() {
    }

    public BookCaseMessageConverter(MediaType supportedMediaType) {
        super(supportedMediaType);
    }

    public BookCaseMessageConverter(MediaType... supportedMediaTypes) {
        super(supportedMediaTypes);
    }

    @Override
    protected boolean supports(Class<?> clazz) {
        return BookCase.class.equals(clazz);
    }

    @Override
    protected BookCase readInternal(Class<? extends BookCase> clazz, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        CSVReader reader = new CSVReader(new InputStreamReader(httpInputMessage.getBody()));
        List<String[]> rows = reader.readAll();
        BookCase bookCase = new BookCase();
        for (String[] row : rows) {
            bookCase.add(new Book(row[0], row[1]));
        }
        return bookCase;
    }

    @Override
    protected void writeInternal(BookCase books, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
        CSVWriter writer = new CSVWriter(new OutputStreamWriter(httpOutputMessage.getBody()));
        for (Book book : books) {
            writer.writeNext(new String[]{book.getIsbn(), book.getTitle()});
        }
        writer.close();
    }
}

The Result

We can now issue text/csv requests to our Resource along with application/json and xml which are basically supported out of the box.

  • 1
    2
    3
    4
    5
    6
    7
    PUT /bookcase
    Content-Type: text/csv
    "123","Spring in Action"
    "456","Clean Code"
    Response
    204 No Content
  • 1
    2
    3
    4
    5
    6
    7
    GET /bookcase
    Accept: text/csv
    Response
    200 OK
    "123","Spring in Action"
    "456","Clean Code"



  • The Spring MVC framework, one of the most popular frameworks for developing a web application in Java world also provides several useful annotations to extract data from the incoming request and mapping the request to the controller, e.g., @RequestMapping@RequestParam, and @PathVariable.
    As the name suggests, @RequestParam is used to get the request parameters from URL, also known as query parameters, while @PathVariable extracts values from URI.
    For example, if the incoming HTTP request to retrieve a book on topic "Java" is http://localhost:8080/shop/order/1001/receipts?date=12-05-2017, then you can use the @RequestParam annotation to retrieve the query parameter date and you can use @PathVariable to extract the orderId i.e. "1001" as shown below:

    @RequestMapping(value="/order/{orderId}/receipts", method = RequestMethod.GET)
    public List listUsersInvoices(                               @PathVariable("orderId") int order,
     @RequestParam(value = "date", required = false) Date dateOrNull) {
    ...
    }

    The required=false denotes that the query parameter can be optional, but the URL must have the same URI.

    How to extract Query Parameters in Spring MVC using @RequestParam

    Spring MVC is a rich framework to develop both web applications and RESTful web services in Java. It provides several ways to retrieve data from the incoming HTTP requests e.g.
    • Request Parameters
    • Path Variables
    • Form inputs
    Now that you know the difference between @RequestParam and @PathVariable in Spring MVC let's see how to write Spring controllers that can handle request parameters and path variables.


    Using @RequestParam to get Query parameters

    In a Spring MVC application, you can use the @RequestParam annotation to accept query parameters in Controller's handler methods.

    For examples, suppose you have a web application which returns details of orders and trades, and you have the following URLs:

    http://localhost:8080/eportal/orders?id=1001

    To accept the query parameters in the above URLs, you can use the following code in the Spring MVC controller:

    @RequestMapping("/orders")
    public String showOrderDetails(@RequestParam("id") String orderId, Model model){
       model.addAttribute("orderId", orderId);
       return "orderDetails";
    }


    If the name of the query parameter is same as the name of the variable in handler's @RequestParam annotated argument then you can simply use @RequestParam without specifying the name of a query parameter, Spring will automatically derive the value (see Introduction to Spring MVC).
    You can see that we have just annotated the method parameter tradeId with @RequestParam without specifying the name of the query parameter because the name of both request parameter and argument name is same, i.e., "tradeId."
    Also, here is the code to prove the point:

    URL: http://localhost:8080/eportal/trades?tradeId=2001

    @RequestMapping("/trades")
    public String showTradeDetails(@RequestParam String tradeId,
                                   Model model){
      model.addAttribute("tradeId", tradeId);
      return "tradeDetails";
    }

    You can see that we have just annotated the method parameter tradeId with @RequestParam without specifying the name of the query parameter because the name of both request parameter and argument name is same, i.e., "tradeId."
    That's all about the difference between @PathVariable and @RequestParam in Spring MVC. Even though both are used to extract data from URL, @RequestParam is used to retrieve query parameters, anything after ? in the URL, while @PathVariable is used to retrieve values from URI itself.  This concept is essential for both traditional web application development as well as developing RESTful Web Services using Spring, so you must spend some time to understand it better.

    No comments:

    Post a Comment