Spring MVC –揭秘了@RequestBody和@ResponseBody

在这篇文章中,我想对Spring MVC进行一些深入的探讨,以揭示将请求转换为参数对象后在幕后发生的情况,反之亦然。 在开始之前,我想解释这些注释的目的。

@RequestBody和@ResponseBody是做什么用的?

它们是spring mvc框架的注释,可用于控制器中以实现智能对象序列化和反序列化。 通过提取消息转换的逻辑并将其作为一个方面,它们可帮助您避免样板代码。 除此之外,它们还帮助您为单个REST资源支持多种格式,而无需重复代码。 如果您使用@ResponseBody注释方法,spring将尝试转换其返回值并将其自动写入http响应。 如果使用@RequestBody注释方法参数,spring会尝试将传入请求主体的内容即时转换为参数对象。

这是一个例子

@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;
    }

}

那么,当我们使用这些注释时,Spring在后台做了什么?

根据您的配置,spring在后台注册了HttpMessageConverters列表。 HttpMessageConverters的职责是根据预定义的mime类型将请求正文转换为特定类,然后再次转换为响应正文。 每当发出的请求命中@RequestBody或@ResponseBody批注时,spring都会循环遍历所有已注册的HttpMessageConverters,以寻找适合给定mime类型和类的第一个,然后将其用于实际转换。

如何添加自定义HttpMessageConverter?

通过分别添加@EnableWebMvc <mvc:annotation-driven />,spring为JSON / XML注册了一堆预定义的消息转换器,等等。 您可以添加如下的自定义转换器

@Configuration
@EnableWebMvc
@ComponentScan
public class WebConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> httpMessageConverters) {
        httpMessageConverters.add(new BookCaseMessageConverter(new MediaType("text", "csv")));
    }
}

在此示例中,我编写了一个转换器,用于处理BookCase的转换,而BookCase基本上是一本Books List。 转换器能够将csv内容转换为BookCase,反之亦然。 我使用opencsv解析文本。

这是模型

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);
    }
}

和实际的转换器

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();
    }
}

结果

现在,我们可以将text / csv请求以及application / json和xml发出给我们的资源,而这些请求基本上是开箱即用的。

  1. PUT /bookcase
    Content-Type: text/csv
    "123","Spring in Action"
    "456","Clean Code"
    
    Response
    204 No Content
  2. GET /bookcase
    Accept: text/csv
    
    Response
    200 OK
    "123","Spring in Action"
    "456","Clean Code"

得益于遵循单责任原则的spring mvc设计,我们的控制器保持纤薄。 如果我们要支持新的媒体类型,则不必添加一行。

完整的示例可以在我的github上找到


翻译自: https://www.javacodegeeks.com/2013/07/spring-mvc-requestbody-and-responsebody-demystified.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值