Spring MVCに基づくWebアプリケーション開発(3)-Resources

13656 ワード

前回はSpring MVCベースのWebプロジェクトにログを追加し、Spring MVCがリソースファイルをどのように処理するかを紹介しました.
本プロジェクトのwebに気づく.xml構成のDispatcherServiceletに対応するurl-patternは「/」であり、つまりすべてのURL要求がSpring MVCの処理を受ける.実際のWebプロジェクトにはjavascriptファイル、cssファイル、png、jpgなどの画像ファイル、さらにFlashなど、多くのリソースファイルがあります.これらの静的ファイルへのアクセスに対応するURLを設定する必要はありません.そうすると、多くの重複作業やメンテナンス上の複雑さをもたらします.Spring MVCは、locationディレクトリの下に対応する静的ファイルに対応するURLとlocationをマッピングできるメカニズムを提供します.次のように構成されています.
<resources mapping="/resources/**" location="/resources/" />

説明すると、
1.アクセスhttp://localhost:8080/resources/test.pngブラウザにwebapp/resources/testが表示されます.png
2.アクセスhttp://localhost:8080/resources/scripts/test.jsブラウザにwebapp/resources/scripts/testが表示されます.js
3.アクセスhttp://localhost:8080/resources/css/2012/test.css、ブラウザにwebapp/resources/css/2012/testが表示されます.css
mappingの値「/resources/**」には2つの*があることに注意してください.これは、resources/の下にあるすべてのURLをマッピングすることを意味します.サブパス(つまり、複数の/)が含まれています.上記の1、2、3のように、1つの*しかない場合は、1レベルのパスしかマッピングできません.つまり、1のみアクセスできます.2、3はエラーを報告します.
残念ながら、この行だけを追加すると、@Controllerクラスの@RequestMappingマッピングは有効になりません.私はstackoverflow上のこの投稿を検索してソリューションを連想したのですが、その後stackoverflowで別の投稿を検索すると、を使用する場合はを追加し、@Controller注釈クラスを持つ@RequestMappingマッピング情報を読み込まなければならないという、比較的詳細な説明がありました.
ここでservlet-context.xmlは次のとおりです.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
	<resources mapping="/resources/**" location="/resources/" />
	
	<!-- Imports user-defined @Controller beans that process client requests -->
	<beans:import resource="controllers.xml" />
	
	<!-- You have to add this because you had a <resources/> declare -->
	<mvc:annotation-driven/>
	
</beans:beans>

http://localhost:8080/web/resources/test.jsにアクセスすると、ブラウザに表示されるのはtestです.jsの内容.
 
次に、ハローワールドの記事に残された問題を解決します.その記事では、@RequestMappingには「/simple」が1つしかありませんが、ログから3つのURL「/simple」、「/simple.*」、「/simple/」マッピングがあることがわかります.
INFO : org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Mapped URL path [/simple] onto handler 'simpleController'
INFO : org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Mapped URL path [/simple.*] onto handler 'simpleController'
INFO : org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Mapped URL path [/simple/] onto handler 'simpleController'

DefaultAnnotationHandlerMappingを見てみましょう.このクラスにはuseDefaultSuffixPatternメンバー変数があります.デフォルトはtrueです.つまり、1つのURLをデフォルトで識別する3つのURL変種です.addUrlsForPathメソッドでif条件が成立すると(useDefaultSuffixPattern=true)、別の2つのマッピングが追加されます('/simple.*'、'/simple/').
したがって、http://localhost:8080/web/simple/2http://localhost:8080/web/simple.html、さらにはhttp://localhost:8080/web/simple.foo(捏造の接尾辞名)にアクセスする場合、実際にはhttp://localhost:8080/web/simpleというURLと等価である.
 
HelloWorldの残された問題を処理した後、を追加した後、起動ログにどのようにマッピングされているかを自然に見てみましょう.
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/simple],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String org.springframework.samples.mvc.simple.SimpleController.simple()

D e faultAnnotationHandlerMappingではなく、RequestMappingHandlerMappingに変更されました.
考えを変えて、SpringMVCが上記の3つのURLをどのように処理するかをリクエスト側から見てみましょう.
アクセスhttp://localhost:8080/web/simple
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /simple
TRACE: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Found 1 matching mapping(s) for [/simple] : [{[/simple],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}]

アクセスhttp://lcoalhost:8080/web/simple.html
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /simple.html
TRACE: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Found 1 matching mapping(s) for [/simple.html] : [{[/simple.*],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}]

アクセスhttp://lcoalhost:8080/web/simple.foo(フィクションの接尾辞名)
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /simple.foo
TRACE: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Found 1 matching mapping(s) for [/simple.foo] : [{[/simple.*],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}]

とても奇妙で、SpringMVCは自動的に3種類のURLを識別して、このすべてはどのようにしてしましたか?起動ログは1つのURLしかないのに.
それともRequestMappingHandlerMappingのソースコードを見てみましょう.2つの属性useSuffixPatternMatchとuseTrailingSlashMatchがあります.
useSuffixPatternMatch(接尾辞モードマッチングを使用)のデフォルトはtrueです.つまり、「/simple.*」を認識できます.
useTrailingSlashMatch(末尾斜線マッチング)のデフォルトはtrueであり、「/simple/」が認識されます.
最後に、2回の起動ログ印刷のクラスが異なることに気づきました.
前はD e f a u l t AnnotationHandlerMapping、後はRequestMappingHandlerMappingとなっていますが、これはなぜでしょうか.
なぜならが加わった後、Spring工場のBeanの選択型が変わり、
を追加する前にSpringMVCはデフォルトポリシーを使用していたのでD e f a u l t AnnotationHandlerMappingが使用され、
を追加すると、SpringMVCはデフォルトポリシーではなくRequestMappingHandlerMappingというクラスを使用します.これはソースコードに書かれているはずです.
 
====================================================================
 
〔補足説明、見なくてもいい、翻訳も下手〕Spring Reference Document(Spring公式マニュアル)の16.14.5 Configuraing Service of Resources節でResourcesについて紹介します.
 
この構成()は、ResourceHttpRequestHandlerにResourceロケーションを構成し、handlerが特殊なURLモードに対応する静的リソース要求を処理できるようにします.Webアプリケーションのrootパスとclasspath上のパスを含む物理パスから静的リソースに直接アクセスするのに便利な方法を提供します.Cache-periodプロパティは、将来使用される可能性のある実験的なheader(Page SpeedやYSlowのような最適化ツールの力の程度を見て1年後かもしれない)を設定するために使用することができ、クライアントにより効率的に使用することができます.このhandlerはLast-MOdifiedというヘッダも適切に評価しているので(あれば)、304ステータスコード(ブラウザで返される404エラー訳者をよく知っているようなHTTPステータスコード)は適切に返され、クライアントにキャッシュされたリソースがサービス側に再アクセスし、負荷をもたらすことを避ける.たとえば、/resources/**のようなURLモードを使用して、Webアプリケーションのroot内部public-resourcesディレクトリのサービス・エンド・リソースへのアクセスを要求するには、次のようにします.
@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
      
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
  }

}

XMLの同じ構成は次のとおりです.
<mvc:resources mapping="/resources/**" location="/public-resources/"/>

次に、処理リソースの構成は、先ほど述べた1年後の実験的特性を満たすことができ、ブラウザキャッシュの最大使用率を確保し、ブラウザからのHTTPリクエストを低減することができる.
@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
      
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926);
  }

}

同じくXMLでは、
<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>

mappingこのプロパティは、SimpleHandlerMappingで使用できるAntモード(Antモード翻訳者とは何かよく分からない)である必要があります.locationプロパティは、1つ以上の有効なリソースディレクトリの場所を指定する必要があります.複数のリソースの場所は、カンマ区切り文字のリスト値を使用して指定できます.指定された場所は、指定されたリクエストのリソースの表現に基づいて、特定の順序でチェックされます.たとえば、Webアプリケーションrootパスにアクセスしたり、classpathパスの下のjarパッケージの既知の/META-INF/public-web-resources/パスにアクセスしたりするために、次のように書きます.
@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
      
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**")
      .addResourceLocations("/", "classpath:/META-INF/public-web-resources/");
  }

}

XML:
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>

リソースが新しいバージョンのアプリケーションのパブリケーションによって変更される可能性がある場合は、バージョン文字列をリクエストリソースに挿入するときに使用するマッピングモードを推奨します.そのため、クライアントにアプリケーションリソースに導入された新しいバージョンを強制することができます.このようなバージョン文字列は、SpEL構成を使用するため、新しいバージョンを導入する際に、単一の場所で容易に管理できます.
例として、本番環境でパフォーマンス最適化されたカスタムDojo JavaScriptライブラリのコンポーネントを使用するアプリケーションを考えます.このコンポーネントは通常、Webアプリケーションの/public-resources/dojo/dojoです.jsパスの下に配置します.アプリケーションの新しいバージョンごとにDojoの異なる部分がカスタムコンポーネントに統合される可能性があるため、クライアントブラウザはカスタムコンポーネントdojoを強制的に再ダウンロードする必要がある.jsリソースは、新しいバージョンのアプリケーションが配備されている限りです.簡単な梱包方法は一つです.propertiesプロファイルでアプリケーションのバージョンを管理します.たとえば、次のようにします.
application.version=1.0.0

次に、1つのbeanでラベルを使用して、propertiesファイルの値をSpELでアクセスできるようにします.
<util:properties id="applicationProps" location="/WEB-INF/spring/application.properties"/>

現在、SpEL、アプリケーションを通じて.バージョンにアクセスできます.ラベルにマージできます.
<mvc:resources mapping="/resources-#{applicationProps['application.version']}/**" location="/public-resources/"/>

Javaクラスでは、@PropertiesSource注釈を使用してEnvironment抽象クラスを注入し、定義済みのすべての属性値にアクセスできます.
@EnableWebMvc
@Configuration
@PropertySource("/WEB-INF/spring/application.properties")
public class WebConfig extends WebMvcConfigurerAdapter {

  @Inject Environment env;

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources-" + env.getProperty("application.version") + "/**")
      .addResourceLocations("/public-resources/");
  }

}

最後に、適切なURLリクエストリソースを使用するために、Spring JSPラベル:(JSPページで使用されている翻訳者)を使用することができます.
<spring:eval expression="@applicationProps['application.version']" var="applicationVersion"/>

<spring:url value="/resources-{applicationVersion}" var="resourceUrl">
    <spring:param name="applicationVersion" value="${applicationVersion}"/>
</spring:url>

<script src="${resourceUrl}/dojo/dojo.js" type="text/javascript"> </script>