問題のI.概要:
PUTのAjaxを直接送信要求が、カプセル化されたオブジェクトスプリングMVC、URIを介して他のIDフィールドは、正常にオブジェクトにデータ要求体でカプセル化されているが囲まれていません。
request.getParameter()メソッドを使用してすることにより、HttpServletRequestオブジェクトだけでなく、データを取得しない。試験によって、要求がデータのフロントエンドから来ます
第二に、解決策:
原則下を向く、HttpPutFormContentFilterフィルターのweb.xmlを追加します。
1 < フィルター> 2 < フィルタ - 名> httpPutFormContentFilter </ フィルタ -name > 3 < フィルタ - クラス> org.springframework.web.filter.HttpPutFormContentFilter </ フィルタリング級> 4 </ フィルタ> 5 < フィルタ - マッピング> 6 < フィルタ - 名> httpPutFormContentFilter </ フィルタ -name > 7 < URL - パターン> / * </ URL -pattern > 8 </ フィルタ -mapping >
第三に、分析の理由:
データは、地図としてパッケージ本体1 Tomcatを要求します、各オブジェクトの属性値のオブジェクトもrequest.getParameter呼び出されたときに、この値からrequest.getParameter()を呼び出すと、地図、Spring MVCのPOJOパッケージとなります()を取得する方法、および、適切なオブジェクトプロパティ、完全なカプセル化特性に割り当てられました。
データ2.しかし、PUT要求、Tomcatのパッケージは、マップ本体の要求ではないマップにカプセル化されたPOST要求データ要求の本体のみ、そう、直接呼び出しrequest.getParameter()メソッドか、又はSpring MVCのパッケージオブジェクトは、確かにプロパティの値を取得するために失敗します。
第四に、ソースコード解析:
1. TomcatのRequest.javaクラスのソースコードorg.apache.catalina.connectorパケットparseParameters()メソッドは、要求パラメータを解析するために使用され、最初の一連の方法は、配置と判断し、その要求パラメータを解析します。タイプを要求する次のコードが決定され、条件が直接返され満たされた場合、すなわち決定されないparseBodyMethod要求は、現在の実施形態は、含まれている場合、Tomcatサーバがパラメータ解決要求体の処理を続行、パッケージを含みますマップに、そうでない場合には、対応するパラメータにはマップされていない、むしろ解像度パラメータの以下の方法を実行するよりも、直接返します。
1 であれば(!。getConnector()isParseBodyMethod(getMethod()メソッド)){ 2つの 成功= 真。 3 リターン ; 4 }
2. getConnector()メソッドは、現在接続を得るために使用され、その後、決定することを含むのisParseBodyMethod()メソッドを呼び出して設定parseBodyMethodSet値がメソッドに渡されず、この方法は、要求タイプの電流値です。
1 / ** 2 * Request.javaクラス 3 *現在の実施例を取り出す 。4 * / 5 公共ストリングgetMethod()メソッド{ 6 リターン coyoteRequest.method()のtoString();. 。7 } 。8 。9 / ** 10 *コネクタ.javaクラス 11 * / 12である 保護 ブール isParseBodyMethod(文字列法){ 13は リターン parseBodyMethodsSet.contains(方法); 14 }
3. parseBodyMethodSetはparseBodyMethods parseBodyMethodSetに割り当てられた値に相当する一般的に使用される値は、デフォルトの設定され、デフォルト値はparseBodyMethodsポストです。
1 / ** 2 *调用setParseBodyMethods将getParseBodyMethods()获取的parseBodyMethods的值赋值给 3 * parseBodyMethods 4 * / 5 保護 ボイド initInternal()がスロー LifecycleExceptionを{ 6 7 // ... 8 9 // makeは確認parseBodyMethodsSetを有しますデフォルト 10 であれば(ヌル == parseBodyMethodsSet){ 11 setParseBodyMethods(getParseBodyMethods())。 12 } 13 14 // ... 15 } 16 17 / ** 18 取得parseBodyMethodsのa *値 19。 * / 20れる 保護された文字列parseBodyMethods = " POST "; 21は、 22である パブリック(文字列getParseBodyMethods){ 23れる 戻り 、この .parseBodyMethodsを; 24 } 25 26である ** / 27 コネクタと、コネクタを定義*ルール非会員解決要求POST要求を許可する、デフォルトではなく、ルールに導入された 28 parseBodyMethodSetは、それがデフォルト値の使用* 29 *値は方法parseBodyMethodsに割り当てられている 30 methodSet値をparseBodyMethodsSetに割り当てられている* 31である * / 32 公共 のボイドsetParseBodyMethods(文字列法){ 33 34 HashSetの<ストリング> methodSet = 新しい HashSetの<文字列>(); 35 36 であれば(ヌル =メソッド!){ 37 methodSet.addAll(は、Arrays.asList(methods.split( " \\はS *、\\はS * ")))。 38 } 39 40 // ... 41 42 この .parseBodyMethodsの=法。 43 この .parseBodyMethodsSet = methodSet。 44 }
唯一の方法は、直接要求オブジェクトを介してのgetParameter()やSpring MVCパッケージPOJOオブジェクトが取得していないかどうか、そのため、分析パラメータを投稿するときにparseBodyMethodSetは、デフォルト、唯一の現在のリクエストを投稿し、分析の前にいくつかの手順を実行することで4、パラメータ値。
五、HttpPutFormContentFilterフィルタ原理
1 / * 2 リクエストオブジェクトを再パッケージ*パッケージデータ要求本体、 3 * / 。4 保護された ボイド doFilterInternal(最終 HttpServletRequestのリクエスト、HttpServletResponseの応答、れるFilterChainフィルターチェーン)がスロー ServletExceptionがは、IOException { 5 //置く要求、または時にパッチを要求する時であると 6 IF(( " PUT " .equals(request.getMethod())|| " PATCH " .equals(request.getMethod()))&& この .isFormContentType(リクエスト)){ 7 HttpInputMessage inputMessage = 新しい新しい ServletServerHttpRequest(要求){ 8 // HttpInputMessageにパッケージ、リクエストボディのデータストリームを取得 9。 公共のInputStream getBody()はスローにIOException { 10 リターン request.getInputStreamを(); 11 } 12れる }; 13である 14 HttpInputMessageを読み取るパッケージにパッケージの//最後のステップオブジェクトMultiValueMap 15 //このオブジェクトは、地図から継承 16 マップに要求をカプセル化//データボディ 17。 MultiValueMap <文字列、文字列> = formParametersはこの .formConverter.read((クラス)ヌル、inputMessage); 18れている 19。 // HttpPutFormContentRequestWrapperを使用Requestオブジェクト再パッケージ 20を = Warpper HttpServletRequestの新しい新 HttpPutFormContentFilter.HttpPutFormContentRequestWrapper(要求、formParameters); 21である FilterChain.doFilter(warpper、応答); 22である } 他 { 23は FilterChain.doFilter(リクエスト、レスポンス); 24 } 25 } 26は、 27 / ** 28 リクエストパッキング*オブジェクトの具体的な実現 29 *は、最初の親クラスを呼び出し、()メソッドのgetParameterの親クラスを書き換える 30 あなたが得ることができる場合*は親クラスに慣れることです。 31 *あなたが得ることができない場合は、取得した現在のクラスを使用することです。 32 * / 33は、 プライベート 静的 クラスHttpPutFormContentRequestWrapperは延び HttpServletRequestWrapperクラス{ 34 プライベート MultiValueMap <文字列、文字列> formParametersと、 35 36 公共の文字列のgetParameter(文字列名){ 37 列queryStringValue = スーパー .getParameter(名); 38 ストリングformValue =(文字列)この .formParameters.getFirst(名前); 39 リターン queryStringValue!= nullの?queryStringValue:formValue。 40 } 41 42 // ... 43 }