ホームページ  >  記事  >  ウェブフロントエンド  >  SpringMVCのrestfulアノテーション@RequestBodyがjsonとobject_javascriptのスキルを変換します

SpringMVCのrestfulアノテーション@RequestBodyがjsonとobject_javascriptのスキルを変換します

WBOY
WBOYオリジナル
2016-05-16 15:26:222522ブラウズ

もうすぐ旧正月のため、プロジェクト チームには多くのタスクがありませんでした。そのため、春には安静な通話を研究する自由時間がありました。 Spring が非常に強力になったため、プログラマはインターフェイスを作成する過程でデータ変換や呼び出しを気にする必要がなくなり、ビジネスだけに集中すればよいことがわかりました。以下に、研究の過程で遭遇した手順と問題点をまとめます。

手順:

1. git clone https://github.com/spring-guides/gs-rest-service.git Spring 公式 Web サイトからソースコードをダウンロードしました

2. Maven でコンパイルします (gradle も可)

3. http://localhost:8080/greeting

を実行してアクセスします。

4. 実行結果はオブジェクトを json オブジェクトに変換してページに返すことができます

このとき、リクエストされたデータを Java オブジェクトに自動的に変換する方法を考えていたところ、実際に Spring が HttpMessageConverter コンバータを提供しており、MappingJackson2HttpMessageConverter (json ~object 変換クラス) がデフォルトでロードされていることがわかりました。 )。 @RequestBody Greeting を設定するだけで使用できます。

コントローラー層のコードは次のとおりです:

@RequestMapping(value = "/greeting", method = RequestMethod.POST,consumes = "application/json")
  public @ResponseBody Greeting greeting(@RequestBody Greeting gree) { 
    System.out.println(gree.getContent());
    return gree;
  }

この時、Google のプラグイン (Postman) を介して電話をかけましたが、生死にかかわる電話は失敗しました。

問題を分析して解決する:

現時点で、問題の原因は次の側面にあるのではないかと感じています。

1. Spring はデフォルトでは MappingJackson2HttpMessageConverter をロードしません (具体的なロード方法はわかりません)

2. MappingJackson2HttpMessageConverter がロード後に動作しません (動作しない理由はわかりません)

実際、最終的にうまくいかなかった理由は、Spring のソース コードを信じすぎたためでした (オブジェクトが設定されたメソッドを提供しなかった)。これら 2 つの質問により、インターネット上で大量の検索が行われました。対応する結果が見つかりませんでした。問題の根本原因を見つけて Spring のソース コードを確認する以外に方法はありません。

最初の質問:

ステップ 1: 読み込み型コンバーターを手動で書き直す

@Configuration
  @EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
  public void configureMessageConverters(List<HttpMessageConverter<&#63;>> messageConverters) {
    System.out.println("init convert is start !!!!!");
    StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
    stringConverter.setWriteAcceptCharset(false);
    messageConverters.add(new MappingJackson2HttpMessageConverter());
    System.out.println("init convert is stop !!!!!");
  }
}

テストの結果、まだ使用できないことが判明しましたが、その理由はさらに明らかになっていません。 Spring がデフォルトで型コンバーターをロードする方法のみを確認できます。 WebMvcConfigurationSupport の addDefaultHttpMessageConverters メソッド (キーワード HttpMessageConverter が反映され、使用されている場所を検索し、判断と追跡によって発見されます) では次のように判明します。

@SuppressWarnings("deprecation")
  protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<&#63;>> messageConverters) {
    StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
    stringConverter.setWriteAcceptCharset(false);
    messageConverters.add(new ByteArrayHttpMessageConverter());
    messageConverters.add(stringConverter);
    messageConverters.add(new ResourceHttpMessageConverter());
    messageConverters.add(new SourceHttpMessageConverter<Source>());
    messageConverters.add(new AllEncompassingFormHttpMessageConverter());
    if (romePresent) {
      messageConverters.add(new AtomFeedHttpMessageConverter());
      messageConverters.add(new RssChannelHttpMessageConverter());
    }
    if (jaxb2Present) {
      messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
    }
    if (jackson2Present) {
      messageConverters.add(new MappingJackson2HttpMessageConverter());
    }
    else if (jacksonPresent) {
      messageConverters.add(new org.springframework.http.converter.json.MappingJacksonHttpMessageConverter());
    }
  }
対応するデフォルトのコンバーターがロードされました。ブレークポイントのデバッグにより、デフォルトの構成に問題がないことがわかります。

2番目の問題が原因であるとしか言えませんが、なぜこの問題が発生したのかわかりません(jsonデータの問題、またはその他の問題)。問題がわからないため、リクエストを見ることしかできません。リクエストして、コンバータがどのように動作するかを確認してください。バネについては詳しくないので原理も分かりません。この場合、対応する使用法は (HttpMessageConverter) キー クラスに基づいてのみ見つかります。経験を活かして判断し、デバッグしてください。 AbstractMessageConverterMethodArgumentResolverのreadWithMessageConvertersメソッドが型変換を行うリクエストリクエストの処理メソッドであることが分かります。

protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage,
      MethodParameter methodParam, Type targetType) throws IOException, HttpMediaTypeNotSupportedException {
    MediaType contentType;
    try {
      contentType = inputMessage.getHeaders().getContentType();
    }
    catch (InvalidMediaTypeException ex) {
      throw new HttpMediaTypeNotSupportedException(ex.getMessage());
    }
    if (contentType == null) {
      contentType = MediaType.APPLICATION_OCTET_STREAM;
    }
    Class<&#63;> contextClass = methodParam.getContainingClass();
    Class<T> targetClass = (Class<T>) ResolvableType.forType(targetType,
        ResolvableType.forMethodParameter(methodParam)).resolve();
    for (HttpMessageConverter<&#63;> converter : this.messageConverters) {
      if (converter instanceof GenericHttpMessageConverter) {
        GenericHttpMessageConverter<&#63;> genericConverter = (GenericHttpMessageConverter<&#63;>) converter;
        if (genericConverter.canRead(targetType, contextClass, contentType)) {
          if (logger.isDebugEnabled()) {
            logger.debug("Reading [" + targetType + "] as \"" +
                contentType + "\" using [" + converter + "]");
          }
          return genericConverter.read(targetType, contextClass, inputMessage);
        }
      }
      if (targetClass != null) {
        if (converter.canRead(targetClass, contentType)) {
          if (logger.isDebugEnabled()) {
            logger.debug("Reading [" + targetClass.getName() + "] as \"" +
                contentType + "\" using [" + converter + "]");
          }
          return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
        }
      }
    }
    throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
  }
このとき、HttpMessageConverterのcanReadメソッドにより、対応する型のメッセージコンバータMappingJackson2HttpMessageConverterが見つかり、変換が開始されたが、実行時例外がスローされた。例外がコンソールに出力されないためです。ブレークポイントのデバッグにより、MappingJackson2HttpMessageConverter の readJavaType メソッドがランタイム例外をスローしたことがわかりました。ソース コードから、最下層が Jackson の objectMapper によって操作されていることがわかりました。コードは次のとおりです。

try {
      return this.objectMapper.readValue(inputMessage.getBody(), javaType);
    }
    catch (IOException ex) {
      throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
    }
コードを個別に取り出して main メソッドで実行してもまだ動作しない場合は、問題の場所を特定できます。型が間違っているか、入力データが間違っています。よく調べてみると、jsonデータには問題がなく、jsonobjectを使って変換することもできることが分かりました。現時点では、受信した javaType に問題があるとしか判断できません。それを開いて、オブジェクト (Greeting) に設定されたメソッドがないことがわかった場合、jakson が機能しないため (原理が明確ではない) のではないかと思います。その場合は、このオブジェクトに set メソッドを提供し、再度実行できるようにします。ぐるぐる回ってようやく問題が解けたのですが、この問題を通じてバネの休息の仕組みがより理解できるようになりました。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。