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

11680 ワード

前の記事では、Spring MVCが静的リソースファイルをどのように処理するかについて説明しました.Spring MVCを使用してファイルをアップロードする方法について説明します.Spring MVCのModelAndViewについて詳しく説明します.FileUploadControllerというコントローラを追加します.
package org.springframework.samples.mvc.fileupload;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/fileupload")
public class FileUploadController {

	@RequestMapping(method=RequestMethod.GET)
	public void fileUploadForm() {
	}

}

このクラスとHelloWorldのControllerクラスでは少し違いますが、まずクラス名に@RequestMapping注記を入れます.これにより、HandlerMappingを行うとSpringMVCはクラス名とメソッド名の@RequestMappingを接続しますが、この例のメソッド名には具体的なパスはありません(もちろん書くこともできますが)、最終的にマッピングされるURLは「/fileupload」です.もう1つはメソッドレベル@RequestMappingの注記にRequestMothodが追加されたことである.GETとは、GET方式で提出された「/fileupload」URLリクエストのみがfileUpload()メソッドに入ることを意味するが、HTTPプロトコルによると、HTTPは一連の提出方法(GET、POST、PUT、DELETE)をサポートし、同じURLでもこれらの提出方式を使用することができる.実際SpringMVCは同じURLの異なるコミット方法を異なる方法に対応させることでRESTfulに達する.
http://localhost:8080/web/fileuploadにアクセスし、バックグラウンドでエラーが発生しました.
2012-03-20 19:12:44.557:WARN::/web/fileupload
javax.servlet.ServletException: Circular view path [fileupload]: would dispatch back to the current handler URL [/web/fileupload] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
	at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:292)
...

Hintで指摘されているように、Viewが指定されていないので、HelloWorldで結果をブラウザに戻すことができるのではないかと疑問に思うかもしれません.注意HelloWorldの@ResponseBodyはViewとは何の関係もありません.HelloWorldでもModelAndViewが返されていますが、このViewはnullで、戻る前に結果はHttpService Responseでブラウザに送信されています.では、どうやってViewを指定しますか?通常、特別なViewが書かれていない場合、すべての結果がこのデフォルトのViewに転送され、最後にブラウザに表示されます.servlet-context.xmlに構成を追加します.
	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>

Beanが構成されており、対応するクラスはInternalResourceView Resolverであり、prefixプロパティが「/WEB-INF/views」、suffixプロパティが「.jsp」と設定されている.このクラスはビュー解析器(view resolver)であり、InternalResourceView(例えばサーブレットやJSP)およびそのサブクラス、例えばJstlViewをサポートし、デフォルトはInternalResourceViewであり、JSTlViewが存在する場合、JSTlViewである.
デフォルトのViewがあり、このViewはview名を/WEB-INF/view/ディレクトリの下に対応するjspファイルに解析します.どこにviewの名前がありますか?@RequestMappingメソッドがvoidを返すと、@RequestMappingマッピングのURLパスであるview名が返されます.
したがって、GET方式でhttp://localhost:8080/web/fileuploadにアクセスすると、最終的にWEB-INF/views/ディレクトリの下にfileuploadがあるかどうかを探す.jspファイル、ある場合はこのjspファイルをブラウザに表示し、ない場合は次のエラーを報告します.
ERROR: PWC6117: File &quot;/Users/stephansun/Documents/workspace/samples/samples-web/src/main/webapp/WEB-INF/views/fileupload.jsp&quot; not found

fileUploadForm.jspファイルは次のとおりです.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
	<title>fileupload | mvc-showcase</title>
	<link href="<c:url value="/resources/form.css" />" rel="stylesheet"  type="text/css" />		
	<script type="text/javascript" src="<c:url value="/resources/jquery/1.6/jquery.js" />"></script>
	<script type="text/javascript" src="<c:url value="/resources/jqueryform/2.8/jquery.form.js" />"></script>	
</head>
<body>
	<div id="fileuploadContent">
		<h2>File Upload</h2>
		<p>
			See the <code>org.springframework.samples.mvc.fileupload</code> package for the @Controller code	
		</p>
		<form id="fileuploadForm" action="fileupload" method="POST" enctype="multipart/form-data" class="cleanform">
			<div class="header">
		  		<h2>Form</h2>
		  		<c:if test="${not empty message}">
					<div id="message" class="success">${message}</div>	  		
		  		</c:if>
			</div>
			<label for="file">File</label>
			<input id="file" type="file" name="file" />
			<p><button type="submit">Upload</button></p>		
		</form>	
	</div>
</body>
</html>

アップロードページが正しく表示されたら、アップロード要求を処理する方法が必要です.processUpload、FileUploadControllerは次のように見えます.
package org.springframework.samples.mvc.fileupload;

import java.io.IOException;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/fileupload")
public class FileUploadController {

	@RequestMapping(method=RequestMethod.GET)
	public void fileUploadForm() {
	}

	@RequestMapping(method=RequestMethod.POST)
	public void processUpload(@RequestParam MultipartFile file, Model model) throws IOException {
		model.addAttribute("message", "File '" + file.getOriginalFilename() + "' uploaded successfully");
	}
	
}

ここに新しい注記@RequestParamが表示されます.まずJSPページのコードクリップを見てみましょう.
<input id="file" type="file" name="file" />

Inputボックスでコミットされたパラメータ名はfile,@RequestParam注記POSTでコミットされたパラメータのうちfileという名前のものを1つのMultipartFileクラスに自動的にカプセル化し,すべて開発者の目の下で作成し,開発者のコード量を大幅に削減した.アップロードページでファイルのアップロードを選択し、バックグラウンドでエラーを報告し、エラーログを見ます.
java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
	at org.springframework.util.Assert.notNull(Assert.java:112)

「MultipartResolverが配置されていないのではないでしょうか?」と、はい、まだ配合されていません.servlet-contextにあります.xmlには、次のような構成が追加されています.
<!-- Only needed because we require fileupload in the org.springframework.samples.mvc.fileupload package -->
	<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

このBeanもビュー解析器(view resolver)です.
完全な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/>
	
	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<!-- Only needed because we require fileupload in the org.springframework.samples.mvc.fileupload package -->
	<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
	
</beans:beans>

ファイルを再度アップロードすると、次のページが表示されます.
File 'a.js' uploaded successfully

アップロードに成功しました.最後に、FileUploadControllerのprocessUploadメソッドを分析します.
@RequestMapping(method=RequestMethod.POST)
	public void processUpload(@RequestParam MultipartFile file, Model model) throws IOException {
		model.addAttribute("message", "File '" + file.getOriginalFilename() + "' uploaded successfully");
	}

ModelはMVCモードのMであり、ModelレイヤはViewレイヤに渡す値をカプセル化している.
最後にpomを更新します.xmlファイル、2つの依存を追加します.
	
	<!-- File Upload -->
	<dependency>
		<groupId>commons-fileupload</groupId>
		<artifactId>commons-fileupload</artifactId>
		<version>1.2.2</version>
	</dependency>	
	<dependency>
		<groupId>commons-io</groupId>
		<artifactId>commons-io</artifactId>
		<version>2.0.1</version>
	</dependency>

前に書いたコードはこの2つのjarパッケージには触れていないようですが、なぜ導入したのですか?
前に書いた
@RequestParam注記POSTが提出したパラメータのfileという名前のファイルを自動的にMultipartFileクラスにカプセル化し、すべて開発者の目の下で完成し、開発者のコード量を大幅に削減しました.
底辺は本当に誰がやったのだろうか.クラスに対応するMultipartResolverというBeanを追加しました
org.springframework.web.multipart.commons.CommonsMultipartResolver,
このクラスのソースコードを見てみると、importには次のように書かれています.
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

そのためSpringMVCはcommons-fileuploadアップロードコンポーネントをパッケージしており、本当にアップロードの役割を果たしているのはcommons-fileupload-1.2.2である.jarというjarパッケージの中のクラス.