Maven(multiple modules)からSpring Boot で Thymeleaf の classpath:/templates/ へのマッピングが上手くいかない...

f:id:ts0818:20200527220943j:plain

タイム (thyme) はシソ科イブキジャコウソウ属 (Thymus) の植物の総称で、およそ350種を数える。芳香を持つ多年生植物で、丈が低く草本にみえるが、茎が木化する木本である。6月2日の誕生花。

タイム (植物) - Wikipedia

⇧ 6月か~、thymeleaf も6月になったら変わるんかな~、どうもボクです。

そういえば、

news.mynavi.jp

Windowsネイティブなパッケージ管理システムは開発者やアドバンスドユーザーが長らく望んできたもの。LinuxmacOSにはパッケージ管理システムが存在しており、アプリケーションやツールのインストール・アンインストール・アップデートなどを手軽に実施できる。一方、Windowsにはこうしたシステムが存在しておらず、似たような環境を整備するのに手間がかかっていた。

Windows 10に公式パッケージ管理システム「winget」登場 | マイナビニュース

⇧ ようやく、Windowsの希望の光となりますかね?

 

By the way。

Spring BootでThymeleafが上手くいかなくて無茶苦茶時間を無駄にしたんだが...

まぁ、結論から申し上げますと、

github.com

@alpha_pz さんより
https://twitter.com/alpha_pz/status/1217367568664522753

Pleiades All in one Eclipseに同梱されているThymeleafプラグインEclipseのランタイムがJava11なので動作しない(javax.activation-1.2.0を要求するが1.1しか入っていないので何も表示されない)

Thymeleaf プラグインの補完が効かない・動作しない · Issue #41 · cypher256/pleiades.io · GitHub

⇧ 以上。

Pleiades All in one EclipseJava 11 を利用する場合は、Thymeleafが上手く機能しない問題発覚。

残念過ぎるでしょ...

何か、でも、私の問題は、上記の現象とはまた別問題な気もするんだけど...

というわけで、ここから先はお時間のある方のみご照覧ください。

 

2020年6月13日(土):追記 ↓ ここから

そもそも、Thymeleafは、Springが推奨してるTemplateエンジンらしいんですが、

note.com

・ Angularは、HTMLとJavaScript(TypeScript)を分割してかきます。
・ Reactは、JavaScriptの中にHTMLを書きます。
・ Vueは、HTMLにJavaScriptを書きます。

202x年代のJS開発における複雑性との戦い|erukiti|note

⇧ いまのところ流行ってるJavaScriptフレームワークとかを組み合わせる場合は、いろいろ考慮しなけりゃならんということですかね。

www.thymeleaf.org

すぐに使える機能として、Thymeleafは6種類のテンプレート処理機能を備えています。これをテンプレートモードと呼びます:

Tutorial: Using Thymeleaf (ja)

⇧ いろいろ選べるらしい。

ちなみに、

www.webjars.org

⇧ 「WebJars」ってものを使うと、「JavaScript」や「CSS」のライブラリをJarファイル経由で利用できるらしい、つまり、「Maven」や「Gradle」といったようなビルドツールの依存関係に追加して利用することもできるらしい。

最新のライブラリが利用できるのかは分からんけど。

2020年6月13日(土):追記 ↑ ここまで 

 

2020年6月11日(木):追記 ↓ ここから

どうやら、@SpringBootApplication ってアノテーションのscanBasePackagesを明示的に指定すると、デフォルトのパッケージが読み込まれなくなるらしい、むっちゃハマった(涙)。

どういうことかと言うと、

f:id:ts0818:20200611201829p:plain

ってな感じで、

  • multiple-module-project
    • app
    • multiple-versions-db-1
    • multiple-versions-db-2

 という、multiple-modules なプロジェクト構成で、「app」プロジェクトの「/app/src/main/java/com/example/multiple_module/application/App.java」クラスがエントリーポイント(mainメソッドを持ってて、@SpringBootApplication ってアノテーションが設定されてる)になってるんだけど、「app」プロジェクトに作成してる「/app/src/main/java/com/example/multiple_module/application/controller/AppController.java」ってクラスは、通常だったら、デフォルトで(特に何もしなくても)、@ComponentScanの対象になるんだけど、@ComponentScanの対象を独自に広げた場合、デフォルトで読み込むはずの対象がリセットされてしまうってことみたい。

■読み込みが駄目な例

@SpringBootApplication(scanBasePackages = {"com.example.multiple_module.db_first",  "com.example.multiple_module.db_second"})

■読み込みがOKな例

@SpringBootApplication(scanBasePackages = {"com.example.multiple_module.application",  "com.example.multiple_module.db_first",  "com.example.multiple_module.db_second"})

⇧ ってな感じで、本来なら、何もしなくても読み込まれるはずの「com.example.multiple_module.application」パッケージも設定しないと読み込んでくれないという...

で、

spring.pleiades.io

⇧ 上記サイト様を良く見たら、

  • package com.example.multimodule
    • service
    • application

 ってな感じのmultiple-modules な構成で、

@SpringBootApplication(scanBasePackages = "com.example.multimodule")    

⇧ ってな感じで上位のパッケージを設定してたというね。

だから、

■読み込みがOKな例

@SpringBootApplication(scanBasePackages = {"com.example.multiple_module"})

⇧ みたいな設定にすれば良いってことですかね?

multiple-modules なプロジェクト構成の時に、scanBasePackages とかを明示的に設定すると、@ComponentScan のデフォルト の読み込みがリセットされちゃうらしいから、要注意ですかね。

2020年6月11日(木):追記 ↑ ここまで 

 

Thymeleafのtemplatesフォルダが認識されんけど... 

Spring Boot で Thymeleaf を利用するために、pom.xml に依存関係を追加して、Eclipseの「パッケージ・エクスプローラー」に表示される プロジェクト内でMavenの依存関係にも、Thymeleaf 系のライブラリが読み込まれてるのが確認できて、プロジェクトをSpring Boot として起動もされて、Spring Boot でデフォルトで表示されるindex.html が表示されるけど、「src/main/resources/template/」に配置した○○.html が認識されない、何でや!

ってことの原因が分からずに悩まされてたんだけど、何かLogbackってライブラリのDEBUGモードでSpring Bootの起動をしてみたんだけど、差異があんまりないんよね...

 

コンソールの出力の比較

■multiple moduleなプロジェクト

f:id:ts0818:20200516201638p:plain

============================
CONDITIONS EVALUATION REPORT
============================


Positive matches:
-----------------

   AopAutoConfiguration matched:
      - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)

   AopAutoConfiguration.ClassProxyingConfiguration matched:
      - @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition)
      - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)

   AuditEventsEndpointAutoConfiguration matched:
      - @ConditionalOnAvailableEndpoint no property management.endpoint.auditevents.enabled found so using endpoint default; @ConditionalOnAvailableEndpoint marked as exposed by a 'management.endpoints.jmx.exposure' property (OnAvailableEndpointCondition)

   BeansEndpointAutoConfiguration matched:
      - @ConditionalOnAvailableEndpoint no property management.endpoint.beans.enabled found so using endpoint default; @ConditionalOnAvailableEndpoint marked as exposed by a 'management.endpoints.jmx.exposure' property (OnAvailableEndpointCondition)

   BeansEndpointAutoConfiguration#beansEndpoint matched:
      - @ConditionalOnMissingBean (types: org.springframework.boot.actuate.beans.BeansEndpoint; SearchStrategy: all) did not find any beans (OnBeanCondition)

----省略----

   DispatcherServletAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet' (OnClassCondition)
      - found 'session' scope (OnWebApplicationCondition)

----省略----

   ThymeleafAutoConfiguration matched:
      - @ConditionalOnClass found required classes 'org.thymeleaf.templatemode.TemplateMode', 'org.thymeleaf.spring5.SpringTemplateEngine' (OnClassCondition)
      
   ThymeleafAutoConfiguration.DefaultTemplateResolverConfiguration matched:
      - @ConditionalOnMissingBean (names: defaultTemplateResolver; SearchStrategy: all) did not find any beans (OnBeanCondition)
      
   ThymeleafAutoConfiguration.ThymeleafDefaultConfiguration#templateEngine matched:
      - @ConditionalOnMissingBean (types: org.thymeleaf.spring5.ISpringTemplateEngine; SearchStrategy: all) did not find any beans (OnBeanCondition)
      
   ThymeleafAutoConfiguration.ThymeleafJava8TimeDialect matched:
      - @ConditionalOnClass found required class 'org.thymeleaf.extras.java8time.dialect.Java8TimeDialect' (OnClassCondition)
      
   ThymeleafAutoConfiguration.ThymeleafJava8TimeDialect#java8TimeDialect matched:
      - @ConditionalOnMissingBean (types: org.thymeleaf.extras.java8time.dialect.Java8TimeDialect; SearchStrategy: all) did not find any beans (OnBeanCondition)
      
   ThymeleafAutoConfiguration.ThymeleafWebMvcConfiguration matched:
      - found 'session' scope (OnWebApplicationCondition)
      - @ConditionalOnProperty (spring.thymeleaf.enabled) matched (OnPropertyCondition)
      
   ThymeleafAutoConfiguration.ThymeleafWebMvcConfiguration.ThymeleafViewResolverConfiguration#thymeleafViewResolver matched:
      - @ConditionalOnMissingBean (names: thymeleafViewResolver; SearchStrategy: all) did not find any beans (OnBeanCondition)    

----省略----

Negative matches:
-----------------

----省略----

   ThymeleafAutoConfiguration.DataAttributeDialectConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'com.github.mxab.thymeleaf.extras.dataattribute.dialect.DataAttributeDialect' (OnClassCondition)

   ThymeleafAutoConfiguration.ThymeleafReactiveConfiguration:
      Did not match:
         - did not find reactive web application classes (OnWebApplicationCondition)

   ThymeleafAutoConfiguration.ThymeleafSecurityDialectConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'org.thymeleaf.extras.springsecurity5.dialect.SpringSecurityDialect' (OnClassCondition)

   ThymeleafAutoConfiguration.ThymeleafWebFluxConfiguration:
      Did not match:
         - did not find reactive web application classes (OnWebApplicationCondition)

   ThymeleafAutoConfiguration.ThymeleafWebLayoutConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'nz.net.ultraq.thymeleaf.LayoutDialect' (OnClassCondition)

   ThymeleafAutoConfiguration.ThymeleafWebMvcConfiguration#resourceUrlEncodingFilter:
      Did not match:
         - @ConditionalOnEnabledResourceChain did not find class org.webjars.WebJarAssetLocator (OnEnabledResourceChainCondition)

----省略----

Exclusions:
-----------

    None


Unconditional classes:
----------------------

    org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration

    org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration

    org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration

    org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration

    org.springframework.boot.actuate.autoconfigure.web.mappings.MappingsEndpointAutoConfiguration

    org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration

    org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration

    org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration


2020-05-16 19:53:24.111  INFO 20112 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-17 09:32:40.296  INFO 3032 --- [main] c.e.multiple_module.application.App      : Started App in 3.984 seconds (JVM running for 5.652)

----省略----

■通常なプロジェクト

f:id:ts0818:20200516201447p:plain

============================
CONDITIONS EVALUATION REPORT
============================


Positive matches:
-----------------

   AopAutoConfiguration matched:
      - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)

   AopAutoConfiguration.ClassProxyingConfiguration matched:
      - @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition)
      - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)

   DispatcherServletAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet' (OnClassCondition)
      - found 'session' scope (OnWebApplicationCondition)    
    
----省略----

   ThymeleafAutoConfiguration matched:
      - @ConditionalOnClass found required classes 'org.thymeleaf.templatemode.TemplateMode', 'org.thymeleaf.spring5.SpringTemplateEngine' (OnClassCondition)

   ThymeleafAutoConfiguration.DefaultTemplateResolverConfiguration matched:
      - @ConditionalOnMissingBean (names: defaultTemplateResolver; SearchStrategy: all) did not find any beans (OnBeanCondition)

   ThymeleafAutoConfiguration.ThymeleafDefaultConfiguration#templateEngine matched:
      - @ConditionalOnMissingBean (types: org.thymeleaf.spring5.ISpringTemplateEngine; SearchStrategy: all) did not find any beans (OnBeanCondition)

   ThymeleafAutoConfiguration.ThymeleafJava8TimeDialect matched:
      - @ConditionalOnClass found required class 'org.thymeleaf.extras.java8time.dialect.Java8TimeDialect' (OnClassCondition)

   ThymeleafAutoConfiguration.ThymeleafJava8TimeDialect#java8TimeDialect matched:
      - @ConditionalOnMissingBean (types: org.thymeleaf.extras.java8time.dialect.Java8TimeDialect; SearchStrategy: all) did not find any beans (OnBeanCondition)

   ThymeleafAutoConfiguration.ThymeleafWebMvcConfiguration matched:
      - found 'session' scope (OnWebApplicationCondition)
      - @ConditionalOnProperty (spring.thymeleaf.enabled) matched (OnPropertyCondition)

   ThymeleafAutoConfiguration.ThymeleafWebMvcConfiguration.ThymeleafViewResolverConfiguration#thymeleafViewResolver matched:
      - @ConditionalOnMissingBean (names: thymeleafViewResolver; SearchStrategy: all) did not find any beans (OnBeanCondition)

----省略----

Negative matches:
-----------------
    
   ThymeleafAutoConfiguration.DataAttributeDialectConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'com.github.mxab.thymeleaf.extras.dataattribute.dialect.DataAttributeDialect' (OnClassCondition)
   ThymeleafAutoConfiguration.ThymeleafReactiveConfiguration:
      Did not match:
         - did not find reactive web application classes (OnWebApplicationCondition)
   ThymeleafAutoConfiguration.ThymeleafSecurityDialectConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'org.thymeleaf.extras.springsecurity5.dialect.SpringSecurityDialect' (OnClassCondition)
   ThymeleafAutoConfiguration.ThymeleafWebFluxConfiguration:
      Did not match:
         - did not find reactive web application classes (OnWebApplicationCondition)
   ThymeleafAutoConfiguration.ThymeleafWebLayoutConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'nz.net.ultraq.thymeleaf.LayoutDialect' (OnClassCondition)
   ThymeleafAutoConfiguration.ThymeleafWebMvcConfiguration#resourceUrlEncodingFilter:
      Did not match:
         - @ConditionalOnEnabledResourceChain did not find class org.webjars.WebJarAssetLocator (OnEnabledResourceChainCondition)
         
----省略----

Exclusions:
-----------

    None


Unconditional classes:
----------------------

    org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration

    org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration

    org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration



2020-05-16 20:40:24.851  INFO 21544 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-17 08:46:58.634  INFO 12464 --- [           main] com.example.demo.HelloDoma1Application   : Started HelloDoma1Application in 1.717 seconds (JVM running for 3.232)

----省略----

お分かりいただけただろうか?

Thymeleaf 系のライブラリに関しては「multiple modulesなプロジェクト」「通常なプロジェクト」の両者に差異は無いのである...

ますます分からんやんけ...

しかも、質の悪いことに、両者とも普通に「Tomcat」「JVM」が起動してるんですな。

 

qiita.com

⇧ 上記サイト様を参考に、Errorページをカスタマイズしてみました。

■デフォルトのエラーページ

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sun May 17 13:04:38 JST 2020
There was an unexpected error (type=Not Found, status=404).
No message available    

■カスタマイズしたエラーページ

timestamp: Sun May 17 13:06:52 JST 2020
status: 404
error: Not Found
exception: null
message: No message available
errors: null
trace: null
path: /users    

お分かりいただけただろうか?

エラーの情報が全く変わらないのである!

強いて言えば、path が追加されたぐらいでしょうか?

どうも、templatesフォルダへ配置した「index.html」「error.html」以外のHTMLファイルへのマッピングが認識されないのである。

 

■/app/src/main/resources/templates/index.html にアクセスを想定

2020-05-17 14:21:58.923  INFO 140 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-17 14:21:58.925  INFO 140 --- [           main] c.e.multiple_module.application.App      : Started App in 3.581 seconds (JVM running for 5.249)
2020-05-17 14:22:03.472  INFO 140 --- [on(1)-127.0.0.1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-05-17 14:22:03.472  INFO 140 --- [on(1)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2020-05-17 14:22:03.472 DEBUG 140 --- [on(1)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Detected StandardServletMultipartResolver
2020-05-17 14:22:03.479 DEBUG 140 --- [on(1)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
2020-05-17 14:22:03.479  INFO 140 --- [on(1)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 7 ms
2020-05-17 14:22:07.787 DEBUG 140 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/", parameters={}
2020-05-17 14:22:07.795 DEBUG 140 --- [nio-8080-exec-1] o.s.b.a.w.s.WelcomePageHandlerMapping    : Mapped to ParameterizableViewController [view="index"]
2020-05-17 14:22:07.802 DEBUG 140 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8]
2020-05-17 14:22:07.806 DEBUG 140 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine             : [THYMELEAF] INITIALIZING TEMPLATE ENGINE
2020-05-17 14:22:07.959 DEBUG 140 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine.CONFIG      : Initializing Thymeleaf Template engine configuration...
[THYMELEAF] TEMPLATE ENGINE CONFIGURATION:
[THYMELEAF] * Thymeleaf version: 3.0.11.RELEASE (built 2018-10-28T22:35:28+0000)

----省略----

[THYMELEAF] TEMPLATE ENGINE CONFIGURED OK
2020-05-17 14:22:07.960 DEBUG 140 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine             : [THYMELEAF] TEMPLATE ENGINE INITIALIZED
2020-05-17 14:22:08.032 DEBUG 140 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 200 OK

■/app/src/main/resources/templates/users.html にアクセスを想定

2020-05-17 14:18:04.864  INFO 13076 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-17 14:18:04.866  INFO 13076 --- [           main] c.e.multiple_module.application.App      : Started App in 3.535 seconds (JVM running for 5.209)
2020-05-17 14:18:07.661  INFO 13076 --- [on(1)-127.0.0.1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-05-17 14:18:07.661  INFO 13076 --- [on(1)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2020-05-17 14:18:07.661 DEBUG 13076 --- [on(1)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Detected StandardServletMultipartResolver
2020-05-17 14:18:07.667 DEBUG 13076 --- [on(1)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
2020-05-17 14:18:07.667  INFO 13076 --- [on(1)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 6 ms
2020-05-17 14:18:18.664 DEBUG 13076 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/users", parameters={}
2020-05-17 14:18:18.672 DEBUG 13076 --- [nio-8080-exec-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2020-05-17 14:18:18.676 DEBUG 13076 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler     : Resource not found
2020-05-17 14:18:18.676 DEBUG 13076 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 404 NOT_FOUND
2020-05-17 14:18:18.684 DEBUG 13076 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for GET "/error", parameters={}
2020-05-17 14:18:18.686 DEBUG 13076 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
2020-05-17 14:18:18.710 DEBUG 13076 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, text/html;q=0.8]
2020-05-17 14:18:18.713 DEBUG 13076 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine             : [THYMELEAF] INITIALIZING TEMPLATE ENGINE
2020-05-17 14:18:18.840 DEBUG 13076 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine.CONFIG      : Initializing Thymeleaf Template engine configuration...
[THYMELEAF] TEMPLATE ENGINE CONFIGURATION:
[THYMELEAF] * Thymeleaf version: 3.0.11.RELEASE (built 2018-10-28T22:35:28+0000)

----省略----

[THYMELEAF] TEMPLATE ENGINE CONFIGURED OK
2020-05-17 14:18:18.841 DEBUG 13076 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine             : [THYMELEAF] TEMPLATE ENGINE INITIALIZED
2020-05-17 14:18:19.056 DEBUG 13076 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Exiting from "ERROR" dispatch, status 404

⇧ ってな感じで、

「/app/src/main/resources/templates/index.html」「/app/src/main/resources/templates/error.html」

の2ファイルは処理されてるようなんだけど、 

spring.pleiades.io

Spring Boot は、静的なウェルカムページとテンプレート化されたウェルカムページの両方をサポートしています。最初に、構成された静的コンテンツの場所で index.html ファイルを探します。見つからない場合は、index テンプレートを探します。どちらかが見つかった場合、アプリケーションのウェルカムページとして自動的に使用されます。

Spring Boot の機能 - 公式ドキュメントの日本語訳

⇧ 「/app/src/main/resources/templates/index.html」 については、Thymeleafのテンプレートとして機能してるのかが分からんと言うね、ややこしいな...

なんか、

デフォルトでは、Spring Boot は、すべてのエラーを適切な方法で処理する /error マッピングを提供し、サーブレットコンテナーに「グローバル」エラーページとして登録されます。マシンクライアントの場合、エラー、HTTP ステータス、および例外メッセージの詳細を含む JSON レスポンスを生成します。ブラウザクライアントには、同じデータを HTML 形式でレンダリングする「ホワイトラベル」エラービューがあります(カスタマイズするには、error に解決される View を追加します)。デフォルトの動作を完全に置き換えるには、ErrorController を実装してそのタイプの Bean 定義を登録するか、タイプ ErrorAttributes の Bean を追加して既存のメカニズムを使用し、内容を置き換えます。

Spring Boot の機能 - 公式ドキュメントの日本語訳

⇧ 「/app/src/main/resources/templates/error.html」についても、Thymeleafのテンプレートとして機能してるのかが分からんね...

 

Spring Boot には、次のテンプレートエンジンの自動構成サポートが含まれています。

Spring Boot の機能 - 公式ドキュメントの日本語訳

⇧ ってあって、

これらのテンプレートエンジンのいずれかを既定の構成で使用すると、src/main/resources/templates からテンプレートが自動的に選択されます。

Spring Boot の機能 - 公式ドキュメントの日本語訳

⇧ とあるんだけど、解決され取らんよね?

アプリケーションの実行メソッドに応じて、IntelliJ IDEA はクラスパスの順序を変えます。IDE でメインメソッドからアプリケーションを実行すると、Maven または Gradle を使用して、またはパッケージ化された jar からアプリケーションを実行する場合とは順序が異なります。これにより、Spring Boot がクラスパスでテンプレートを見つけられない場合があります。この問題がある場合は、IDE でクラスパスを並べ替えて、モジュールのクラスとリソースを最初に配置できます。または、次のように、クラスパス上のすべての templates ディレクトリを検索するようにテンプレートプレフィックスを設定できます: classpath*:/templates/

Spring Boot の機能 - 公式ドキュメントの日本語訳

⇧ 出た出た、IDEの特有の問題あるかもってさ...

こういう情報をみんなブログとかで紹介しないのは何なのかね?確かにEclipseについては特に触れてなさそうに見えるけどさ。

まぁ、設定してみたけどエラーは変わらずなんですけどね...

いや~、もう謎過ぎるんですけど...

 

って多大な時間を浪費して辿り着いた真実...

そう、冒頭での結論にあった衝撃。

github.com

@alpha_pz さんより
https://twitter.com/alpha_pz/status/1217367568664522753

Pleiades All in one Eclipseに同梱されているThymeleafプラグインEclipseのランタイムがJava11なので動作しない(javax.activation-1.2.0を要求するが1.1しか入っていないので何も表示されない)

Thymeleaf プラグインの補完が効かない・動作しない · Issue #41 · cypher256/pleiades.io · GitHub

⇧ 絶句なんですけど...

Thymeleafプラグインが改修されていた場合はそれを導入

Java 11 に対応した Thymeleaf プラグイン 3.0.0 ブランチのリリースが先になりそうなので、
私のほうで、Thymeleaf プラグインJava 11 対応に改修し、
Eclipse All in One 2019-12.20200205 をリリースします。
Thymeleaf プラグイン 3.0.0 が正式リリースされたら、それを使用する予定です。

Thymeleaf プラグインの補完が効かない・動作しない · Issue #41 · cypher256/pleiades.io · GitHub

⇧ Oh, my gosh...

え~っと、上記のissueがオープンになったままですが、Eclipse All in Oneの変更履歴を見てみますか。

http://download.pleiades.io/download/pleiades/build/stable/changes.html

 

2020.05.03

・[IDEA][github#58] 2020.1 vmoptions 位置変更に関する Mac JetBrains Toolbox 以外の Pleiades インストーラー対応

2020.04.27

・[IDEA][github#56] SSHトンネルを使用したデータベース接続がエラー 対応
・訳追加修正: IntelliJ

2020.04.20

・[IDEA][github#54] 2020.1 の vmoptions 位置変更に関する Pleiades インストーラー対応

2020.04.11

・[IDEA] 2020.1 対応。日本語になっていた部分が英語になってしまっていた部分を修正
・訳追加修正: IntelliJ

2020.04.10

・[IDEA] 2020.1 対応。起動後、すべてのビューが表示されない問題を修正
・[Eclipse] EGit 共有ダイアログ > 作成ボタン > ディレクトリ名の repository が翻訳される問題を修正
・訳追加修正: Eclipse / IntelliJ

2020.03.22

・Java 14 が「インストール済みの JRE」に追加できない不具合を修正
・訳追加修正: Eclipse, EGit, Mark Text Editor, Buildship, Textmate, STS, Scala / Rider, DataGrip

2020.02.13

・訳追加修正: Eclipse, EGit / IntelliJ

2020.01.29

・[IDEA][github#43]【不具合】DBのカラム名まで日本語化されてしまう
・訳追加修正: Eclipse, EGit / IntelliJ

2019.12.25

・訳追加修正: Eclipse, BuildShip, PDT, EGit / IntelliJ, Android Studio, PhpStorm, PyCharm, Rider

2019.11.29

・[IDEA][github#38] Android Studio 3.5.2でコード補完の際不必要なスペースが表示されている:不具合対応
・[IDEA] PyCharm で Shift + F1 でブラウザに日本語ドキュメントを開くように設定
・訳追加修正: Eclipse, BuildShip, PDT, EGit / IntelliJ, Android Studio, PhpStorm, PyCharm, Rider

2019.10.03

・[Eclipse] javaagent オプション no.clean.message 追加 (詳細:readme_pleiades.txt)
・訳追加修正: Eclipse, IntelliJ, Android Studio

2019.09.30

・[Eclipse] Eclipse 2019-09 対応

2019.09.29

・[Eclipse] Eclipse 2019-09、Java 13 対応
・訳追加修正: Eclipse, IntelliJ, Android Studio

2019.09.15

・[IDEA][github#32] 日本語化するとGitHubの連携が正常にできない
・訳追加修正: Eclipse, IntelliJ, Android Studio

2019.08.31

・[Eclipse][github#30] Command Line Interfaceが「できます」と翻訳されている
・訳追加修正: Eclipse, IntelliJ, Android Studio

2019.08.21

・[IDEA] Toolbox でインストールした Android Studio 3.5 の Pleiades インストーラー対応

2019.08.18

・[IDEA][github#19] 最新版でphpStormを日本語化後にgit操作をするとバージョン管理ウィンドウ内に"コンソール"タブが増殖
・訳追加修正: Eclipse, IntelliJ, Android Studio, TeamCity

2019.08.10

・訳追加修正: Android, AndroidStudio, AppCode, BashSupport, DataGrip, EclipseUML, Eclipse, Eclipse_Babel, Eclipse_CDT,
  Eclipse_Help, Eclipse_UpdateManager, Eclipse_m2e, Eclipse_mylyn_trans_newdic, Flutter, GeronimoEclipsePlugin,
  GlassfishTools, IDEA, IDEA_Inspections, IDEA_fix, IDEA_tips, IdeaVIM, Kotlin_Idea, MPS, PhpStorm, PyCharm, Rider,
  RubyMine, STS, TeamCity, YouTrack, org.eclipse-SDK_3.5-20091021, q4e, regex-IDEA

2019.06.30

・[Eclipse] 訳追加修正: Eclipse
・[IDEA] 訳追加修正: IntelliJ, Android Studio

2019.05.08

・[Eclipse] 訳追加修正: Eclipse, EGit
・[IDEA] 訳追加修正: IntelliJ, Android Studio

2019.05.07



すべての履歴は zip 内の readme/readme_pleiades_changes.txt 参照

そもそも、2020年2月5日の履歴が無いですね...

 

https://ja.osdn.net/projects/mergedoc/scm/svn/blobs/head/trunk/Pleiades/readme/readme_pleiades_changes.txt

⇧ 上記に全履歴が載ってるようです。

    2019.05.07
 
・デバッグ関連コード削除もれ削除
 
2019.05.04
 
・[Eclipse] 訳追加修正: Eclipse, Aptana, Scala, STS
・[IDEA] 訳追加修正: IntelliJ, PhpStorm, ReSharper, Rider, MPS, RubyMine, PyCharm, DataGrip, AppCode, CLion, GoLand,
 Android Studio, IDE Features Trainer, String Manipulation, Jasmine, Material UI Theme
・Android Studio で日本語ヘルプを開くように AOP 定義追加 (メニュー、設定左下アイコン、ビューで F1 など)
・[github#18] Delete Problemsが削除の問題と翻訳されている
 
2019.03.24
 
・[Eclipse] 訳追加修正: Eclipse, STS4, Eclipse Quicksearch
・[IDEA] 訳追加修正: IntelliJ, Clion, ReSharper
 
2019.02.24
 
・[Eclipse] 訳追加修正: Eclipse, STS
・[IDEA] 訳追加修正: IntelliJ, PhpStorm, PyCharm, CLion, WebStorm, RubyMine, GoLand, DataGrip, Rider, ReSharper,
 Android Studio, Key Promoter X, Grep Console, Tab Shifter, Rust
・[IDEA] PhpStorm 設定 > 言語フレームワーク > PHP > サーバー > パスマッピングツリーの要素が翻訳される問題を修正
・[IDEA] Android Studio の LogCat ビューで applicationIdSuffix が翻訳される問題を修正
 
2019.01.20
 
・[IDEA] クイック定義ポップアップのクラス名が翻訳されてしまう問題を修正
・[IDEA] 訳追加修正: IntelliJ, Scala, Android Studio
 
2019.01.18
 
・[Eclipse] 訳追加修正: Eclipse
・[IDEA] Java アプリ実行結果が「プロセスは終了コード $EXITCODE$ で完了しました」となる問題を修正
・[IDEA] 訳追加修正: IntelliJ
 
2019.01.07
 
・[Eclipse] 訳追加修正: Eclipse
・[IDEA] 構造ビューが開けない場合がある問題を修正
・[IDEA] 訳追加修正: IntelliJ, String Manipulation
 
2019.01.05
 
・[Eclipse] 訳追加修正: Eclipse
・[IDEA] 一部の設定が開けない問題を修正
・[IDEA] 訳追加修正: IntelliJ, CLion, RubyMine, PyCharm, WebStorm, Material UI Theme, Bash Support, String Manipulation,
 Rainbow Brackets
 
2018.12.24
 
・[Eclipse] Eclipse 2018-12 対応
・[Eclipse] ワークスペースの選択ダイアログの workspace ディレクトリリンクが訳される問題を修正
・[Eclipse] 訳追加修正: Eclipse, Buildship, CDT
・[IDEA] 訳追加修正: IntelliJ


...省略

 

⇧ 結局、それっぽいの見つから無い...

 

 

結論

2020年5月27日(水)現在、Pleades Eclipse All in OneでThymeleafを使用したい場合は、Java 8 でいくしかない(涙)。

世間は、Java 11の流れが主流になりつつあると思うのですが、哀しい気持ちでいっぱいですね...

というか、私が無駄にした時間を返して欲しい...

2020年5月27日(水)23:00 追記:↓ ここから

あれ?

でも、よく考えてみたら、multiple modules じゃないプロジェクトだと、普通にJava 11 を使ってても「src/main/resources/templates」に配置したhtmlがThymeleafで読み込まれてるんだよな~。

謎は深まるばかりですかな...

2020年5月27日(水)23:00 追記:↑ ここまで

 

2020年5月29日(金)追記:↓ ここから

ログを比べたところ、

2020-05-29 20:14:23.015 DEBUG 3628 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/users", parameters={}
2020-05-29 20:14:23.017 DEBUG 3628 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.demo.controller.HelloController#hello()
2020-05-29 20:11:57.258 DEBUG 21628 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/users", parameters={}
2020-05-29 20:11:57.264 DEBUG 21628 --- [nio-8080-exec-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]

⇧ 何か、そもそもマッピングに使われてるメソッドが違うんだが...

ちなみに、「o.s.w.s.handler.SimpleUrlHandlerMapping」は、「org.springframework.web.servlet.handler.SimpleUrlHandlerMapping」のことらしい...パッケージを微妙に省略する意味あるんかね?

「s.w.s.m.m.a.RequestMappingHandlerMapping」は、「org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping」のことらしい...

ガッデーム!

しかもパッケージの場所がクソ分かり辛い

Mavenの依存関係の中の、「spring-web-x.x.x.RELEASE.jar」じゃなくて、「spring-webmvc-x.x.x.RELEASE.jar」のほうにあるというね...

f:id:ts0818:20200530011237p:plain

同じ「spring-webmvc-x.x.x.RELEASE.jar」に「org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping」もおりますと。

f:id:ts0818:20200530011544p:plain

ちょっと、ソースを追えてないんだけど、何故か、

  • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
  • org.springframework.web.servlet.handler.SimpleUrlHandlerMapping

と呼ばれるクラスが変わってきてしまっていますと。

あと、「Maven 依存関係」>「C:/Users/Toshinobu/.m2/repository/org/springframework/spring-webmvc/5.2.6.RELEASE/spring-webmvc-5.2.6.RELEASE-sources.jar」>「org/springframework/web/servlet/DispatcherServlet.properties」のprofile の内容が気になるんよね...

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
	org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
	org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager    

⇧ ってあるんだけど、何か、「multiple modules」のほうは、このファイルが認識されてないんじゃないかなって気が、その心は?

「multiple modules」のほうは、上記のprofileに記載のある「org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping」が呼ばれていないので。

何で呼ばれてないのかは、「DispatcherServlet」から動きを追わないといかんのかね?いや~、地獄だな...

 

公式の説明を確認してみると、

spring.pleiades.io

DispatcherServlet は、リクエストを処理して適切なレスポンスをレンダリングするために特別な Bean に委譲します。「特別な Bean」とは、フレームワーク契約を実装する Spring 管理の Object インスタンスを意味します。通常、これらにはビルトイン契約が付属していますが、プロパティをカスタマイズし、拡張または置換できます。

次の表に、DispatcherServlet によって検出された特別な Bean を示します。

Spring Web MVC サーブレットスタック - ドキュメント

⇧ とあり、Beanタイプが「HandlerMapping」を確認してみると、

前処理および後処理用のインターセプターのリストとともにリクエストをハンドラーにマップします。マッピングはいくつかの条件に基づいており、その詳細は HandlerMapping の実装によって異なります。

Spring Web MVC サーブレットスタック - ドキュメント

⇧ とあり、

2 つの主要な HandlerMapping 実装は、RequestMappingHandlerMapping (@RequestMapping アノテーション付きメソッドをサポート)と SimpleUrlHandlerMapping (ハンドラーへの URI パスパターンの明示的な登録を維持)です。

Spring Web MVC サーブレットスタック - ドキュメント

⇧ とありますと。

どうも、「ハンドラー」ってのが何を指すのか明示的に示されてないんだけど、おそらく、@Controller が付いたクラスのことなんですかね?

qiita.com

⇧ 何か、それっぽい感じですかね。@RestController の場合は、「ハンドラー」ってことにはならんのかな?

そんな感じで、何か、@RequestMapping が認識されとらんっちゅうことなんですかね?

profile(application.ymlとか)を複数使ってるのがマズいのかな?

って言うか、

⇧ 毎回、「Dispatcher Servlet」に処理が戻るんね。

Spring を管理してるPivotal(今はVM社に合併)の本でも、

⇧ 肝心のところが分からない...

何だろうな~、シーケンス図とか載っけてくれたら処理の流れが見渡せるのにな~。

進展があったら追記して参ります。

2020年5月29日(金)追記:↑ ここまで

 

2020年5月31日(日)追記:↓ ここから

頑張ってソースコードデバッグしてみたところ、どうも、「spring-webmvc-x.x.x.RELEASE.jar」の中の、「org.springframework.web.servlet.DispatcherServlet.class」の中の「initStrategies」メソッドがあって、

	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

⇧ ってな感じで、様々な初期化が行われてるんだけど、その中の、

initHandlerMappings(context);    

⇧ って処理の中で、最終的に、

  • org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
  • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

のどちらを使うかが割り振られているっぽい。

ちなみに、中国の方がシーケンス図を描いてくださってました。

www.liangzl.com

⇧ 上記のシーケンス図で言うところの「initHandlerMappings()」って部分の中で、様々な処理が行われてますと。

で、最終的には、

	/**
	 * Process the actual dispatching to the handler.
	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
	 * to find the first that supports the handler class.
	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
	 * themselves to decide which methods are acceptable.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception in case of any kind of processing failure
	 */
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

⇧ の中の、

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

⇧ ってメソッドで最終的に決定されてたんだけど、このメソッドは「org.springframework.web.servlet.HandlerAdapter.class」っていうインターフェイスで定義されていて、

	/**
	 * Use the given handler to handle this request.
	 * The workflow that is required may vary widely.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler the handler to use. This object must have previously been passed
	 * to the {@code supports} method of this interface, which must have
	 * returned {@code true}.
	 * @throws Exception in case of errors
	 * @return a ModelAndView object with the name of the view and the required
	 * model data, or {@code null} if the request has been handled directly
	 */
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

⇧ ご覧のように、引数が、

  1. @param request current HTTP request
  2. @param response current HTTP response
  3. @param handler the handler to use. This object must have previously been passed

ってあるんだけど、「3. @param handler the handler to use. This object must have previously been passed」 で決まってそうな気がして、結局、

	/**
	 * Initialize the HandlerMappings used by this class.
	 * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
	 * we default to BeanNameUrlHandlerMapping.
	 */
	private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

⇧ の中の、

			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);

⇧ のメソッドで求められる値に左右されるんではないかと、つまるところ、「initHandlerMappings(ApplicationContext context)」メソッドの引数である「ApplicationContext」の値が何かしら影響してるんだとは思うんだけど、どこをどう直していいのか見えてこんよね...。

private void initHandlerMappings(ApplicationContext context)

いや~、Spring もうちょいログか、ドキュメントを何とかして欲しいな~。

qiita.com

docs.spring.io

⇧ 上記サイト様を参考に、「spring-boot-starter-actuator」 ってライブラリを使ってみたところ、やはり、「multiple-modules」のプロジェクトのほうで、「@RequestMapping」が認識されとらんかった。

「@RequestMapping("/users")」をどちらのプロジェクトにも設定してます。

 

それぞれ、Spring Bootで起動した後に、

http://localhost:8080/actuator/mappings

⇧ 上記のURLにアクセス。

表示されルテキストを、

www.diffchecker.com

⇧ 上記のサイトで、差分を比較してます。

■「multiple-modules」じゃないプロジェクト

f:id:ts0818:20200531230908p:plain

■「multiple-modules」なプロジェクト

f:id:ts0818:20200531231015p:plain

「@RequestMapping」が認識されとらんのは分かったけど、対処法が分からず...

引き続き調査ですかね...

Spring は、と言うか、フレームワークってエラーになった時の対処法が追いにくいんですよね...

やっぱり、ドキュメントを充実させて欲しいかな...

2020年5月31日(日)追記:↑ ここまで