スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Spring MVC 検索にソート条件を追加する(コントローラ編)

ソート条件の追加にあたり、今回はコントローラを中心に説明していきたいと思う。

なお、ソート条件追加にあたり実現したいことを再掲しておく。
①ソートする項目はリストボックスから選択する(デフォルトはID)
②昇順、降順はラジオボタンで選択する(デフォルトは昇順)
③国際化対応によりリストボックスの内容も日本語・英語で切り替わるようにする
④ページング機能は変わらず使えるようにする

また、ボリュームが多いため、記事を3回に分けて掲載している。
 ①DB編
  ⇒Spring MVC 検索にソート条件を追加する(DBアクセス編)
 ②コントローラ編
  ⇒本記事
 ③JSP編
  ⇒次回掲載予定

◎動作検証にあたっての各バージョンは以下の通り
  • SpringFramework 3.2.8.RELEASE
  • Java 1.7
  • Tomcat 7.0


検索一覧(完成イメージ)
Sort_1.png

1.BookSearchForm.java

package jp.co.sample.book.form;

import java.io.Serializable;

public class BookSearchForm implements Serializable {

private static final long serialVersionUID = 1L;

//検索条件(タイトル)
private String bookName;

//ページ番号
private int pageNo;

//ソート用項目ID
private String sortId;

//ソート順(昇順or降順)
private String sortDirection;

//getter・setter省略
}

検索条件を格納するBookSearchFormクラスであるが、今回、ソート用の項目ID、ソート順を追加している。なお、BookSearchFormクラスはセッションスコープに保持している。セッションに関しては過去の記事を参考にしてほしい。

■セッションに関する過去の記事
Spring MVC @SessionAttributesアノテーションとログアウト時のセッション破棄


2.ListDataForm.java

package jp.co.sample.book.form;

import java.io.Serializable;

public class ListDataForm implements Serializable{

private static final long serialVersionUID = 1L;

private String label;

private String data;

public ListDataForm(String label, String data) {
super();
this.label = label;
this.data = data;
}
//getter・setter省略
}

こちらは今回リストボックス用に追加したJavaBeanとなる。コンストラクタで表示用ラベルと値を設定するようにしている。

3.messages_ja.properties(関連箇所のみ掲載)

bookId=ID
bookName=タイトル
price=価格


4.messages_en.properties(関連箇所のみ掲載)

bookId=Id
bookName=Title
price=Price

リストボックスの表示用ラベルで使用するため掲載しておく。

5.mvc-config.xml(関連箇所のみ掲載)

<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:i18n/messages"/>
</bean>

messageSourceのBean定義となる。

■国際化に関する過去の記事
Spring MVC メッセージの国際化に対応する


6.BookController.java(関連箇所のみ掲載)

package jp.co.sample.book.controller;

import java.util.List;
import jp.co.sample.book.bean.BookPageBean;
import jp.co.sample.book.entity.BookEntity;
import jp.co.sample.book.form.BookSearchForm;
import jp.co.sample.book.form.ListDataForm;
import jp.co.sample.book.service.BookService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
//他のimport文は省略

@Controller
@RequestMapping("/book")
@SessionAttributes("bookSearchForm")
public class BookController {

private static Logger logger = LoggerFactory.getLogger(BookController.class);

@Value("${upload.fileSize}")
private int uploadFileSize;

@Value("${page.records}")
private int pageRecords;

@Autowired
protected MessageSource messageSource;

@Autowired
protected BookService<BookEntity> bookService;

@ModelAttribute
public BookSearchForm initBookSearchForm() {
BookSearchForm form = new BookSearchForm();
form.setBookName("");
form.setSortId("bookId");
form.setSortDirection("asc");
return form;
}

private List<ListDataForm> getSortList() {
List<ListDataForm> list = new ArrayList<ListDataForm>();
MessageSourceAccessor accessor = new MessageSourceAccessor(this.messageSource);
list.add(new ListDataForm(accessor.getMessage("bookId"),"bookId"));
list.add(new ListDataForm(accessor.getMessage("bookName"),"bookName"));
list.add(new ListDataForm(accessor.getMessage("price"),"price"));
return list;
}

@RequestMapping(value="/list/page/{pageNo}", method = RequestMethod.GET)
public String pageList(BookSearchForm bookSearchForm,
BindingResult result,Model model) {

logger.info("pageList start");
int pageNo = bookSearchForm.getPageNo();
if (pageNo < 1) {
result.reject("error.pageNo","Page number error");
return "pageList";
}

PageRequest pageRequest = new PageRequest(pageNo-1, pageRecords);

//Page<BookEntity> page = bookService.findPageByNameLike(pageRequest,bookSearchForm.getBookName());
Page<BookEntity> page = bookService.findPageByNameLike(pageRequest,
bookSearchForm.getBookName(),bookSearchForm.getSortId(),bookSearchForm.getSortDirection());

if (page.getNumberOfElements() ==0) {
result.reject("error.pageRecords","Search error");
return "pageList";
}

BookPageBean bookPageBean = new BookPageBean();
bookPageBean.setTotalPages(page.getTotalPages());
bookPageBean.setCurrentPage(page.getNumber() + 1);
bookPageBean.setTotalRecords(page.getTotalElements());
bookPageBean.setBooks(page.getContent());
bookPageBean.setHasNextPage(page.hasNextPage());
bookPageBean.setHasPreviousPage(page.hasPreviousPage());

//表示レコード数
if (pageNo == 1) {
bookPageBean.setStartRecords(1);
bookPageBean.setEndRecords(page.getNumberOfElements() < pageRecords ? page.getNumberOfElements() : pageRecords);
} else if(pageNo == page.getTotalPages()) {
bookPageBean.setStartRecords((pageNo-1)*pageRecords+1);
bookPageBean.setEndRecords(page.getNumberOfElements() < pageRecords ? (pageNo-1)*pageRecords + page.getNumberOfElements() : pageNo*pageRecords);
} else {
bookPageBean.setStartRecords((pageNo-1)*pageRecords+1 );
bookPageBean.setEndRecords(pageNo*pageRecords);
}

model.addAttribute("bookPage", bookPageBean);
model.addAttribute("sortList",getSortList());

return "pageList";
}
//他のメソッドは省略
}

今回「③国際化対応によりリストボックスの内容も日本語・英語で切り替わるようにする」を実現にあたって、メッセージプロパティファイルより表示用ラベルを取得したい。36,39行目のように以前紹介した@Valueアノテーションを使って、個別に取得する方法もなくはないが、43行目MessageSourceをインジェクションして、メッセージプロパティファイルから値を取得する。

48~55行目はBookSearchFormオブジェクトの生成・初期化処理となる。今回「sortId」の初期値は「bookId」、「sortDirection」の初期値を昇順「asc」とするにあたり、「private String sortId = "bookId";」のようにすることも考えたが、以前紹介した@ModelAttributeアノテーションを使った方が分かりやすいと思い、こちらを採用した。これに伴い、前回まで「private String bookName = "";」としていたが、51行目で「""」を設定するよう変更している。

57~64行目が表示用ラベルと値をリストに設定して返却している処理となる。
59行目にMessageSourceAccessorクラスを使っているが、こちらを使用すると、getMessageメソッドの引数にプロパティファイルのキーを渡せば、該当ロケールの値を取得してくれる便利なクラスだ。43行目のMessageSourceインターフェースにもgetMessageメソッドが用意されているが、ロケールを渡す必要がある。値にはソート用項目IDを設定している。

80行目でソート用項目IDとソート順を追加したfindPageByNameLikeメソッドを呼んでいる。コメント化した79行目が前回まで使用していたメソッドとなる。

109行目「model.addAttribute("sortList",getSortList());」で、ソート用項目IDを格納したリストをJSPから「sortList」で参照できるようにしている。

■@Valueアノテーションに関する過去の記事
Spring MVC プロパティファイルを使用する

■@ModelAttributeアノテーションに関する過去の記事
Spring MVC リクエストパラメータ格納オブジェクトの検証

■ページングに関する過去の記事
Spring MVC ページング機能を実装する(DBアクセス編)
Spring MVC ページング機能を実装する(コントローラ編)
Spring Data JPA JPQLインジェクション対策


一箇所だけ「private String bookName = "";」と初期値を設定していたので、今回@ModelAttributeアノテーションを使って上手く対応できたのではないかと思う。次回に続く。


■過去のSpring関連記事
Spring関連記事 Index

スポンサーサイト

コメントの投稿

非公開コメント

プロフィール

bookmount8

Author:bookmount8
システムエンジニア。サーバーサイドでjavaを扱うことが多い。最近は、ミドルやフロント周りも関心あり。

最新記事
カテゴリ
検索フォーム
最新コメント
月別アーカイブ
これまでの訪問者数
ブロとも申請フォーム

この人とブロともになる

RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。