zoukankan      html  css  js  c++  java
  • SpringMVC源码解读

    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     }
  • 相关阅读:
    算法之顺序、二分、hash查找
    基本数据结构-顺序表和链表!!!
    Deque的应用案例-回文检查
    基本数据结构-双端队列(Deque)
    队列的应用案例-烫手的山芋
    基本数据结构-队列
    基本数据结构-栈
    python中列表,字典,字符串常用操作
    flask中request请求中各种传参
    HTTP请求向服务器传参方式
  • 原文地址:https://www.cnblogs.com/leftthen/p/5210427.html
Copyright © 2011-2022 走看看