ラベル Spring Boot の投稿を表示しています。 すべての投稿を表示
ラベル Spring Boot の投稿を表示しています。 すべての投稿を表示

2017年2月20日月曜日

Spring Boot / Redirect先にオブジェクトを渡す

Spring Bootをいじってました。


RedirectAttributes attributes
Spring BootのGetting StartedでRedirect先にオブジェクトが渡せなくて1時間くらいハマってました。
結論、「RedirectAttributes attributes」で回避
  @PostMapping("/")
  public String checkPersonInfo(
          @Valid
          @ModelAttribute("personForm")
          PersonForm personForm
          ,BindingResult bindingResult
          ,RedirectAttributes attributes) {

    if (bindingResult.hasErrors() ) {
      return "form";
    }
    attributes.addFlashAttribute("personForm", personForm);
    return "redirect:/results";
  }
こちらを参考にさせていただきました。
Qiita SpringMVCでリダイレクト先ページにパラメータを渡す方法

brに閉じスラッシュをどうしてもつけたくない
意外とかったるいThymeleafのtemplatemodeの制約
LegacyHTML5だと単独タグでも閉じスラッシュが必要になる。
そこでtemplatemodeをLegacyHTML5にしましたが、この時はnekoHTMLというライブラリをimportする必要があるみたいです。
Gradleなら
dependencies {
        ...
 compile('net.sourceforge.nekohtml:nekohtml')
}

spring.thymeleaf.cache=falseを指定したのに、更新されない!どういうこと!?
IntelliJ上でgradle::bootRunしていて、spring.thymeleaf.cache=falseを設定の上、
HTMLファイルを更新してもブラウザで変更が確認できず調べる羽目になった。

結果、ファイル更新した後にbuildしないと内容は変わりません。
IntelliJ依存も疑って、Terminalでgradle bootRunしてみましたが、
これもbuildし直さなきゃHTMLファイルの変更すら反映されませんでした。

javax.validation.constraints.*のvalidation message
@NotNull(message="hoge")
以上!!簡単かつ簡潔
Spring Bootいいね!!

エラーページ
デフォルトなら、templates配下にerror.htmlを作ればよし。
エラーコードによる分岐はまた今度やります。
こちらを参考にさせてもらいました:システム開発メモ Spring Boot + Thymeleafでエラー画面をカスタマイズする

2017年2月8日水曜日

Spring Boot / Form周り

Spring BootのForm周りでつまずいたところのメモ
時々intelliJショートカットやGradleのメモ


メモ

Gradle / 拡張プロパティ
ext {
  springBootVersion = '4.0.0.BUILD-SNAPSHOT'
}

Gradle / buildscript
拡張プロパティやレポジトリ、ビルドツールの依存を記述
ライブラリの依存は別の場所
buildscript { 
 ext { // extended property
  springBootVersion = '2.0.0.BUILD-SNAPSHOT'
 }
 repositories {
  mavenCentral()
  maven { url "https://repo.spring.io/snapshot" }
  maven { url "https://repo.spring.io/milestone" }
 }
 dependencies {
  classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
 }
}

Gradle / タスク名は前方一致で特定できれば省略できる
公式参照

Gradle / -x
依存しているタスクを省略
$ gradle --daemon jar 
:compileJava
:processResources
:classes
:jar

BUILD SUCCESSFUL

Total time: 2.217 secs
--
$ gradle --daemon jar -x compileJava
:processResources UP-TO-DATE
:classes
:jar UP-TO-DATE

BUILD SUCCESSFUL

Total time: 0.844 secs


Spring / URLをパラメータとして受け取る
@RequestMapping("/{param}")
public String calc(@PathVariable int param) {

ちなみに、型が違うと下記のように怒られます
Tue Feb 07 22:24:50 JST 2017
There was an unexpected error (type=Bad Request, status=400).
Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "hoge"

少数は問題なかったです。

intelliJ + lombok
Qiita IntelliJ IDEA+GradleでLombokを使う
Enable annotation processing にチェックが覚えられない
Welcome画面で設定すればデフォルト設定できます。
現在Gradleの設定は、 compileOnly "org.projectlombok:lombok:1.16.12" でした

また、ディレクトリのインポート時にbuild.gradleにlombokをdependenciesに記載していなかった場合、
build.gradleに追記後、それをsynchronizedする必要があるみたいでした。
少なくても自分の環境では、synchronizedしないとimport lombok.*;は認識しませんでした。
  • @Data:getter/setter/toString/equals/hashCode
  • @AllArgsConstructor
  • @NoArgsConstructor
うむ、楽だ。

Spring / org.springframework:springloaded
htmlファイルの更新時に、再読み込みをするライブラリ
参照: Qiita Spring Boot + Thymeleaf + Tomcat + Gradleで業務系アプリ 躓いた所6点
buildscript {
 ext {
  springBootVersion = '1.5.1.RELEASE'
 }
 repositories {
  mavenCentral()
 }
 dependencies {
  classpath
                  ("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
  classpath "org.springframework:springloaded"
 }
}
開発効率上げるために入れたほうがいい。

Thymeleaf自体はgradleで
compile "org.springframework.boot:spring-boot-starter-thymeleaf"

またまた、thymeleafのキャッシュは開発時には切っておきます。
[application.properties]
spring.thymeleaf.cache=false

Spring / @Controllerと@RestController
かなり恥ずかしい話ですが、違いがよくわかっていなかった。
@Controllerが付いているクラスのメソッドの戻り値は、HTMLテンプレートのファイル名
@RestControllerがついているクラスのメソッドの戻り値はHTTPレスポンスボディ

参考:Qiita Spring MVCのコントローラでの戻り値いろいろ

Git / **/で再帰的にignore
参考:MindTo01s git-ignoreの設定

Spring / 2.0.0-SNAPSHOTで超絶シンプル@Controllerサンプルを試してみるも。。。
ルーティング(@RequestMapping)がうまくいかず、ファイルがあるのに404が出た
hotload=ONやhtmlcache=OFFの設定があったので、とりあえずミートしてみましたが、変わらず。
1.5.1.RELEASEで同じコードを試したら、問題なくルーティングできた。
無駄に時間食ったわ。。。

Spring / ModelとModelAndView
Modelはセッションの属性値を持つだけ。
ビューのファイル名は別途メッソドの文字列返り値として渡す。

一方、ModelAndViewはセッションの属性値に加え、viewNameとしてビューのファイル名をもつ。
// Model
@RequestMapping("/{num}")
public String index(@PathVariable int num, Model model) {
  model.addAttribute("msg", "arg: " +num);
return "index"; // index.htmlを開く

// ModelAndView
public ModelAndView index(@PathVariable int num, ModelAndView modelAndView) {
  modelAndView.addObject("msg", "total: " + res);
  modelAndView.setViewName("index");
return modelAndView; // index.htmlを開く

IntelliJ w/Mac 1行消す
Command + delete
Qiita 忙しい人のためのIntelliJ IDEAショートカット集(´-`)

Command + dかと思ったんですが、逆に1行増えました。。。。Duplicateっすね。

Spring / フォームの値受け取り
@RequestParam("form_name") Type var_name
public ModelAndView submit(@RequestParam("name") String name , ModelAndView modelAndView) {

forwardとredirect
forwardはURLは元のまま、
redirectはURLも遷移後のものとなります。
Modelの場合
return "forward:/";

ModelAndViewの場合
return modelAndView;

2017年2月7日火曜日

Spring Boot / JPAとか

Spring BootのJPA周りとかでつまずいたところのメモ


メモ

JPA /JPQLのつまずきポイント
@QueryのFrom句は、ドメインクラスの@Table(name=xxx)の指定とは関係がなく、
ドメインクラス名を指定する

****
具体的には、
ドメインクラスでこう指定し、
@Table(name = "customers")

リポジトリのJPAインターフェースを下記のように設定
public interface CustomerRepository
 extends JpaRepository {
    @Query("SELECT x FROM Customer x ORDER BY x.firstName, x.lastName")
    List findAllOrderByName();

}
customersだとmappingできないと怒られる。
ドキュメントをちゃんと読もう

RequestMappingの設定確認
@RestControllerをつけたクラスに、
対応した@RequestMappingが付与する

起動時の確認としては、ログにMapped "xxx" onto ....と出力されるかを確認する
Looking for @ControllerAdvice: 
 org.springframework.boot.context.embedded.
 AnnotationConfigEmbeddedWebApplicationContext@243c4f91
Mapped "{[/api/customers],methods=[GET]}" 
 onto java.util.List 
 com.example.api.CustomerRestController.getCustomers()
...

SQL / Primary key制約の解除
> ALTER TABLE table_name DROP CONSTRAINT primary_key_name ;

JPA / Pagingとsort
Mapping(Controller)
    @GetMapping
    Page<Customer&t; getCustomers(@PageableDefault Pageable pageable) {
        Page customers = customerService.findAll(pageable);
        return customers;
    }
Service
    public Page<Customer> findAll(Pageable pageable) {
        return customerRepository.findAll(pageable);
    }
Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer&t; {
    @Query("SELECT x FROM Customer x ORDER BY x.firstName, x.lastName")
    Page<Customer&t; findAllOrderByName(Pageable pagealbe);
}
URLパラメータで表示数を変化できる
http://localhost:8080/project?page=1&size=3
これ面白い。ちょうど検索数が多い場合の画面を実装どうしようと考えていたとこ。
Pageの内容だとこんな感じのJSON
{"content":[{"id":1,"firstName":"Hanamichi","lastName":"Sakuragi"},
{"id":2,"firstName":"Kaede","lastName":"Rukawa"},
{"id":3,"firstName":"Sho","lastName":"Sato"}],
"last":false,
"totalElements":5,
"totalPages":2,
"size":3,
"number":0,
"numberOfElements":3,
"first":true,"
sort":null}


Spring / 開発時にHTMLのキャッシュを無効化する
デフォルトはパフォーマンス向上のため、HTMLはキャッシュされる設定です。
そのため、HTMLキャッシュを開発時に無効化すると効率的にHTMLファイルの変更を確認できます。

方法は2通り
  1. application.propertiesで設定する
  2. Spring Dev Toolsを使用する
Spring Dev Tools はgradleならbuild.gradleのdependencyに加えておくだけ。