SpringMVC源码解读 - RequestMapping注解实现解读 - ConsumesRequestCondition

consumes  指定处理请求的提交内容类型(media-Type),例如application/json, text/html.

所以这边的ConsumesRequestCondition就是通过content type进行url过滤的.

 

具体分析前,我们先准备下基础知识.

  1. MediaType(org.springframework.http包下,封装n多api)

  2. MediaTypeExpression接口,对MediaType和是否匹配关系(=或!=)的封装

  3. AbstractMediaTypeExpression体系,也就是ConsumeMediaTypeExpression和ProduceMediaTypeExpression.

 

// MediaTypeExpression接口

1 package org.springframework.web.servlet.mvc.condition;
2 public interface MediaTypeExpression {
3 
4     MediaType getMediaType();
5 
6     boolean isNegated();
7 
8 }

 

AbstractMediaTypeExpression构造方法处理是否!后,委托MediaType处理

// AbstractMediaTypeExpression

 1     AbstractMediaTypeExpression(String expression) {
 2         if (expression.startsWith("!")) {
 3             isNegated = true;
 4             expression = expression.substring(1);
 5         }
 6         else {
 7             isNegated = false;
 8         }
 9         this.mediaType = MediaType.parseMediaType(expression);
10     }

看看条件匹配的match

// AbstractMediaTypeExpression

 1     public final boolean match(HttpServletRequest request) {
 2         try {
 3             boolean match = matchMediaType(request);
 4             return !isNegated ? match : !match;
 5         }
 6         catch (HttpMediaTypeException ex) {
 7             return false;
 8         }
 9     }
10 
11     protected abstract boolean matchMediaType(HttpServletRequest request) throws HttpMediaTypeException;

Consume和Produce的区别终于出来了

 1 static class ConsumeMediaTypeExpression extends AbstractMediaTypeExpression {
 2         @Override
 3         protected boolean matchMediaType(HttpServletRequest request) throws HttpMediaTypeNotSupportedException {
 4             try {
 5                 MediaType contentType = StringUtils.hasLength(request.getContentType()) ?
 6                         MediaType.parseMediaType(request.getContentType()) :
 7                         MediaType.APPLICATION_OCTET_STREAM;
 8                         return getMediaType().includes(contentType);
 9             }
10             catch (IllegalArgumentException ex) {
11                 throw new HttpMediaTypeNotSupportedException(
12                         "Can't parse Content-Type [" + request.getContentType() + "]: " + ex.getMessage());
13             }
14         }
15 }

 

 1     private final List<ProduceMediaTypeExpression> MEDIA_TYPE_ALL_LIST =
 2             Collections.singletonList(new ProduceMediaTypeExpression("*/*"));
 3 
 4 
 5     /**
 6      * Parses and matches a single media type expression to a request's 'Accept' header.
 7      */
 8     class ProduceMediaTypeExpression extends AbstractMediaTypeExpression {
 9 
10         @Override
11         protected boolean matchMediaType(HttpServletRequest request) throws HttpMediaTypeNotAcceptableException {
12             List<MediaType> acceptedMediaTypes = getAcceptedMediaTypes(request);
13             for (MediaType acceptedMediaType : acceptedMediaTypes) {
14                 if (getMediaType().isCompatibleWith(acceptedMediaType)) {
15                     return true;
16                 }
17             }
18             return false;
19         }
20     }

 

正文

combine方法,这边不做合并,直接覆盖

// ConsumesRequestCondition

1     /**
2      * Returns the "other" instance if it has any expressions; returns "this"
3      * instance otherwise. Practically that means a method-level "consumes"
4      * overrides a type-level "consumes" condition.
5      */
6     public ConsumesRequestCondition combine(ConsumesRequestCondition other) {
7         return !other.expressions.isEmpty() ? other : this;
8     }

 

getMatchingCondition的规则是存在一个即判定匹配

// ConsumesRequestCondition

 1     /**
 2      * Checks if any of the contained media type expressions match the given
 3      * request 'Content-Type' header and returns an instance that is guaranteed
 4      * to contain matching expressions only. The match is performed via
 5      * {@link MediaType#includes(MediaType)}.
 6      *
 7      * @param request the current request
 8      *
 9      * @return the same instance if the condition contains no expressions;
10      *         or a new condition with matching expressions only;
11      *         or {@code null} if no expressions match.
12      */
13     public ConsumesRequestCondition getMatchingCondition(HttpServletRequest request) {
14         if (isEmpty()) {
15             return this;
16         }
17         Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<ConsumeMediaTypeExpression>(expressions);
18         for (Iterator<ConsumeMediaTypeExpression> iterator = result.iterator(); iterator.hasNext();) {
19             ConsumeMediaTypeExpression expression = iterator.next();
20             if (!expression.match(request)) {
21                 iterator.remove();
22             }
23         }
24         return (result.isEmpty()) ? null : new ConsumesRequestCondition(result);
25     }

 

compareTo谁有匹配规则谁牛逼,都有的话比较第一个expression

// ConsumesRequestCondition

 1     public int compareTo(ConsumesRequestCondition other, HttpServletRequest request) {
 2         if (this.expressions.isEmpty() && other.expressions.isEmpty()) {
 3             return 0;
 4         }
 5         else if (this.expressions.isEmpty()) {
 6             return 1;
 7         }
 8         else if (other.expressions.isEmpty()) {
 9             return -1;
10         }
11         else {
12             return this.expressions.get(0).compareTo(other.expressions.get(0));
13         }
14     }

 

看看初始化吧

 1     /**
 2      * Creates a new instance with "consumes" and "header" expressions.
 3      * "Header" expressions where the header name is not 'Content-Type' or have
 4      * no header value defined are ignored. If 0 expressions are provided in
 5      * total, the condition will match to every request
 6      * @param consumes as described in {@link RequestMapping#consumes()}
 7      * @param headers as described in {@link RequestMapping#headers()}
 8      */
 9     public ConsumesRequestCondition(String[] consumes, String[] headers) {
10         this(parseExpressions(consumes, headers));
11     }
12 
13     private static Set<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, String[] headers) {
14         Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<ConsumeMediaTypeExpression>();
15         if (headers != null) {
16             for (String header : headers) {
17                 HeaderExpression expr = new HeaderExpression(header);
18                 if ("Content-Type".equalsIgnoreCase(expr.name)) {
19                     for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
20                         result.add(new ConsumeMediaTypeExpression(mediaType, expr.isNegated));
21                     }
22                 }
23             }
24         }
25         if (consumes != null) {
26             for (String consume : consumes) {
27                 result.add(new ConsumeMediaTypeExpression(consume));
28             }
29         }
30         return result;
31     }

 

你可能感兴趣的:(SpringMVC源码解读 - RequestMapping注解实现解读 - ConsumesRequestCondition)