int i1 = 20; int i2 = 10; // 条件式 ? true : false String s = i1 > i2 ? "i1の方が大きい" : "i2の方が大きい"; System.out.println(s); //i1の方が大きい
thymeleafで使えるページングのメソッド一覧
PageImplクラスのメソッドが使えるようです。
こんな感じでメソッド名そのままで使えるんです。 知らなかったなあ。 どういう仕組みなんだろ。
<p th:text="${page.getSize}"></p> <p th:text="${page.getNumber}"></p> <p th:text="${page.NumberOfElements}"></p> <p th:text="${page.getContent}"></p> <p th:text="${page.hasContent}"></p> <p th:text="${page.isFirst}"></p> <p th:text="${page.nextOrLastPageable}"></p> <p th:text="${page.isLast()}"></p> <p th:text="${page.nextPageable}"></p> <p th:text="${page.getSort}"></p> <p th:text="${page.hasNext}"></p> <p th:text="${page.hasPrevious}"></p> <p th:text="${page.getTotalElements}"></p> <p th:text="${page.getTotalPages}"></p> <p th:text="${page.getPageable}"></p> <p th:text="${page.iterator}"></p> <p th:text="${page.empty}"></p> <p th:text="${page.totalPages}"></p>
@PageableDefaultでページのソートやサイズ指定など
@PageableDefaultでページのソート、サイズ指定、開始ページ指定ができるよ。
かんたんだよ。
@Controller public class AccountController { @Autowired private Service service; @GetMapping("/hello") public String getHello( @PageableDefault(page = 0, size = 2, direction = Direction.DESC, sort = { "id", "name" }) Pageable pageable, Model model) { Page<AccountEntity> accountAll = service.findAllAccount(pageable); model.addAttribute("page", accountAll); model.addAttribute("accountAll", accountAll.getContent()); return "hello"; } }
メソッドーチェーンとは
・決まり
チェーンでつなぐメソッドは自身のオブジェクトの参照を返す必要がある。(return this;)
// toString()もtrim()もstrip()も returnはthis String s = "あいうえお".toString().trim().strip(); // 最後に繋げるメソッドはthisを返さなくても良い char c = "あいうえお".toString().trim().strip().charAt(3); // これと同じ String s2 = "あいうえお".toString(); s2 = s2.trim(); s2 = s2.strip(); ------------------------------------------- public String toString() { return this; } public String trim() { String ret = isLatin1() ? StringLatin1.trim(value) : StringUTF16.trim(value); return ret == null ? this : ret; } public String strip() { String ret = isLatin1() ? StringLatin1.strip(value) : StringUTF16.strip(value); return ret == null ? this : ret; public char charAt(int index) { if (isLatin1()) { return StringLatin1.charAt(value, index); } else { return StringUTF16.charAt(value, index); } }
JPAでの複数ワード検索(動的クエリ・動的SQL・ページング・照合順序)
Googleみたいにスペース区切りでAND検索したくて作ったやつ。
なおかつページングと照合順序(collate)も入れたかった。
例:「東京 銭湯」
参考
・setPrameterの参考
・ページスライスの参考
hibernate - Implementing Pagination using entity manager in spring - Stack Overflow
注意点
この実装だと半角カタカナの「プ」「ゲ」を全角カタカナ「プ」「ゲ」でLIKE検索するとヒットしない。
utf8_unicode_ciの仕様でそうなってしまう。
それも改善するならこっちもどうぞ↓
ポイント
ページスライス
クエリの生成。SOLが全て完成してから生成しないとダメ。
完成してから.setParameter()。
LIKE句をsetParameter()で渡すとこ。
ソース
// ここは検索メソッドとページングメソッドを呼び出してるだけ public Page<SkillEntity> searchBigSkill(String[] keywordArray, Pageable pageable) { List<SkillEntity> skillList = skillRepository.searchBigSkill(keywordArray); return commonService.returnPagedList(pageable, skillList); }
import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; /** * ページスライス * * 受け取ったListをページにスライスする * * @param <E> * @param pageable * @param listOfEntities * @return 1ページ分にスライスされたListをpageableにして返す */ public <E> Page<E> returnPagedList(Pageable pageable, List<E> listOfEntities) { List<E> listToReturn = listOfEntities; if (pageable.isPaged()) { // 1ページのデータ数 int pageSize = pageable.getPageSize(); // 現在のページ番号 int currentPage = pageable.getPageNumber(); // 現在のページの最初の要素番号 int startItem = currentPage * pageSize; // ページに続きがあるかの判定 if (listOfEntities.size() < startItem) { //ページに続きがなければ空のリストを返す listToReturn = Collections.emptyList(); } else { //現在のページの最後の要素番号 int toIndex = Math.min(startItem + pageSize, listOfEntities.size()); // startItemからtoIndexまでのListを作る listToReturn = listOfEntities.subList(startItem, toIndex); } } return new PageImpl<>(listToReturn, pageable, listOfEntities.size()); }
import java.util.ArrayList; import java.util.List; import java.util.Objects; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.springframework.stereotype.Repository; public class Repository { @PersistenceContext private EntityManager em; //複数ワード検索&collate public List<SkillEntity> searchBigSkill(String[] keyWords) { String additionSQL = ""; // 追加するSQL。複数keywordの場合はAND句を追加 for (int i = 1; i < keyWords.length; i++) { additionSQL = additionSQL + " AND(bigName collate utf8_unicode_ci LIKE ?" + i + ")"; } // 元となるSQL String sql = "SELECT * FROM skill WHERE(bigName collate utf8_unicode_ci LIKE ?0)" + additionSQL + " ORDER BY bigID, normalID, smallID"; // クエリの生成。 Query query = em.createNativeQuery(sql, SkillEntity.class); // クエリに検索ワードをセット。 for (int i = 0; i < keyWords.length; i++) { query.setParameter(i, "%" + keyWords[i] + "%"); } @SuppressWarnings("unchecked") List<SkillEntity> skillList = query.getResultList(); return skillList; }
SpringBootでページング
SpringBootでページング
・概要
Page<T>のTにコンテンツをぶち込むと、コンテンツ量に応じてページ分割してくれる。
TはEntityクラスとかFormクラス。
参考
https://qiita.com/tanibuchi12/items/6c8fedbc19bdb277d6f2
https://qiita.com/KevinFQ/items/ca68a3001bae19f92879
公式
非常に詳しい公式
かっこいいページネーション
https://taikii.net/posts/2020/02/spring-boot-kakko-e-pagination/
検索用:ページネーション pageable page
SpringでJPAメモ
SpringでJPA
JPAはDBとのやりとりを簡単にしてくれる。
クエリメソッドでSQLを自動生成。
SpringBoot + JPA + Thymeleafで簡単なCRUDを作る②~画面と機能作成まで~ https://qiita.com/ozaki25/items/3b348874b6db5ab4f04f
DB側で必要な設定は↓ 参考:@GeneratedValueを使って主キーを生成する方法 https://qiita.com/KevinFQ/items/a6d92ec7b32911e50ffe
JPA その3 - JPQL https://qiita.com/opengl-8080/items/e074330b5f4862d9995f
Spring Data JPA でのクエリー実装方法まとめ(@Query()とかの使い方) https://qiita.com/tag1216/items/55742fdb442e5617f727
【Spring Data JPA】自動実装されるメソッドの命名ルール(クエリメソッドってやつの参考) https://qiita.com/shindo_ryo/items/af7d12be264c2cc4b252#orderby
JPQL基本の書き方
table名→Entityクラス名
カラム名→フィールド名
で書く。
さらに、teble名を変数宣言する(ここの場合AdressEntity a)
@Table(name="address") public class AddressEntity { @Column(name="city_code") private Integer cityCode; } --------------------------------- 上記に対応したSQLとJPQL SELECT * FROM address Where city_code = ?; //SQL SELECT a FROM AddressEntity a Where a.cityName = ?1; //JPQL
Entity
- @EntityをつけることでDBのテーブルと紐づく
- @Tableでテーブル名を指定
- @Idを付けた変数がテーブルのプライマリーキーになる
- @GeneratedValueをつけると連番が自動で振られるようになる(MySQL側では主キーにオートインクリメントが必須)
- @Columnでカラム名を指定
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import lombok.Data; @Data @Entity @Table(name="player_table") - public class Player { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="id") private Integer id; @Column(name="name") private String name; @Column(name="number") private Integer number; @Column(name="position") private String position; }
Repository
中身は空でもOK。独自の処理をしたい時はここに追記。
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface PlayerRepository extends JpaRepository<Player, Long> { @PersistenceContext private EntityManager em; /** * 参考 * @return プレイヤー全リスト */ public List<Player> index() { return em.createQuery("select m from Player m ", Player.class).getResultList(); } }
Service
findAll/findOne/save/deleteはJPAのメソッド。 基本的なCRUDはこれでOK. SQL書かなくてよいのでグッド。
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class PlayerService { @Autowired private PlayerRepository playerRepository; public List<Player> findAll() { return playerRepository.findAll(); } public Player findOne(Long id) { return playerRepository.findById(id).orElse(null); } public Player save(Player player) { return playerRepository.save(player); } public void delete(Long id) { playerRepository.deleteById(id); } }