SpringBoot バリデーション
SpringBootのバリデータを試す
・@NotBlank付与
import java.io.Serializable; import javax.validation.constraints.NotBlank; public class User implements Serializable { private static final long serialVersionUID = 1L; @NotBlank private String name; @NotBlank private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
・バリデータのメッセージを設定
// src/main/resources/ValidationMessages.properties
javax.validation.constraints.NotBlank.message = 入力してください。
・@Valid付与、BindingResultもセットで必要
@RequestMapping(value="/", method=RequestMethod.GET) public ModelAndView index(ModelAndView mv) { mv.addObject("user", new User()); mv.setViewName("index"); return mv; } @RequestMapping(value="/regist", method=RequestMethod.POST) public ModelAndView regist(@ModelAttribute @Valid User user, BindingResult result, ModelAndView mv) { if (result.hasErrors()) { mv.setViewName("index"); mv.addObject("user", user); return mv; } mv.setViewName("result"); mv.addObject("user", user); return mv; }
・バリデーションメッセージの表示制御
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <form method="post" action="regist" th:object="${user}" > <label for="name">名前:</label> <input type="text" name="name" th:field="*{name}" th:errorclass="error-field"> <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span><br> <label for="password">パスワード:</label> <input type="text" name="password" th:field="*{password}" th:errorclass="error-field"> <span th:if="${#fields.hasErrors('password')}" th:errors="password"></span> <input type="submit" value="送信" /> </form> </body> </html>
SpringBoot レスポンス
SpringBoot レスポンスについて
・テンプレート名返却
※@RestControllerではbodyとして返却される
@RequestMapping(value="/", method=RequestMethod.GET) public String index() { return "index"; }
・body返却
@RequestMapping(value="/", method=RequestMethod.GET) @ResponseBody public String index() { return "index"; }
・ModelAndView返却
@RequestMapping(value="/", method=RequestMethod.GET) public ModelAndView index(ModelAndView mv) { mv.setStatus(HttpStatus.OK); mv.setViewName("index"); return mv; }
・フォワード
@RequestMapping(value="/", method=RequestMethod.GET) public String index() { return "forward:method"; } @RequestMapping(value="/method", method=RequestMethod.GET) @ResponseBody public String method() { return "method"; }
・リダイレクト
@RequestMapping(value="/", method=RequestMethod.GET) public String index() { return "redirect:method"; // return "redirect:http://localhost:8080/method"; } @RequestMapping(value="/method", method=RequestMethod.GET) @ResponseBody public String method() { return "method"; }
・リソース返却
@Autowired ResourceLoader resourceLoader; @RequestMapping(value="/", method=RequestMethod.GET, produces=MediaType.TEXT_HTML_VALUE) public Resource index() { return resourceLoader.getResource("classpath:templates/index.html"); }
・xml返却(@ResponseBody不要)
@RequestMapping(value="/", method=RequestMethod.GET, produces=MediaType.APPLICATION_XML_VALUE) public String index() { return "<xml><title>index</title></xml>"; }
・HTTPヘッダやステータスとあわせて返却
@RequestMapping(value="/", method=RequestMethod.GET) public ResponseEntity<String> index() { String body = "index"; HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.DATE, LocalDateTime.now().toString()); return new ResponseEntity<String>(body, headers, HttpStatus.OK); }
SpringBoot jsonの受け取りと返却
jsonの受け取りと返却を試した
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>User Setting</title> <script src="https://code.jquery.com/jquery-3.4.0.min.js" integrity="sha256-BJeo0qm959uMBGb65z40ejJYGSgR7REI4+CW1fNKwOg=" crossorigin="anonymous"></script> <script> $(function() { $('#submit').on('click',function(){ var json = { 'name':$('#name').val(), 'password':$('#password').val() }; // リストの場合[{json1},{json2}]... $.ajax({ url:'/json', type:'POST', contentType: 'application/json', data:JSON.stringify(json), dataType:'json' }) .done((data, textStatus, jqXHR) => { alert(JSON.stringify(data)); }) .fail((jqXHR, textStatus, errorThrown) => { alert(jqXHR.status); }) .always((data) => { }); }); }); </script> </head> <body> <form method="post" action="/body"> <label for="name">名前:</label> <input type="text" name="name" id="name"><br> <label for="password">パスワード:</label> <input type="text" name="password" id="password"> <input type="button" id="submit" value="送信" /> </form> </body> </html>
jsonのデータ格納先
public class User implements Serializable { private static final long serialVersionUID = 1L; private String name; private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
コントローラ
@RequestMapping(value= {"/json"}, method=RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public User index(@RequestBody User user) { return user; } // リストの場合 @RequestMapping(value= {"/json"}, method=RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public List<User> index(@RequestBody List<User> users) { return users; }
SpringBoot パラメータ取得
・リクエストパラメータ(クエリパラメータ、POSTパラメータ)の取得
value(name):パラメータ名
required:必須フラグ(デフォルトtrue)
defaultValue:デフォルト値
// http://localhost:8080/?id=1 // value省略(変数名がパラメータと一致していれば省略可能) public String getUser(@RequestParam String id) { return id; } // value省略 public String getUser(@RequestParam("id") String id) { return id; } // value指定 public String getUser(@RequestParam(value="id") String id) { return id; } // 必須フラグ指定 public String getUser(@RequestParam(value="id", required=true) String id) { return id; } // デフォルト指定 public String getUser(@RequestParam(value="id", required=true, defaultValue="") String id) { return id; } // Optional public String getUser(@RequestParam(value="id", required=false) Optional<String> id) { return id.orElse(""); }
・URLパスパラメータの取得
value(name):URLパスパラメータ名
required:必須フラグ(デフォルトtrue)
// http://localhost:8080/1 // value省略(変数名がURLパスパラメータと一致していれば省略可能) @RequestMapping(value= {"/{id}"}, method=RequestMethod.GET) @ResponseBody public String getUser(@PathVariable String id) { return id; } // value省略 @RequestMapping(value= {"/{id}"}, method=RequestMethod.GET) @ResponseBody public String getUser(@PathVariable("id") String id) { return id; } // value指定 @RequestMapping(value= {"/{id}"}, method=RequestMethod.GET) @ResponseBody public String getUser(@PathVariable(value="id") String id) { return id; } // URLパスパラメータを必須としない場合、リクエストマッピングにURLパスパラメータを外したURLを追加する必要がある @RequestMapping(value= {"/", "/{id}"}, method=RequestMethod.GET) @ResponseBody public String getUser(@PathVariable(value="id", required=false) String id) { return id; }
・リクエストヘッダ
value(name):リクエストヘッダの項目名
required:必須フラグ(デフォルトtrue)
defaultValue:デフォルト値
// ex Mozilla/5.0~ @RequestMapping(value= {"/"}, method=RequestMethod.GET) @ResponseBody public String index(@RequestHeader("User-Agent") String userAgent) { return userAgent; }
・リクエストボディ
required:必須フラグ(デフォルトtrue)
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>User Setting</title> </head> <body> <form method="post" action="/body"> <label for="name">名前:</label> <input type="text" name="name"><br> <label for="password">パスワード:</label> <input type="text" name="password"> <input type="submit" value="送信" /> </form> </body> </html>
// ex name=name&password=password @RequestMapping(value= {"/body"}, method=RequestMethod.POST) @ResponseBody public String index(@RequestBody String body) { return body; }
SpringBoot リクエストマッピング
・リクエストマッピングは以下の条件を指定できる
value(path)
リクエストパス
method
HTTPメソッドによる絞り込み
params
リクエストパラメータによる絞り込み
headers
リクエストヘッダによる絞り込み
consumes
Content-Typeヘッダによる絞り込み
produces
Acceptヘッダによる絞り込み
・HTTPメソッドのマッピング確認
//@RestController //@RequestMapping("api/users") @Controller public class UserController { //@GetMapping("/") @RequestMapping(value="/", method=RequestMethod.GET) public ModelAndView index(ModelAndView mv) { mv.setViewName("index"); return mv; } //@PostMapping @RequestMapping(method=RequestMethod.POST) @ResponseBody public String createUser(@RequestParam("name") String name) { return "call post"; } //@GetMapping("/{id}") @RequestMapping(value="/{id}", method=RequestMethod.GET) @ResponseBody public String getUser(@PathVariable String id) { return "call get"; } //@PutMapping("/{id}") @RequestMapping(value="/{id}", method=RequestMethod.PUT) @ResponseBody public String updateUser(@PathVariable String id, @RequestParam String name, @RequestParam String password) { return "call put"; } //@DeleteMapping("/{id}") @RequestMapping(value="/{id}", method=RequestMethod.DELETE) @ResponseBody public String deleteUser(@PathVariable String id) { return "call delete"; } }
・PostMapping
<form method="post" action="/"> <label for="name">名前:</label> <input type="text" name="name"><br> <label for="password">パスワード:</label> <input type="text" name="password"> <input type="submit" value="送信" /> </form>
・GetMapping
<form method="get" action="/1"> <label for="name">名前:</label> <input type="text" name="name"><br> <label for="password">パスワード:</label> <input type="text" name="password"> <input type="submit" value="送信" /> </form>
・PutMapping
<form method="post" action="/1"> <label for="name">名前:</label> <input type="text" name="name"><br> <label for="password">パスワード:</label> <input type="text" name="password"> <input type="hidden" name="_method" value="PUT"> <input type="submit" value="送信" /> </form>
・DeleteMapping
<form method="post" action="/1"> <label for="name">名前:</label> <input type="text" name="name"><br> <label for="password">パスワード:</label> <input type="text" name="password"> <input type="hidden" name="_method" value="DELETE"> <input type="submit" value="送信" /> </form>
Java ファイル操作
ファイル操作について調べてみた
・インスタンスの生成
Path path = Paths.get("C:\\test.txt"); System.out.println(path); File file = new File("C:\\test.txt"); Path path = file.toPath(); System.out.println(path);
・パス指定
// 絶対パス Path path = Paths.get("C:\\test.txt"); System.out.println(path); System.out.println(path.isAbsolute()); // true // 相対パス String dir = System.getProperty("user.dir"); System.out.println(dir); Path path = Paths.get("test.txt"); System.out.println(path.toAbsolutePath()); // dir/path System.out.println(path.isAbsolute()); // false // 正規化 Path path = Paths.get("C:\\dir1", "..\\dir2", "test.txt"); System.out.println(path); // C:\dir1\..\dir2\test.txt System.out.println(path.normalize()); // C:\dir2\test.txt
・存在チェック file directory共通
Path path = Paths.get("C:\\dir"); System.out.println(Files.exists(path)); System.out.println(Files.notExists(path));
・更新日時/ファイルサイズの取得
Path path = Paths.get("C:\\test.txt"); System.out.println(Files.getLastModifiedTime(path)); System.out.println(Files.size(path)); // 対象が存在しない場合 NoSuchFileException
・ディレクトリ判定
Path path = Paths.get("C:\\dir"); System.out.println(Files.isDirectory(path)); // ディレクトリであればtrue // 対象が存在しない場合 false
・ディレクトリの作成
Path path = Paths.get("C:\\dir1\\dir2"); Files.createDirectory(path); // 親ディレクトリがない場合 NoSuchFileException Files.createDirectories(path); // 親ディレクトリがない場合 作成 // ディレクトリが既に存在しても例外は起きない
・ファイルの作成
Path path = Paths.get("C:\\dir\\test.txt"); System.out.println(Files.createFile(path)); // 親ディレクトリがない場合 NoSuchFileException // ファイルが既に存在する場合 FileAlreadyExistsException
・ファイルの読み込み
Path path = Paths.get("C:\\dir\\test.txt"); // バイト byte[] bytes = Files.readAllBytes(path); // 文字列 Files.readAllLines(path).stream().forEach(System.out::println); // バッファリング BufferedReader reader = Files.newBufferedReader(path); reader.lines().forEach(System.out::println); // 対象が存在しない場合いずれも NoSuchFileException
・ファイルの書き込み
Path path = Paths.get("C:\\dir\\test.txt"); String line = "line"; Files.write(path, line.getBytes()); // バッファリング BufferedWriter writer = Files.newBufferedWriter(path); writer.write(line, 0, line.length()); writer.newLine(); writer.flush(); // ディレクトリが存在しない場合 NoSuchFileException // ファイルが存在しない場合 ファイルが作成される
・ファイルのコピー
Path src = Paths.get("C:\\dir\\test1.txt"); Path dest = Paths.get("C:\\dir\\test2.txt"); Files.copy(src, dest); // コピー先が存在する場合 FileAlreadyExistsException Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING); // コピー先が存在する場合上書き // コピー元が存在しない場合 NoSuchFileException
・ファイルの移動
Path src = Paths.get("C:\\dir\\test1.txt"); Path dest = Paths.get("C:\\dir\\test2.txt"); Files.move(src, dest); // 移動先が存在する場合 FileAlreadyExistsException Files.move(src, dest, StandardCopyOption.REPLACE_EXISTING); // 移動先が存在する場合上書き // 移動元が存在しない場合 NoSuchFileException
・ファイルの削除
Path path = Paths.get("C:\\dir1\\test1.txt"); Files.delete(path); // 削除対象が存在しない場合 NoSuchFileException Files.deleteIfExists(path); // 削除に成功した場合にtrue返却 削除対象がなくても例外は発生しない
・ファイル検索
Path path = Paths.get("C:\\dir"); // 所定ディレクトリ内の検索 Files.list(path).forEach(System.out::println); // パスがディレクトリでない場合 NotDirectoryException // 再帰検索 Files.walk(path).forEach(System.out::println); // パスがファイルでも動作 // 条件付き検索 Files.find(path, Integer.MAX_VALUE, (i, j) -> i.toString().contains("txt")).forEach(System.out::println); // パスがファイルでも動作 // ディレクトリが存在しない場合 NoSuchFileException
・テンポラリ作成
Path path = Paths.get("C:\\dir"); // 一時ディレクトリ Files.createTempDirectory(path, "tmp_"); // ex tmp_9194118049955059353 // 一時ファイル Files.createTempFile(path, "tmp_", ".csv"); // ex tmp_2871683714486788849.csv // ディレクトリが存在しないやファイルを指定した場合 NoSuchFileException
Java 日時APIについて
日時APIについて調べてみた
・日時クラス
// LocalDateTime タイムゾーンなし System.out.println(LocalDateTime.now()); // ex 2019-04-12T23:41:14.816 // ZonedDateTime タイムゾーン付き System.out.println(ZonedDateTime.now()); // ex 2019-04-12T23:42:07.975+09:00[GMT+09:00] // OffsetDateTime オフセット付き System.out.println(OffsetDateTime.now()); // ex 2019-04-12T23:42:36.609+09:00
・インスタンス生成
// now 現在日時 System.out.println(LocalDateTime.now()); // of System.out.println(LocalDateTime.of(9999, 12, 31, 23, 59, 59, 999999999)); // ex 9999-12-31T23:59:59.999999999
・日時クラス間の変換
// atZone System.out.println(LocalDateTime.now().atZone(ZoneOffset.systemDefault())); // atOffset System.out.println(LocalDateTime.now().atOffset(ZoneOffset.ofHours(9))); // toInstant System.out.println(LocalDateTime.now().toInstant(ZoneOffset.ofHours(9))); // LocalDate System.out.println(LocalDateTime.now().toLocalDate()); // ex 2019-04-12 // LocalTime System.out.println(LocalDateTime.now().toLocalTime()); // 23:45:02.682 // ofInstant Date date = new Date(); System.out.println(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault())); // from System.out.println(LocalDateTime.from(ZonedDateTime.now())); System.out.println(LocalDateTime.from(OffsetDateTime.now()));
・日時クラスのパラメータ
// ZoneId System.out.println(ZoneId.of("Asia/Tokyo")); System.out.println(ZoneId.systemDefault()); // ex GMT+09:00 // ZoneOffset System.out.println(ZoneOffset.ofHours(9)); // isSupported ChronoField フィールドの標準セット System.out.println(LocalDateTime.now().isSupported(ChronoField.YEAR)); System.out.println(LocalDateTime.now().isSupported(ChronoField.MONTH_OF_YEAR)); System.out.println(LocalDateTime.now().isSupported(ChronoField.DAY_OF_MONTH)); System.out.println(LocalDateTime.now().isSupported(ChronoField.HOUR_OF_DAY)); System.out.println(LocalDateTime.now().isSupported(ChronoField.MINUTE_OF_HOUR)); System.out.println(LocalDateTime.now().isSupported(ChronoField.SECOND_OF_MINUTE)); System.out.println(LocalDateTime.now().isSupported(ChronoField.NANO_OF_SECOND)); System.out.println(LocalDateTime.now().isSupported(ChronoField.DAY_OF_WEEK)); // range System.out.println(LocalDateTime.now().range(ChronoField.YEAR)); // -999999999 - 999999999 System.out.println(LocalDateTime.now().range(ChronoField.MONTH_OF_YEAR)); // 1 - 12 System.out.println(LocalDateTime.now().range(ChronoField.DAY_OF_MONTH)); // 1 - 30(31では?) System.out.println(LocalDateTime.now().range(ChronoField.HOUR_OF_DAY)); // 0 - 23 System.out.println(LocalDateTime.now().range(ChronoField.MINUTE_OF_HOUR)); // 0 - 59 System.out.println(LocalDateTime.now().range(ChronoField.SECOND_OF_MINUTE)); // 0 - 59 System.out.println(LocalDateTime.now().range(ChronoField.NANO_OF_SECOND)); // 0 - 999999999 System.out.println(LocalDateTime.now().range(ChronoField.DAY_OF_WEEK)); // 1 - 7 // isSupported ChronoUnit 日時期間の単位の標準セット System.out.println(LocalDateTime.now().isSupported(ChronoUnit.YEARS)); System.out.println(LocalDateTime.now().isSupported(ChronoUnit.MONTHS)); System.out.println(LocalDateTime.now().isSupported(ChronoUnit.DAYS)); System.out.println(LocalDateTime.now().isSupported(ChronoUnit.HOURS)); System.out.println(LocalDateTime.now().isSupported(ChronoUnit.MINUTES)); System.out.println(LocalDateTime.now().isSupported(ChronoUnit.SECONDS)); System.out.println(LocalDateTime.now().isSupported(ChronoUnit.NANOS)); System.out.println(LocalDateTime.now().isSupported(ChronoUnit.WEEKS));
・値の取得
System.out.println(LocalDateTime.now().getYear()); System.out.println(LocalDateTime.now().getMonth());//ex APRIL System.out.println(LocalDateTime.now().getMonthValue()); // 1-12 System.out.println(LocalDateTime.now().getDayOfMonth()); System.out.println(LocalDateTime.now().getHour()); System.out.println(LocalDateTime.now().getMinute()); System.out.println(LocalDateTime.now().getSecond()); System.out.println(LocalDateTime.now().getNano()); System.out.println(LocalDateTime.now().getDayOfWeek()); System.out.println(LocalDateTime.now().getDayOfYear()); // 1-365 // get/getLong フィールド指定 System.out.println(LocalDateTime.now().get(ChronoField.YEAR)); // int System.out.println(LocalDateTime.now().getLong(ChronoField.YEAR)); // long // format フォーマット指定 System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy"))); // truncatedTo 切り捨て指定、指定したunitまで取得 System.out.println(LocalDateTime.now().truncatedTo(ChronoUnit.DAYS)); // until LocalDateTime tomorrow = LocalDateTime.now().plusDays(1); System.out.println(LocalDateTime.now().until(tomorrow, ChronoUnit.DAYS)); // 1
・比較
// compareTo ※エポック比較ではない LocalDateTime now = LocalDateTime.now(); System.out.println(tomorrow.compareTo(now)); // 1 System.out.println(now.compareTo(tomorrow)); // -1 System.out.println(now.compareTo(now)); // 0 // equals ※エポック比較ではない // 属性判定 System.out.println(now.equals(now)); // true System.out.println(tomorrow.equals(now)); // false // isAfter // エポック比較 System.out.println(tomorrow.isAfter(now)); // true System.out.println(now.isAfter(tomorrow)); // false // isBefore // エポック比較 System.out.println(now.isBefore(tomorrow)); // true System.out.println(tomorrow.isBefore(now)); // false // isEqual // エポック比較 System.out.println(now.isEqual(now)); // true System.out.println(tomorrow.isBefore(now)); // false
・編集
// plus System.out.println(LocalDateTime.now().plusDays(1)); // minus System.out.println(LocalDateTime.now().minusDays(1)); // with(set) System.out.println(LocalDateTime.now().withDayOfMonth(1));