こんにちは、くまごろーです。
今回は、作成中のアプリに検索機能を付けてみました。
一応、複数ワード対応&半角/全角どちらの空白にも対応するようにしてます。
1 Serviceクラス
今回は、viewファイルで入力された文字列を、Controllerクラス→Serviceクラスへ渡して、Serviceクラスで検索可能な形に整えることにしました。
<Serviceクラス>
public List<PostByNickname> SearchPosts() { String wordsStr = "全角 と 半角 が 混ざった 文字列" //検索ワードの入れ物としてlistを用意 List<String> keyWordsList = new ArrayList<String>(); //検索ワードが1つの場合 if (wordsStr.indexOf(" ") == -1 && wordsStr.indexOf(" ") == -1) { //listにその単語をaddしておしまい keyWordsList.add(wordsStr); //検索ワードが複数の場合 } else { //空白が全角、半角の場合も対応 while (wordsStr.indexOf(" ") != -1 || wordsStr.indexOf(" ") != -1) { //空白の場所を割り出すための変数 int number = 0; int numberHalf = wordsStr.indexOf(" "); int numberFull = wordsStr.indexOf(" "); //一番手前の空白が半角ならnumberHalf、全角ならnumberFullをnumberに代入 if (numberHalf != -1 && numberHalf < numberFull) { number = numberHalf; } else { if (numberFull != -1) { number = numberFull; } else { number = numberHalf; } } //空白の場所で文字列をトリミング String word = wordsStr.substring(0, number); //抜き出した単語をlistにadd keyWordsList.add(word); //抜き出した分の文字列を削除 wordsStr = wordsStr.substring(number + 1); } //最後の検索ワードをlistにaddする keyWordsList.add(wordsStr); } //検索ワードListを配列化 String keyWords[] = keyWordsList.toArray(new String[keyWordsList.size()]); //DBで検索 List<PostByNickname> list = pDao.findPostByWords(keyWords); return list; }
改めて見てみると、本当ナンセンスなコードの組み方してる・・・(-_-;)
if節がマトリョーシカみたいになってるのは、後でなんとかしなきゃなあ。
2 DAOクラス
今回はDAOクラスを使って、JPQLでやりました。理由は、ネイティブクエリではSQL文を動的に変化させられなさそうだったからです。(自分の調べ方が悪かっただけかもしれないが)
<DAOクラス>
//投稿検索(複数ワード対応) @SuppressWarnings("unchecked") @Override public List<PostByNickname> findPostByWords(String words[]) { String qstr1 = "select P.postId, P.postCategory, U.username, U.userNickname, P.postTitle, P.postBody, P.createdAt, P.updatedAt from Post P "; String qstr2 = "left join SiteUser U on P.username = U.username where P.postBody like concat('%', ?1, '%') "; //検索ワードの数に応じて、qstr3の結合回数を変化させる String qstr3 = "and P.postBody like concat('%', ?number, '%')"; //qstr1とsqtr2はあらかじめ結合しておく String qstr = qstr1 + qstr2; //検索ワード数が2以上の場合 if (words.length > 1) { for (int i = 2; i < words.length + 1; i++) { String currentNumber = String.valueOf(i); //SQL文の引数に数字を振る qstr3 = qstr3.replace("number", currentNumber); //SQL文に結合 qstr += qstr3; //SQL文の引数を所定の変数名に戻す qstr3 = qstr3.replace(currentNumber, "number"); } } Query query = em.createQuery(qstr); //検索ワード数に応じて、パラメータをセット for (int i = 0; i < words.length; i++) { query.setParameter(i + 1, words[i]); } List<Object[]> listObj = query.getResultList(); List<PostByNickname> list = listObj.stream().map(PostByNickname::new).collect(Collectors.toList()); return list; }
検索ワード数を「配列.length」メソッドで確認して、その数に応じてSQL文を変化させるようにしました。また、SQL文にセットするパラメータも、for文で番号を振る方式にしました。
なんとなく思い付きでやってみた方法だけど、これでうまくいってしまいました・・・