ファイルのダウンロードをしてみた。
XMLファイルとかの場合単にコントローラーに
@Autowired
ResourceLoader resourceLoader;
@RequestMapping(value = "/file_download", produces = MediaType.APPLICATION_XML_VALUE)
public Resource xmlfile() {
Resource resource = resourceLoader.getResource("classpath:sample.xml");
try{
return new FileSystemResource(resource.getFile().toString());
} catch (FileNotFoundException e) {
e.getStackTrace();
}
}
とかって書くと行けちゃったりしますが、これだとブラウザに表示されて終わりなので、
やっぱりダウンロードフォルダに欲しいよね。
って事でやり方をメモ
やることの構成
1.ファイルを読み込む
2.バイト形式に変換
3.OutputStreamに書き込む
こんな感じで3つの処理を行います。
最後に適当なビュー(nullでもいいのよ)を返してあげるとダウンロード機能の完成です。
1.ファイルを読み込む
まずはファイルをセットしましょう。
src/main/resourcesにファイルをセットします。
今回はこんなsample.xmlをセット
ファイルを読み込むコントローラーの部分を作ります。
@RestController
public class XMLController {
@Autowired
ResourceLoader resourceLoader;
@RequestMapping(value="/personize", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public String personize(HttpServletResponse response) {
Resource resource = resourceLoader.getResource("classpath:sample.xml");
}
}
ファイルの読み込みはこれだけでOKです。ResourceLoaderはコンテキスト生成時に自動でDIコンテナに登録される(っぽい)のでxmlファイルに記述する必要すらありません。ありがたく@Autowiredしましょう。
2.バイト形式に変換
処理を分けましょう。
新しいプライベートメソッドを作ります。
/**
* InputStream から バイト文字列に変換
* @param filepath
* @return
*/
private byte[] StreamToByte(Resource resource) {
int nRead;
InputStream is = null;
byte[] fileContent = new byte[16384];
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
//ファイルをバイト形式に変換
try {
is = new FileInputStream(resource.getFile().toString());
while ((nRead = is.read(fileContent, 0, fileContent.length)) != -1) {
buffer.write(fileContent, 0, nRead);
}
buffer.flush();
return buffer.toByteArray();
} catch (FileNotFoundException e) {
e.getStackTrace();
} catch (IOException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
return null;
}
Springとしてやっていることは15行目のresource.getFile().toString()の部分だけです。
これはgetFile()メソッドで、src/main/resource下にあるファイルをFile形式で取得できます。それをtoString()して絶対アドレスに変換するという肯定ですね。
まぁ、せっかくなのでJavaコードの解説も
while ((nRead = is.read(fileContent, 0, fileContent.length)) != -1) {
buffer.write(fileContent, 0, nRead);
}
buffer.flush();
ここがBufferdOutputStreamに書き込んでいるメインの部分です。バッファにデータを貯めてフラッシュで実行してます。
Cっぽいですけど、もう定型文ですね。
後はtry~catchでエクセプションを取得しています。
3.OutputStreamに書き込む
responseのアウトプットストリームに書き込みます
まずはどんな種類のファイルか、ヘッダーをセットしましょう。
@RequestMapping(value="/personize", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public String personize(HttpServletResponse response) {
Resource resource = resourceLoader.getResource("classpath:sample.xml");
byte[] fileContent = null;
fileContent = StreamToByte(resource);
// //ファイル書き込み
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + "sample.xml");
response.setContentLength(fileContent.length);
}
setContentTypeではバイナリファイルという型を指定してます。response.setHeaderでファイルネームを指定していますが、これが実際にダウンロードされるファイルの名前になります。response.setContentLengthはファイルの大きさですね。
それではOutputStreamに作成してたバイナリを書き込みましょう
これも別メソッドに書きます。
/**
* ダウンロードファイル書き込み
* @param response
* @param fileContent
*/
public void OutputSreamWrite(HttpServletResponse response, byte[] fileContent) {
OutputStream os = null;
try {
os = response.getOutputStream();
os.write(fileContent);
os.flush();
} catch (IOException e) {
e.getStackTrace();
}
}
特に難しい所はないでしょう。os.writeで書き込み、os.flushでストリームを実行です。
このメソッドをコントローラーに組み込みます。
@RequestMapping(value="/personize", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public String personize(HttpServletResponse response) {
Resource resource = resourceLoader.getResource("classpath:sample.xml");
byte[] fileContent = null;
fileContent = StreamToByte(resource);
// //ファイル書き込み
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + "sample.xml");
response.setContentLength(fileContent.length);
OutputSreamWrite(response, fileContent);
return null;
}
という感じで、コントローラーの最終形はこうなります
package tsugaruinfo.controller;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class XMLController {
@Autowired
ResourceLoader resourceLoader;
DomController(){
}
@RequestMapping(value="/personize", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public String personize(HttpServletResponse response) {
Resource resource = resourceLoader.getResource("classpath:sample.xml");
byte[] fileContent = null;
fileContent = StreamToByte(resource);
// //ファイル書き込み
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + "sample.xml");
response.setContentLength(fileContent.length);
OutputSreamWrite(response, fileContent);
return null;
}
/**
* InputStream から バイト文字列に変換
* @param filepath
* @return
*/
private byte[] StreamToByte(Resource resource) {
int nRead;
InputStream is = null;
byte[] fileContent = new byte[16384];
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
//ファイルをバイト形式に変換
try {
is = new FileInputStream(resource.getFile().toString());
while ((nRead = is.read(fileContent, 0, fileContent.length)) != -1) {
buffer.write(fileContent, 0, nRead);
}
buffer.flush();
return buffer.toByteArray();
} catch (FileNotFoundException e) {
e.getStackTrace();
} catch (IOException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
return null;
}
/**
* ダウンロードファイル書き込み
* @param response
* @param fileContent
*/
public void OutputSreamWrite(HttpServletResponse response, byte[] fileContent) {
OutputStream os = null;
try {
os = response.getOutputStream();
os.write(fileContent);
os.flush();
} catch (IOException e) {
e.getStackTrace();
}
}
}
ちょっと長くなっちゃいましたね。ですが、面倒な処理は分離しているので、これから新しいダウンロード機能を作るときは、面倒な処理を使いまわせるようにしています。
1つ1つの処理の解説はしているので、全体を一気に取らえるより、小さな完成品を理解するようにすればいいかと。
レッツ実行
では実際のアドレスにアクセスしてみましょう。
↓
sample.xmlがサーバーからダウンロードできました。


