20220402のJavaに関する記事は7件です。

初心者がJavaのマルチスレッドプログラミングを学ぶお題を作ってみた

はじめに チーム内でJavaプログラミング初心者向けの勉強会をしていて、そのときに出したマルチスレッドプログラミングの勉強用の題材とメンバーからの回答例です。 よくある事例からお題を作ってみたら、いろんな回答が返ってきました。 お題 以下のプログラムをスレッドセーフにしてみよう スレッドアンセーフ(お題) package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import lombok.Getter; public class ThreadUnsafeMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { @Getter private int count = 0; /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public void countUp() { this.count++; } } } メンバーの回答例 synchronizedメソッドを利用 synchronizedメソッド package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SynchronizedMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { private int count = 0; /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public synchronized void countUp() { this.count++; } public synchronized int getCount() { return this.count; } } } 簡単な解説 この場合、インスタンス自身をロックオブジェクトとして排他制御している synchronizedブロックでオブジェクトを同期化 synchronizedブロックで同期 package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SynchronizedMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { private int count = 0; private final Object lock = new Object(); /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public void countUp() { synchronized (lock) { this.count++; } } public int getCount() { synchronized (lock) { return this.count; } } } } 簡単な解説 明示的にロックオブジェクトを使って排他制御をしている Lockクラスを利用 ReentrantLockクラス package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { private int count = 0; private Lock lock = new ReentrantLock(); /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public void countUp() { lock.lock(); try { this.count++; } finally { lock.unlock(); } } public int getCount() { lock.lock(); try { return this.count; } finally { lock.unlock(); } } } } 簡単な解説 ロックオブジェクト+synchronizedと比較して、柔軟な排他制御によるスケーラビリティ(read/writeの分離)やタイムアウト指定が可能なため、安全(このサンプルでは登場していない) volatile修飾子を利用 volatile修飾子 package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import lombok.Getter; public class ThreadUnsafeVolatileMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { @Getter private volatile int count = 0; /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public void countUp() { this.count++; } } } 簡単な解説 volatile修飾子は可視性(メインメモリの最新の値が見える)のみを保証するだけで、Compare-and-Swap(CAS)の原子性は保証されないので、スレッドセーフではない。期待する結果が得られない Atomic変数を利用(このお題に対しての、私の中のベストアンサー) Atomic変数 package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class AtomicIntegerMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { private AtomicInteger count = new AtomicInteger(0); /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public void countUp() { this.count.incrementAndGet(); } public int getCount() { return count.get(); } } } 簡単な解説 Atomic変数は、Compare-and-Swap(CAS)の原子性を保証しつつ、ロックフリー同期を行うため、synchronizedやLockよりもパフォーマンスが劣化しにくい。かつ、デッドロックも起きないため安全 ただし、1つの処理単位で複数の変数の更新を行う場合には、複雑な実装が必要になるため、synchronizedやLockを使った方が簡単にはなる 補足)Javaのメモリモデル Javaのスレッドプログラミングを正しく理解するには、Javaのメモリモデルの理解が必須(スレッドごとのローカルメモリとヒープの関係) さいごに スレッドセーフなプログラムは複数通りの書き方ができますが、人によって違う答えが帰ってきて面白いなーと思ったので、ここに書いてみました。それぞれの違いを正しく理解して適材適所でプログラミングできることが重要だと再認識。 他にも、初心者向けの解説や最適な題材があれば、教えていただけると嬉しいです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者向けのJavaのマルチスレッドプログラミングを学ぶ題材

はじめに チーム内でJavaプログラミング初心者向けの勉強会をしていて、そのときに出したマルチスレッドプログラミングの勉強用の題材とメンバーからの回答例です。 よくある事例からお題を作ってみたら、いろんな回答が返ってきました。 お題 以下のプログラムをスレッドセーフにしてみよう スレッドアンセーフ(お題) package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import lombok.Getter; public class ThreadUnsafeMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { @Getter private int count = 0; /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public void countUp() { this.count++; } } } メンバーの回答例 synchronizedメソッドを利用 synchronizedメソッド package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SynchronizedMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { private int count = 0; /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public synchronized void countUp() { this.count++; } public synchronized int getCount() { return this.count; } } } 簡単な解説 この場合、インスタンス自身をロックオブジェクトとして排他制御している synchronizedブロックでオブジェクトを同期化 synchronizedブロックで同期 package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SynchronizedMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { private int count = 0; private final Object lock = new Object(); /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public void countUp() { synchronized (lock) { this.count++; } } public int getCount() { synchronized (lock) { return this.count; } } } } 簡単な解説 明示的にロックオブジェクトを使って排他制御をしている Lockクラスを利用 ReentrantLockクラス package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { private int count = 0; private Lock lock = new ReentrantLock(); /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public void countUp() { lock.lock(); try { this.count++; } finally { lock.unlock(); } } public int getCount() { lock.lock(); try { return this.count; } finally { lock.unlock(); } } } } 簡単な解説 ロックオブジェクト+synchronizedと比較して、柔軟な排他制御によるスケーラビリティ(read/writeの分離)やタイムアウト指定が可能なため、安全(このサンプルでは登場していない) volatile修飾子を利用 volatile修飾子 package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import lombok.Getter; public class ThreadUnsafeVolatileMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { @Getter private volatile int count = 0; /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public void countUp() { this.count++; } } } 簡単な解説 volatile修飾子は可視性(メインメモリの最新の値が見える)のみを保証するだけで、Compare-and-Swap(CAS)の原子性は保証されないので、スレッドセーフではない。期待する結果が得られない Atomic変数を利用(このお題に対しての、私の中のベストアンサー) Atomic変数 package study.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class AtomicIntegerMain { private static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CountDownLatch latch = new CountDownLatch(1); long start = System.currentTimeMillis(); executor.execute(() -> { for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.countDown(); }); for (int i = 0; i < 100_000; i++) { counter.countUp(); } latch.await(); long end = System.currentTimeMillis(); // countは200,000を期待 System.out.println(String.format("count=%d, 処理時間=%dms", counter.getCount(), (end - start))); } private static class Counter { private AtomicInteger count = new AtomicInteger(0); /** * 1. count の値を読み出す<br> * 2. 読み出した値に 1 を足す<br> * 3. 足した結果を count に保存する */ public void countUp() { this.count.incrementAndGet(); } public int getCount() { return count.get(); } } } 簡単な解説 Atomic変数は、Compare-and-Swap(CAS)の原子性を保証しつつ、ロックフリー同期を行うため、synchronizedやLockよりもパフォーマンスが劣化しにくい。かつ、デッドロックも起きないため安全 ただし、1つの処理単位で複数の変数の更新を行う場合には、複雑な実装が必要になるため、synchronizedやLockを使った方が簡単にはなる 補足)Javaのメモリモデル Javaのスレッドプログラミングを正しく理解するには、Javaのメモリモデルの理解が必須(スレッドごとのローカルメモリとヒープの関係) さいごに スレッドセーフなプログラムは複数通りの書き方ができますが、人によって違う答えが帰ってきて面白いなーと思ったので、ここに書いてみました。それぞれの違いを正しく理解して適材適所でプログラミングできることが重要だと再認識。 他にも、初心者向けの解説や最適な題材があれば、教えていただけると嬉しいです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】ファイル操作関連

まえがき Javaではファイル操作関連クラスが豊富に提供されている。それぞれのクラスの役割/使い方についてまとめる。 java.io と java.nio と java.nio2 JDK6/SE6:io系(File) JDK7/SE7:nio系(Files, Path) JDK8/SE8:nio2系(nioの強化)+ Stream + ラムダ式 + メソッド参照 SE → JavaAPI群。JDKの一部品。 JDK → Java開発プログラムのセット(ソフトウェア) JDK6/SE6:io系(File) File ・ファイルの置き場所を定義する ・ファイルを操作する JDK7/SE7:nio系(Files, Path) Path ・ファイルの置き場所を定義する Files ・ファイルを操作する Fileクラスの2機能を、PathクラスとFilesクラスで分割したような形。 Fileクラスにはない便利機能がPathとFilesにはあるので、JDK7/SE7以上の環境である場合は  ✕ Fileクラス  〇 Pathクラス&Filesクラス の組み合わせで利用するとBETTERなコーディングができるだろう? Filesクラスの便利なやつ ファイル作成/コピー/削除系 メソッド 機能 Files.copy(Path fromPath, Path toPath) コピー Files.createFile(Path path, FileAttribute attr) 新規ファイル作成 with ファイル権限第2引数なしバージョンFiles.createFile(Path p1);第2引数ありバージョンFiles.createFile(Path p1, PosixFilePermissions.asFileAttribute(EnumSet.of(OWNER_READ, …)));orPosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString(“r—r—r—“))); Files.createDirectory(Path path, FileAttribute attrs...) 新規ディレクトリ作成※親ディレクトリがないとエラー Files.createDirectories(Path path, FileAttribute attrs...) 新規ディレクトリ作成※親ディレクトリがなければ勝手に作る Files.delete(Path path) ファイルorディレクトリの削除※ディレクトリ内は空でないと例外発生 Files.deleteIfExists(Path path) ファイルorディレクトリの削除※対象ファイルがあったら消すけど、なかったら例外発生せずfalse返して終わる。 Files.move(Path fromPath, Path toPath, CopyOption options) ファイルの移動/リネーム Files.exists(Path path, LinkOption options) ファイルの存在有無の確認LinkOption.NO_FOLLOW_LINK→シンボリックリンクをたどらない ファイル読み書き系 メソッド 機能 Files.newInputStream(Path path) Pathオブジェクト→InputStreamの作成ファイル内の文字をプログラム内で参照する時に使える。 Files.newOutputStream(Path path) Pathオブジェクト→OutputStreamの作成ファイルに書き出す時に利用できる。 Files.newBufferedReader(Path path) 直でBufferedReaderを呼べる代物。デフォルトで文字コードはUTF-8。=前だったら=new BufferedReader(new FileReader(new File("----")))=これだと=Files.newBufferedReader(Path.get("----")) シンプルで良い。 Files.newBufferedReader(Path oath, Charset charset) ↑の文字コード指定するバージョンFiles.newBufferedReader(Path.get("----"), StandardCharsets.UTF-8); Files.newBufferedWriter(Path path) Files.newBufferedWriter(Path, Charset charset) Files.readAllLines(Path path) 全行をList<String>で返す。 Files.readAllLines(Path path, Charset charset) ↑の文字コード指定するバージョン。 ファイル情報操作系 メソッド 機能 Files.getPosixFilePermissions(Path path, LinkedOption …) 既存ファイルの権限取得 Files.setPosixFilePermissions(Path path,Set set); 既存ファイルの権限設定 Files.size(Path path) ファイルの容量の取得 Files.isReadableFiles.isWritableFiles.isExecutable JVMが〇〇可能か streamを使う系 メソッド 機能 Files.walk(Path path)Files.list(Path path) ディレクトリ内のエントリを全て取得 Files.walk(Path path, int maxDepth) 調べる階層数を指定して、ディレクトリ内のエントリを取得 Files.find(Path path, int maxDepth, BiPredicate matcher) ディレクトリ内で指定した条件に該当するエントリのみ取得BiPredicate 第1引数はPathオブジェクト、第2引数はFileAttiributeを示すFiles.find(dir, Integer.MAX_VALUE, (p, attr) -> p.toFile().getName().endsWith(".png")).forEach(System.out::println); Files.lines(Path path) ○○Readerとか書かずに中身をStreamで取り出せるFiles.lines(path).forEach(System.out::println); Reader, Writer, InputStream, OutputStreamらへんの整理 =古いとされるやつ= ・FileInputStream ~バイト~ ・FileOutputStream ~バイト~ ・FileReader ~文字列~ ・FileWriter ~文字列~ =新しいとされるやつ= ・BufferedInputStream ~バイト~ ・BufferedOutputStream ~バイト~ ・InputStreamReader バイト→文字列にして読み込む ・OutputStreamWriter バイト→文字列にして読み込む ・BufferedReader 文字列 ・BufferedWriter 文字列 ✅ 7から提供されている「バッファ」を使うために、古いやつを新しいやつでラップして使う。 ✅ 既存ファイルをコピーする場合は「バイト→バイト」でOK. org.springframework.core.io.Resourceクラスを使う Spring Frameworkでは、ファイル・クラスパス(src/main/resources等)配下のリソースにアクセスするためにResourceインタフェースが提供されている。実装クラスとして「ClassPathResource」と「FileSystemResource」を利用可能。 ClassPathResource Resource resource = new ClassPathResource("src/main/resources/file/sample_file_1.txt"); FileSystemResource Path path = Path.of("src/main/resources/file/sample_file_1.txt"); Resource resource = new FileSystemResource(path); Resourceインタフェースで提供しているメソッド resource.getFile() -> Fileオブジェクト内を返す resource.getInputStream() -> InputStreamオブジェクトを返す resource.getURL() -> URLオブジェクトを返す // 他にもいろいろある ファイルダウンロード時にResourceインタフェースを利用する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SpringBootの値をJavaScriptに渡す方法

はじめに SpringBootで設定した値をJavaScriptに渡す際に、少しばかり、つまずいたため備忘録がてら記録しておこうと思います。 SpringBootとJavaScriptを用いた場合には、非常にあるあるな事象だと思うので、ご参考になれば幸いです。 ちなみに、Thymeleafでは、このことを「 JavaScriptナチュラルテンプレート 」と呼ぶようです。 ControllerからJavaScriptに値を渡す方法 以下のようにModelに登録してある値をJavaScriptに渡したいとします。 SampleController.java @GetMapping("/index") public String getIndex(EasyHouseholdForm form, Model model) { model.addAttribute("form", form); return "sample/index"; } これを渡す方法はThymeleafで以下のようにします。 index.html <script th:inline="javascript"> const form = /*[[${form}]]*/"form"; console.log(form); </script> ポイントとしては、<script>タグのth:inline属性の値にjavascriptを設定し、/*[[${渡したい値}]]*/とすることでJavaからJavaScriptに値を渡すことができます。 また、定数定義の後ろの "form"; ですが、こちらは無視される仕様となっているようです。 これを加えないとエラーとなり、連続しての定数もしくは変数の定義(以下、参照)ができないようです。 index.html <script th:inline="javascript"> const hoge = /*[[${hoge}]]*/"hoge"; const fuga = /*[[${fuga}]]*/"fuga"; console.log(form); </script> 上記のように「JavaScriptナチュラルテンプレート」の記載をすれば、連続して定数・変数の定義が可能です。 もちろん、JavaScriptの外部ファイル(〇〇.js)に渡したい場合も同様の内容で実装することができます。 ※もちろん、HTML内で該当のjsファイルを読み込んでいないとできませんが・・・ JSファイルに値を渡す方法 こちらも最初のやり方は同じです。 index.html <script th:inline="javascript"> const form = /*[[${form}]]*/"form"; // JavaScriptの関数呼び出し sample(); </script> まずはHTMLで値を変数に代入します。 あとはこの値を使用したいJavaScriptファイルで使用するだけです。 index.js 'use strict' { function sample(){ console.log(form); } } このようにすれば、JavaScriptファイルでもJavaの値を使用することができます。 ただし、この方法には制約があるので、その点だけ注意が必要です。 以下が、その制約です。 <script>タグにsrc属性、またはth:src属性が指定してある場合には使用できないこと(th:inline属性とsrc属性ないしth:src属性の併用は不可) 上記の制約の通り、<head>タグ内で<script>タグを作成の上、そこでsrc属性、ないしth:src属性を利用して、JavaScriptファイルを読み込む必要がある とはいえ、各自の仕様や好みにもよるので、前者を使用する人が大多数かと思います。 筆者自身の場合は、HTML内でのJavaScriptの記述は最低限にして、JSファイルでJavaScriptを書く場合が多いので、後者の方法が必須となります。 このように、好みによるところもあるので前者を使うのが多くの人にとっては無難かと思われます。 参考文献 Thymeleaf Spring Bootの設定値をJavaScriptの引数に渡してみた SpringBoot thymeleafでデータをjs内で受け取る
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】ファイルダウンロード

まえがき ファイルをバイナリに変換したものをレスポンスにセットすることで、ファイルダウンロードを実現する。やり方は2つ。 ① レスポンス(Controllerメソッドの戻り値)にバイナリをセットする。 ② レスポンス(メソッドの引数/HttpServletResponse)にバイナリをセットする。 参考 ① レスポンス(Controllerメソッドの戻り値)にバイナリをセットする。 ② レスポンス(メソッドの引数/HttpServletResponse)にバイナリをセットする。 ① レスポンス(Controllerメソッドの戻り値)にバイナリをセットする。 ソースコード import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import org.springframework.core.io.PathResource; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/files") public class FileController { @GetMapping("/downloadFile") public ResponseEntity<Resource> downloadFile() throws Exception { Path path = Path.of("src/main/resources/file/sample_file_1.txt"); Resource resource = new PathResource(path); return ResponseEntity.ok() .contentType(getContentType(path)) .contentLength(resource.contentLength()) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") .body(resource); } private MediaType getContentType(Path path) throws IOException { try { return MediaType.parseMediaType(Files.probeContentType(path)); } catch (IOException e) { return MediaType.APPLICATION_OCTET_STREAM; } } } 補足 HttpHeaders.CONTENT_DISPOSITIONとは? ・レスポンスとして返したファイルをどう処理するかを定めるヘッダー情報。 ヘッダ内容 処理内容 inline WEBページとして表示 attachment ダウンロードする attachment; filename="filename.jpg" ファイル名指定でダウンロードする // WEBページとして表示 ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "inline"); // ダウンロードする ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment") // ファイル名指定でダウンロードする ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") MediaType.APPLICATION_OCTET_STREAMとは? ・MIMEの種類の1つ。 ・「ファイルの種類は気にするな!」を意図した表現。 return MediaType.APPLICATION_OCTET_STREAM; ② レスポンス(メソッドの引数/HttpServletResponse)にバイナリをセットする。 ・ダウンロード用に作成した一時ファイルを最後に削除する、という処理を差し込みたい場合は①ではなくこの②を使う。 ソースコード @Controller @RequestMapping("/files") public class SampleController { @Autowired FastExcel fastExcel; private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); @GetMapping("/downloadFile2") public void downloadFile2(HttpServletResponse response) throws Exception { // テンプレートファイルをコピー → 一時ファイル作成 Path templateFile = Path.of("src/main/resources/file/templateFile.txt"); Path temporaryFile = Path.of("src/main/resources/tmp/" + format.format(new Date()) + ".txt"); Files.copy(templateFile, temporaryFile); Resource resource = new PathResource(temporaryFile); // レスポンス作成 response.setContentType(getContentType(temporaryFile).getType()); response.setContentLengthLong(resource.contentLength()); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\""); try ( BufferedInputStream in = new BufferedInputStream(Files.newInputStream(temporaryFile)); BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); ) { out.write(in.readAllBytes()); } // 一時ファイル削除 Files.deleteIfExists(temporaryFile); } private MediaType getContentType(Path path) throws IOException { try { return MediaType.parseMediaType(Files.probeContentType(path)); } catch (IOException e) { return MediaType.APPLICATION_OCTET_STREAM; } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【 Java Servletについて(また、その周辺) 】

現在書籍にてJavaを独学で学習中です。 この投稿はその備忘録になります。 Java Servlet(サーブレット)とは? Javaサーブレットとは、一言でいうとプログラムのことです。 どんなプログラムか? ・Javaを使って作成されている。 ・サーバ側(バックエンド側)で動くプログラム。 ・動的なwebページの配信システムを実現するためのプログラム。 ■Javaサーブレットの働き■ クライアント側からのリクエストをサーブレットが受けて、 データの処理や動的なwebページを生成したりします。 【例】YouTubeで?ボタンを押すとそれが反映されたページが構成される。 ■サーブレットコンテナという実行環境■ サーブレットはプログラムのため実行環境が必要になります。 その実行環境となるソフトウェアがサーブレットコンテナです。 ■GETメソッドとPOSTメソッド(リクエストの違い)■ サーブレットはクライアント側から送られてくるリクエストに対して、 GETメソッドかPOSTメソッドかを判断します。 ・GETメソッド...「指定したURLの情報を送り返してほしい」というリクエスト ・POSTメソッド...「送ったデータを基に処理して返してほしい」というリクエスト 【例】~会員サイトにログインを行う場合~ まず、検索画面にURLを打ち込んで検索をする(GETメソッドによるリクエスト)。 すると、ログイン画面が表示され、IDやパスワードを入力して送信を押す(POSTメソッドによるリクエスト)。 ■JSPとは?■ サーブレットについて調べた時に、JSPについての解説も度々拝見したので、併せて学習します。 JSPはサーブレットとペアで使われます。 サーブレットはHTMLで静的なコンテンツを出力するのは苦手です。 そのため、サーブレットは計算処理やデータへのアクセスを担当し、 JSPはサーブレットが処理したデータを受け取り、クライアント側に返答する役割を担っています。 ■まとめ■ Java Servletとはサーバー側で動くJavaで書かれたプログラムの事です。 クライアントからのリクエストに対応します。 しかし、静的なコンテンツは得意ではないためJSPと役割分担をしています。 また、Java Servlerが動くためにはサーブレットコンテナという環境が必要になります。 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaでメール受信

概要 Apache Jamesを使うサンプル。Jamesはかなり高機能なようですが、今回はメール受信して独自に処理する必要があったので、受信してログ出すだけの最小サンプル。 Apache James Javaで実装されているメールサーバ。SMTPやIMAPなどに対応しているようです。「Mailet」を実装することでメールの独自処理を行うことができます。 実装 https://github.com/YasunoriHigashiyama/custom-james-assembly-sample
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む