RequestMapping注解中consumes与produces的区别

一直没搞懂RequestMapping中consumes和produces的区别
今天看了下源码,总结一下

说到这两个参数,不得不先回顾一下HTTP协议Header中的两个东西
ContentType 和Accept

在Request中
ContentType 用来告诉服务器当前发送的数据是什么格式
Accept 用来告诉服务器,客户端能认识哪些格式,最好返回这些格式中的其中一种


consumes 用来限制ContentType
produces 用来限制Accept


举例:
有个用户给我发了一个请求,

请求头中
ContentType =application/json
Accept = */*
就是说用户发送的json格式的数据,可以接收任意格式的数据返回

但是我的接口中定义了consumes={"application/xml"},produces={"application/xml"}
我只接收 application/xml 格式,也只返回xml格式

很明显,用户调不通这个接口

所以我改下consumes={"application/xml","application/json"},produces={"application/xml"}
注: 除了格式支持,还需要与数据对应的http转换器(HttpMessageConverter)此处先跳过


MediaType 其实就是 application/xml,application/json 等类型格式

接下来看下源码

AbstractHandlerMethodMapping
在这里通过查找符合类型的method

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
//这里找到所有对应path的方法
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}

if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}


private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}


RequestMappingInfo
在这里对header,consumes和produces进行筛选

public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
[color=red] ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);[/color]

if (methods == null || params == null || headers == null || consumes == null || produces == null) {
return null;
}

PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
if (patterns == null) {
return null;
}

RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
if (custom == null) {
return null;
}

return new RequestMappingInfo(this.name, patterns,
methods, params, headers, consumes, produces, custom.getCondition());
}


ConsumesRequestCondition
对consume的过滤

public ConsumesRequestCondition getMatchingCondition(HttpServletRequest request) {
if (CorsUtils.isPreFlightRequest(request)) {
return PRE_FLIGHT_MATCH;
}
if (isEmpty()) {
return this;
}
MediaType contentType;
try {
contentType = StringUtils.hasLength(request.getContentType()) ?
MediaType.parseMediaType(request.getContentType()) :
MediaType.APPLICATION_OCTET_STREAM;
}
catch (InvalidMediaTypeException ex) {
return null;
}
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<ConsumeMediaTypeExpression>(this.expressions);
for (Iterator<ConsumeMediaTypeExpression> iterator = result.iterator(); iterator.hasNext();) {
ConsumeMediaTypeExpression expression = iterator.next();
if (!expression.match(contentType)) {
iterator.remove();
}
}
return (result.isEmpty()) ? null : new ConsumesRequestCondition(result);
}



ProducesRequestCondition
对Produces的过滤

public ProducesRequestCondition getMatchingCondition(HttpServletRequest request) {
if (CorsUtils.isPreFlightRequest(request)) {
return PRE_FLIGHT_MATCH;
}
if (isEmpty()) {
return this;
}
List<MediaType> acceptedMediaTypes;
try {
//获取Accept
acceptedMediaTypes = getAcceptedMediaTypes(request);
}
catch (HttpMediaTypeException ex) {
return null;
}
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<ProduceMediaTypeExpression>(expressions);
for (Iterator<ProduceMediaTypeExpression> iterator = result.iterator(); iterator.hasNext();) {
ProduceMediaTypeExpression expression = iterator.next();
if (!expression.match(acceptedMediaTypes)) {
iterator.remove();
}
}
if (!result.isEmpty()) {
return new ProducesRequestCondition(result, this.contentNegotiationManager);
}
else if (acceptedMediaTypes.contains(MediaType.ALL)) {
return EMPTY_CONDITION;
}
else {
return null;
}
}



从代码中可以清楚的看到consumes和produces的区别
### 关于 `@RequestMapping` 注解的使用方法 #### 1. 基本概念 `@RequestMapping` 是 Spring MVC 中用于映射 Web 请求到处理器方法上的注解。此注解可以应用于类级别或方法级别,提供了一种灵活的方式来进行 URL 映射以及定义请求处理逻辑[^1]。 #### 2. 类级别的应用 当把 `@RequestMapping` 放置在类上面时,意味着该类下的所有 handler 方法都将继承这个公共前缀路径。这有助于减少重复代码并使URL结构更加清晰[^2]。 ```java @Controller @RequestMapping("/users") // 所有方法默认都会带有 /users 这个基础路径 public class UserController { // ... } ``` #### 3. 方法级别的应用 对于具体的方法而言,在其上方添加 `@RequestMapping` 可以进一步细化访问规则,比如指定HTTP动词(GET/POST等),设置参数约束条件等等[^4]。 ```java @RequestMapping(value="/list", method=RequestMethod.GET) @ResponseBody public List<User> listUsers() { return userService.getAllUsers(); } @RequestMapping(value="/add", method=RequestMethod.POST) @ResponseBody public String addUser(@RequestBody User user) { userService.saveUser(user); return "success"; } ``` 这里展示了两个例子:一个是GET类型的请求用来获取用户列表;另一个则是接收JSON格式的数据并通过POST提交新用户的实例。 #### 4. 参数配置 除了基本的路径 HTTP 动作外,还可以利用其他属性来自定义行为: - **params**: 对应查询字符串中的键值对限制; - **headers**: 需要满足特定头部信息才能触发的目标函数; - **consumes & produces**: 分别指明客户端发送过来的内容类型服务端返回给浏览器的内容编码形式。 例如下面这段代码只会在 Content-Type 设置为 application/json 并且 Accept 头部也接受 JSON 数据的情况下才会被调用: ```java @RequestMapping( value = "/jsonExample", consumes="application/json", produces={"application/json"}, headers="Accept=*/*" ) @ResponseBody public ResponseEntity<String> jsonHandler(@RequestBody MyObject obj){ // handle request... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值