99.トラブルシューティング
概要
ここでは、「実践的な」ことをしようとしたとき起こるかもしれない事態のトラブルシュートを
記述してみます。
ご存じのことも多いかもしれませんが、何か参考になるとうれしいです。
主に、Spring MVC、Spring Security、Eclipse、単体テストなどのトラブルを扱います。
分類や順番は適当ですので、目次からうまく解決策を見つけてもらえればと思います。
Spring
Spring MVCで、リクエストパラメタがフォームPOJO(モデル)に設定されない
@InitBinderで、binderにsetAllowedFields などでパラメタを絞っていませんか?
その場合は、パラメタ名を追加しましょう。
もし、binderでプレフィックスを設定してる場合は、プレフィックスを除いたパラメタ名を指定します。
例: binder.setFieldDefaultPrefix("member."); とプレフィックスを指定している場合、
⇒binder.setAllowedFields("id"); "member.id"ではなく"id"だけを設定します。
@ModelAttributeメソッドが呼ばれない。
以下のような設定でステータス400などのエラーになるケース。
@ModelAttribute("form")
public Form newRequest(
@RequestParam(required=false, value="member.id") Integer memberId
) {
上記のように、数値型に対して、以下のような数字でない値を渡していませんか?
http://localhost:8080/spring_mvc_sample/input.html?member.id=5H
数値を渡すようにすると動作します。
これを型変換エラーにする方法を調べたのですが、見つかりませんでした。
海外のフォーラムでも話題に挙がっていましたが、そのフォーラムでは解決策はありませんでした。
@RequestMappingメソッドであれば、引数にBindingResultを追加すれば型変換エラーを補足できるのですが、@ModelAttributeメソッドではできないようです(2016年現在)。
SpringSecurityのJSPのタグで、SpringSecurityの式を使うとエラーが出る
There must be at least one in order to support expressions in JSP 'authorize' tags.
上記のようなエラーが出る場合、設定が不足しています。
以下のbeanをSpring設定ファイルに追記してください。
<!-- JSPタグでSpringSecurity式を使用したい場合に以下を定義する -->
<bean id="webexpressionHandler"
class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"/>
@ResponseBodyでStringを返した時に文字化けする
@ResponseBodyを使用しているということは、HttpMessageConverterが裏で動いていると思います。
結果、StringHttpMessageConverterが返却した文字を文字コード変換していると思いますので、
defaultCharsetプロパティを変更してあげれば解決するかと思います。
方法は以下を参照ください。
12-1.return値の変換方法(HttpMessageConverter)について
具体的な方法は以下の「Stringの内容をそのまま返す方法」などを参照ください。
12-2.return値の変換方法(HttpMessageConverter)の技術的Tips
リクエスト時にContent typeエラーが出る
以下のエラーが発生するケース。
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'xxxxxx' not supported
xxxxには例えば、「text/plain;charset=UTF-8」などが入ります。
このようなケースの場合、おそらく、@RequestBodyを引数にして、Jsonを受け付けているのではないでしょうか。
RequestMappingは成功していますが、
Jackson2のConverterが、Content-typeとして"application/json"しか許していないので、エラーになっているものと思います。
クライアントの送信Content-typeを"application/json"にするとうまく動くかと思います。
<リクエスト例(jqueryの場合)>
$.post({
"url": "http://localhost:8080/xxx/ttt.html",
"data" : JSON.stringify(params),
"contentType": "application/json; charset=utf-8",
"accept" : "application/json" ,
"method": "POST",
:
});
Could not find acceptable representationのようなエラーが出る
以下のエラーが発生するケース。
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
このようなケースの場合、おそらく@ResponseBodyを指定しているのではないでしょうか。
また、デバッガーなどで追うと、@RequestMappingメソッドは呼び出されているのではないでしょうか?
つまり、HttpMessageConverterを使用する処理を適用していて、コンバータが見つかっていないものと思われます。
いろいろな原因が考えられますが、よくあるのは以下かと思います。
・レスポンス処理のConverterの処理で、MediaTypeもしくはreturn型にマッチするConverterが見つからなかった。
まず、URLの拡張子が、html, xml, jsonになっていないかを確認。
⇒ContentNegotiationManagerFactoryBeanでSpringの設定を変更し、Converter決定条件に拡張子を含めないようにする。
【Spring設定ファイルの記述例】
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<!-- URLの拡張子でMediaTypeを決める機能をOffにする -->
<property name="favorPathExtension" value="false" />
</bean>
<!-- Make this available across all of Spring MVC -->
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
※原理を以下の参考リンクに書いていますので、応用が利くようにお読みいただければと思います。
上記で解決しない場合は、クライアントが送信するAcceptなどを確認ですが、以下の記事を読むと他の原因も見つかると思います。
参考:12-1.return値の変換方法(HttpMessageConverter)について
環境(およびSpring以外)
eclipseでデバッグ中に、ThreadPoolExecutor というエラーが発生し、デバッグを中断させられる
デバッグ中に何もしていないのに中断され、「ThreadPoolExecutor」というエラーが発生する場合があります。
この場合は、以下のようなことを試してみてください。
eclipseで、[ウィンドウ]-[設定] で設定プロパティを開き、以下のチェックを外します。
dbUnitのデータExcelを更新してデバッグを実行したが、DBの値が更新したとおりにならない。
eclipse上の対象のファイルのあるパスをリフレッシュ(F5)してください。
リフレッシュしないと実行のパスにコピーされないようです。
djUnit実行しようとすると、VerifyErrorが発生した。
これは、JDK6で導入されたclassファイルの検証方式変更(JSR-202)がJDK7からは有効となっており、
それでVerifyErrorが発生したようです。
実行時のVM引数に、「-noverify」を記述して実行してみてください。
参考: 05.設計7: 単体テスト
ClassNotFoundException: org.springframework.web.context.ContextLoaderListener が発生する
tomcatを起動したときに上記のエラーが出る場合は以下のことを試してみてください。
eclipseに何かゴミが残ってしまって、クリアできていないケースがあるようです。
eclipseの以下の場所を、右クリック ⇒ クリーン を選択してクリアしてみてください。
参考: 海外のフォーラム(ClassNotFound例外が発生する)
戻るボタン(もしくは javascript: history.back()) が効かない
history.back()で前の画面に戻りたい場合でも、戻れる画面と戻れない画面がある場合。
おそらく、戻れないのはフォーム送信しているPOSTをしている画面ではないでしょうか?
通常、GETの画面は戻れますが、POSTの画面は画面キャッシュが無効になって、history.back()などで戻れないと思います。
1つの解決策は、HTTPヘッダに Cache-Control:private を追加する方法です。
これが必ずしも正しい方法とは限らないので、各自、良い方法を調べてください。
一応、Spring MVCでCache-Control:privateを追加する例を示しておきます。
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="locale" />
<!-- HTTPヘッダにCache-Control:privateを追加。POSTでもブラウザにキャッシュされるようになる。 -->
<bean class="org.springframework.web.servlet.mvc.WebContentInterceptor">
<property name="CacheControl" value="#{T(org.springframework.http.CacheControl).empty().cachePrivate()}"/>
</bean>
</mvc:interceptors>
Spring MVCのinterceptorsに追加します。
CacheControlクラスは、HTTPのレスポンスヘッダの「Cache-Control」を生成するクラスです。
上記の場合はprivateを作成しています。
Cache-Controlのセキュリティ等の一般的知識は以下も参照のこと:
https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/405.html
Created Date: 2015/03/24