質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Spring Security

Spring Securityは、Springのサブプロジェクトの一つでWebアプリケーションに必要な機能を追加します。正規ユーザーであるかを確認するための「認証機能」と、ユーザーのアクセスを制御する「認可機能」を簡単に追加することが可能です。

アップロード

アップロードは特定のファイルをウェブサーバに送るプロセスのことを指します。

Thymeleaf

Thymeleaf(タイムリーフ)とは、Java用のテンプレートエンジンで、特定のフレームワークに依存せず使用することが可能です。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

Q&A

解決済

1回答

12662閲覧

spring bootで画像のアップロードを行いたい。

hello_space

総合スコア24

Spring Security

Spring Securityは、Springのサブプロジェクトの一つでWebアプリケーションに必要な機能を追加します。正規ユーザーであるかを確認するための「認証機能」と、ユーザーのアクセスを制御する「認可機能」を簡単に追加することが可能です。

アップロード

アップロードは特定のファイルをウェブサーバに送るプロセスのことを指します。

Thymeleaf

Thymeleaf(タイムリーフ)とは、Java用のテンプレートエンジンで、特定のフレームワークに依存せず使用することが可能です。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

0グッド

1クリップ

投稿2020/09/21 07:55

編集2020/09/21 08:09

spring boot 初学者です。
自分で作ったフォルダの配下にアップロードした画像を表示させたいのですがうまくいきません。
アップロード自体はできたのですが、それをどう表示したらいいのかがわからず質問させていただきました。
理想としてはstaticの下にあるimagesファイルの下に画像をアップロードすることができれば、thymeleafのほうで読み込めたのですが、調べるとサーバー起動後に追加した画像は読み込まれないということを知り、その方法はとらないことにしました。
そのため、spring bootのプロジェクト直下にhogeという名前でフォルダを作りそこに画像をアップロードするまではできたのですが、そのあと画面のほうで画像を表示することができない状態で詰まってしまいました。

前提・実現したいこと

自分でプロジェクト直下に作ったフォルダ内にある画像を表示させたい。

発生している問題・エラーメッセージ

画像が読み込まれない。

該当のソースコード

project/ ┣ src/main/resources/ │   ┣ static/ │ //この時は表示できていた。 │ ┣ images/ │ ┣ hoge.png │ // ここに自分でフォルダを追加 ┣ hoge/ // これを表示させたい ┣ fuga.png

java

1<div class="container"> 2 <div class="store_wrap col-12 col-sm-12 col-md-6 col-lg-4 my-5 text-center" th:each="store : ${stores}" th:object="${store}"> 3 // ここでimageを表示させたい (static/images配下にイメージを配置していた時は<img th:src="@{/images/} + *{image}">で表示できていた。 4 <div class="store_image"><img th:src="*{image}"></div> 5 <div class="store_text text-wrap text-break"> 6 <h3> 7 <a th:href="@{/main/{id}(id=*{id})}" th:text="*{name}"></a> 8 </h3> 9 <h3> 10 <a th:href="@{/main/{id}(id=*{id})}" th:text="*{address}"></a> 11 </h3> 12 </div> 13 </div> 14</div>

セキュリティ関係も色々記述変えてみたんですがあまり理解しておらずうまくいきませんでした。

websecurity

1 @Override 2 public void configure(WebSecurity web) throws Exception { 3 web.ignoring().antMatchers("/css/**","/js/**","/images/**","/fonts/**","/api/**"); 4 }
public void uploadfile(MultipartFile upfile) { if(!upfile.isEmpty()) { try { Files.copy(upfile.getInputStream(), Paths.get("/hoge", upfile.getOriginalFilename())); } catch(RuntimeException | IOException e) { } } return;
@GetMapping("/main") String index(Model model) { List<Store> stores = storeService.findAll(); model.addAttribute("stores", stores); return "store/index"; }

試したこと

src属性を変えたりして試してみたのですがうまく表示されませんでした。

補足情報(FW/ツールのバージョンなど)

spring boot 1.4.0
webSecurity使用中
thymeleaf 3
java 1.8

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

SpringBootアプリケーション内のstaticリソースへファイルをアップロードした場合は、アプリケーションを更新すると削除されるかと思います。
SpringBootは静的ファイルをWebアプリケーションの外へも設定できますので、まずはそこへの静的リソースパスを設定します。以下は設定例です。

application.yml

yml

1spring: 2 resources: 3 static-locations: 4 - classpath:/static/ 5 - file:/var/file/

この設定で、例えば http://localhost:8080/(ファイル名) で参照させたい場合は、/static/ 以下のファイル、ないしは /var/file/ 以下のファイルを自動的に探し出します。

あとはファイルアップロードの際に、 /var/file/ 以下へアップロードをすれば参照できます。

Controllerの実装:

java

1import java.io.File; 2import java.io.FileOutputStream; 3import java.io.IOException; 4import java.io.InputStream; 5 6import org.apache.tomcat.util.http.fileupload.IOUtils; 7import org.springframework.stereotype.Controller; 8import org.springframework.validation.BindingResult; 9import org.springframework.web.bind.annotation.GetMapping; 10import org.springframework.web.bind.annotation.PostMapping; 11import org.springframework.web.bind.annotation.RequestMapping; 12import org.springframework.web.bind.annotation.RequestParam; 13import org.springframework.web.multipart.MultipartFile; 14import org.springframework.web.servlet.ModelAndView; 15 16@Controller 17@RequestMapping("/upload") 18public class FileUploadController { 19 @PostMapping("upload") 20 public ModelAndView upload(@RequestParam("file") MultipartFile multipartFile, ModelAndView mnv, BindingResult result) { 21 22 if (result.hasErrors()) { 23 String message = result.getFieldError().getDefaultMessage(); 24 mnv.addObject("errorMessage", message); 25 mnv.setViewName("upload/index"); 26 return mnv; 27 } 28 29 if (multipartFile.isEmpty()) { 30 String message = "ファイルがありません"; 31 mnv.addObject("errorMessage", message); 32 mnv.setViewName("upload/index"); 33 return mnv; 34 } 35 36 try (InputStream uploadStream = multipartFile.getInputStream()){ 37 String filename = multipartFile.getOriginalFilename(); 38 FileOutputStream fos = new FileOutputStream(new File("/var/file/" + filename)); 39 IOUtils.copyLarge(uploadStream, fos); 40 mnv.addObject("uploadFileName", filename); 41 } catch (IOException e) { 42 log.warn("アップロード処理でエラーが発生しました", e); 43 String message = "アップロード処理が失敗しました"; 44 mnv.addObject("errorMessage", message); 45 mnv.setViewName("upload/index"); 46 return mnv; 47 } 48 49 mnv.addObject("message", "アップロードが完了しました"); 50 mnv.setViewName("upload/index"); 51 return mnv; 52 } 53}

アップロード画面の実装は以下のようになります。これも簡易的に、アップロード画面と、完了画面を同一にしています。

html

1<!DOCTYPE html> 2<html xmlns:th="http://www.thymeleaf.org"> 3<head> 4<meta charset="UTF-8" /> 5<meta name="viewport" 6 content="width=device-width, initial-scale=1, shrink-to-fit=no" /> 7<title>Title</title> 8</head> 9<body> 10 <div class="container"> 11 <div class="alert alert-primary" role="alert" th:if="${message}" th:text="${message}">通常メッセージ</div> 12 <div class="alert alert-warning" role="alert" th:if="${errorMessage}" th:text="${errorMessage}">エラーメッセージ</div> 13 <form method="post" th:action="@{/upload/upload}" enctype="multipart/form-data"> 14 <input type="file" name="file" > 15 <button type="submit" class="btn btn-primary">アップロード機能を使う</button> 16 </form> 17 <img th:if="${uploadFileName}" th:src="@{/{filename}(filename=${uploadFileName})}" width="320"/> 18 </div> 19</body> 20</html>

SpringSecurityの設定は以下です。
最も簡易的なformログインの、ユーザ名user、パスワードpasswordでログインできるものです。

java

1import org.springframework.context.annotation.Bean; 2import org.springframework.security.config.annotation.web.builders.HttpSecurity; 3import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 4import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 5import org.springframework.security.core.userdetails.User; 6import org.springframework.security.core.userdetails.UserDetails; 7import org.springframework.security.core.userdetails.UserDetailsService; 8import org.springframework.security.provisioning.InMemoryUserDetailsManager; 9 10/** 11 * SpringSecurity設定。 12 * https://github.com/spring-projects/spring-security/blob/5.4.0/samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java 13 * @author a-pz 14 * 15 */ 16@EnableWebSecurity 17public class SecurityConfig extends WebSecurityConfigurerAdapter { 18 @Override 19 protected void configure(HttpSecurity http) throws Exception { 20 21 http.authorizeRequests( 22 (authorize) -> authorize 23 .antMatchers("/webjars/**","/index","/static/**").permitAll() 24 .antMatchers("/upload/**").hasRole("USER") 25 ).formLogin( 26 (formLogin) -> formLogin 27 .loginPage("/login") 28 .failureUrl("/login-error") 29 ); 30 } 31 32 @Bean 33 protected UserDetailsService userDetailsService() { 34 UserDetails userDetails = User.withDefaultPasswordEncoder() 35 .username("user") 36 .password("password") 37 .roles("USER") 38 .build(); 39 return new InMemoryUserDetailsManager(userDetails); 40 } 41} 42

イメージ説明

投稿2020/09/21 10:18

編集2020/09/21 10:19
A-pZ

総合スコア12011

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hello_space

2020/09/22 01:12 編集

ご回答いただきありがとうございます!! 申し訳ありません。3点ほど質問があります。 1.試してみたのですが、static以下のcss、js等が読み込まれなくなってしまいました。 application.propertiesに以下のように記述しました。 css,jsはstaticの配下にあります。 spring.resources.static-locations=classpath:/static/ file:/var/file/ 2.アプリケーションの外というのはspring bootのプロジェクトの外という意味でしょうか?その場合、自分のPC上に/var/fileを作るという認識でよろしいでしょうか?ちなみに私はwindowsを使用しております。 3.画像を表示させたいページは@PostMapping("upload")以外のメソッドを使用しています。そのため、mnv.addObject("uploadFileName", filename);でhtmlのほうでth:if=${uploadFileName}が空になってしまい使うことができません。 そのため、htmlで直接 /var/file直下にあるファイルを参照したいのですがその場合どう言った記述をすればよろしいでしょうか?フィールド名はString型のimageです。 質問が多く申し訳ありません。 ご回答お願いいたします。
A-pZ

2020/09/22 01:23 編集

1. プロパティでの記述方法ですが、複数項目ある場合はカンマつなぎです。 spring.resources.static-locations=classpath:/static/,file:/var/file/ 2. Windowsでも、SpringBootを実行しているドライブに /var/file/ を作成すれば問題ありません。 3. 実際にimgタグで出力されたURLを見ていただきたいのですが、実際にアップロードしたファイル名そのものが /var/file/ にあり、そのファイルパスをstatic-locationsで関連付けしていますので、例えば http://localhost:8080 でアプリケーションが動作している場合は、 http://localhost:8080/(アップロードされたファイル名) になります。
hello_space

2020/09/22 01:56

ご回答ありがとうございます! 何度も申し訳ございません。 1については,を付けたところcssが適用されました!本当にありがとうございます! 2についてもう少し詳しく教えていただきたいのですが、SpringBootを実行しているドライブというのはSpringToolSuite4.exeが配置してあるところのことでしょうか?それともCドライブ直下でしょうか?はたまたそれ以外でしょうか? ファイル構成など把握しておらず申し訳ありません。よろしくお願いいたします。
A-pZ

2020/09/22 02:30

SpringToolSuiteを実行しているドライブでっす。
hello_space

2020/09/22 02:50 編集

理解ができなくて申し訳ありません。ドライブという言葉が何を表しているかがわかっておりません。 spring-tool-suite-4-4.7.2.RELEASE-e4.16.0-win32.win32.x86_64.self-extracting       ┣ sts-4.7.2.RELEASE            ┣ lombok.jar            ┣ SpringToolSuite4.exe            ┣ var              ┣ file こちらで合っているでしょうか?よろしくお願いいたします。
A-pZ

2020/09/22 04:54

いいえ、Cドライブで実行しているならCドライブ直下です。
hello_space

2020/09/22 05:55

ありがとうございます! Cドライブ直下にvar/fileを作り、そこにアップロードまではできました! ただ、やはり画像を読み込んでくれません。 画像を表示させたいurl http://localhost:8080/main デベロッパーツールで確認すると <img src="/表示させたい画像ファイル" width="320"> となっています。 ここを色々いじっているのですが表示されません。 var/file直下には表示させたい画像が配置されています。 何度もすみません。よろしくお願いいたします。
A-pZ

2020/09/22 06:47

thymeleafでURLを生成している <img th:if="${uploadFileName}" th:src="@{/{filename}(filename=${uploadFileName})}" にて、uploadFileNameがある場合に表示しています。表示したいファイル名をControllerで uploadFileName に格納すれば表示されます。 URLに/main で指定してリクエストした場合は、Controller にて /main のパスが設定されたロジックが実行されるかと思いますが、そのときに画像をレスポンスしたい、ということでしょうか?(最初の質問内容からだいぶ反れているように思いますが…)
hello_space

2020/09/22 07:16

経緯からお話しすると現在ECサイトをspring bootにて作成しております。その中で商品をデータベースに登録したかったので商品名、価格、在庫等をフォームで入力していき、商品画像もフォームで送信してそれをhttp://localhost:8080/mainで遷移した先の画面にて新しく登録した商品として表示させたかったのです。そのため画像アップロード処理が必要だったのですが、調べてもあまり画像アップロードについては情報が少なく色々試してはみたもののうまくいかず質問させていただいたという次第であります。 よろしくお願いいたします。
A-pZ

2020/09/22 09:37

/mainがコンテキストパスであれば、localhost:8080/main/画像ファイル名 で表示されますでしょうか? ログイン済みのブラウザにて、実際にアクセスを行っても表示されませんでしょうか。
hello_space

2020/09/22 09:54

デベロッパーツールで<img src="http://localhost:8080/main/画像ファイル名" width="320"> にしてみましたが表示されませんでした。 URLに直接localhost:8080/main/画像ファイル名と打つと Failed to convert value of type [java.lang.String] to required type [java.lang.Integer]; nested exception is java.lang.NumberFormatException: For input string: "画像ファイル名"となります。 これはmain/{id}で詳細画面に飛ぶ設定にしてあるからだと思います。
hello_space

2020/09/22 10:45

@Controllerの@GetMapping("/main")としています。 <div class="store_image"><img th:if="*{image}" th:src="@{localhost:8080/main/} + *{image}" width="320"/></div> で表示させようとすると GET localhost:8080/main/画像ファイル名 net::ERR_UNKNOWN_URL_SCHEME と出ます。 DBの設定でうまくいってないのでしょうか?
A-pZ

2020/09/22 11:29

thymeleafのURL表現である @{ ... } は コンテキストパスからのURLを生成してくれるものですので、その記述は正しくありません。 アップロードしたあとのパスが / からだと都合悪い場合は、アップロードしたファイルのパスを別の階層にする方法で試してください。 例えば、Springの設定で、static-resources を /var/file/ のままにしておき、アップロードファイルの保存先を /var/file/upload_images/ にして、HTMLの th:src="@{/upload_images/{filename}(filename=${uploadFileName})}" とすると、Controllerにて /upload_images が登録されていなければ動作します。
hello_space

2020/09/22 13:06

ありがとうございます! 画像はデベロッパーツールでいじれば表示はできるのですが、商品一覧画面(ここで画像を表示させたい)→商品新規作成フォームへ→ファイルアップロードといった遷移をするので最初に商品一覧画面を表示するときがuploadFileNameに値が入っておらず、画像が表示されません。addObjectを使わないやり方はないのでしょうか?よろしくお願いいたします。
A-pZ

2020/09/22 13:15

アップロードされていなければ画像は表示されません。
hello_space

2020/09/22 13:26

ありがとうございます。 アップロードをしてもuploadFileNameに値が入っておらず画像が表示されないのでaddObjectの前でうまくいってないのかもしれません。 もう少し原因を探ってみたいと思います。本当に何度もありがとうございます!
hello_space

2020/09/22 13:50

今アップロードが完了したら商品一覧ページにredirectする仕様になっているのですが、これは画像が表示できない理由と関係がありますでしょうか?
A-pZ

2020/09/22 13:54

リダイレクトした場合はmodelに格納した内容は消えますので、RedirectAttributeを使ってリダイレクト先に情報を共有させると良いです。ファイルアップロードのControllerメソッドの引数に RedirectAttributeを追加しておけば、リダイレクト先にて取り出せます。https://qiita.com/kamikenta/items/074f4126857aaa8b6d88 を参考に。
hello_space

2020/09/22 14:31

できました!ありがとうございます! とりあえず画像をアップロードし表示させることができたのでこちらの質問は閉めさせていただきます。 また、つたない質問にも何度も答えていただきありがとうございました! ベストアンサーに選ばさせていただきます。次はDBに保存した画像データを引っ張ってくるやり方でチャレンジしたいと思います!
A-pZ

2020/09/22 15:30

d(・ω・ おつかれさまでした!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問