diff --git a/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/controller/ToDoController.java b/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/controller/ToDoController.java index 6b20956..cf860d8 100644 --- a/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/controller/ToDoController.java +++ b/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/controller/ToDoController.java @@ -1,16 +1,14 @@ package jp.ac.kobe_u.cs.itspecialist.todoapp.controller; import java.util.List; +import java.util.Objects; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.*; import jp.ac.kobe_u.cs.itspecialist.todoapp.dto.LoginForm; import jp.ac.kobe_u.cs.itspecialist.todoapp.dto.ToDoForm; @@ -54,27 +52,47 @@ public class ToDoController { * ユーザのToDoリストのページ */ @GetMapping("/{mid}/todos") - String showToDoList(@PathVariable String mid, @ModelAttribute(name = "ToDoForm") ToDoForm form, Model model) { + String showToDoList(@PathVariable String mid, + @RequestParam(name="sort_by", required = false) String sortBy, + @RequestParam(name="order", required = false) String order, + @ModelAttribute(name = "ToDoForm") ToDoForm form, Model model) { Member m = mService.getMember(mid); + // デフォルト値を入れておく. + sortBy = getDefault(sortBy, "seq"); + order = getDefault(order, "asc"); + model.addAttribute("member", m); model.addAttribute("ToDoForm", form); - List<ToDo> todos = tService.getToDoList(mid); + List<ToDo> todos = tService.getToDoList(mid, sortBy, order); model.addAttribute("todos", todos); - List<ToDo> dones = tService.getDoneList(mid); + List<ToDo> dones = tService.getDoneList(mid, sortBy, order); model.addAttribute("dones", dones); return "list"; } + private String getDefault(String value, String defaultValue) { + if(value == null || Objects.equals(value.trim(), "")) { + return defaultValue; + } + return value; + } + /** * 全員のToDoリストのページ */ @GetMapping("/{mid}/todos/all") - String showAllToDoList(@PathVariable String mid, Model model) { + String showAllToDoList(@PathVariable String mid, + @RequestParam(name="sort_by", required = false) String sortBy, + @RequestParam(name="order", required = false) String order, + Model model) { Member m = mService.getMember(mid); + // デフォルト値を入れておく. + sortBy = getDefault(sortBy, "seq"); + order = getDefault(order, "asc"); model.addAttribute("member", m); - List<ToDo> todos = tService.getToDoList(); + List<ToDo> todos = tService.getToDoList(sortBy, order); model.addAttribute("todos", todos); - List<ToDo> dones = tService.getDoneList(); + List<ToDo> dones = tService.getDoneList(sortBy, order); model.addAttribute("dones", dones); return "alllist"; } @@ -86,7 +104,7 @@ public class ToDoController { String createToDo(@PathVariable String mid, @Validated @ModelAttribute(name = "ToDoForm") ToDoForm form, BindingResult bindingResult, Model model) { if (bindingResult.hasErrors()) { - return showToDoList(mid, form, model); + return showToDoList(mid, "seq", "asc", form, model); } tService.createToDo(mid, form); return "redirect:/" + mid + "/todos"; diff --git a/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/controller/ToDoRestController.java b/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/controller/ToDoRestController.java index 1862695..79f33d3 100644 --- a/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/controller/ToDoRestController.java +++ b/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/controller/ToDoRestController.java @@ -49,13 +49,13 @@ public class ToDoRestController { /* --- R: ToDoを取得する (リスト) --- */ @GetMapping("/{mid}/todos") List<ToDo> getToDoList(@PathVariable String mid) { - return todoService.getToDoList(mid); + return todoService.getToDoList(mid, "seq", "asc"); } /* --- R: Doneを取得する (リスト) --- */ @GetMapping("/{mid}/dones") List<ToDo> getDoneList(@PathVariable String mid) { - return todoService.getDoneList(mid); + return todoService.getDoneList(mid, "seq", "asc"); } /* --- U: ToDoを完了する --- */ diff --git a/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/repository/ToDoRepository.java b/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/repository/ToDoRepository.java index 4d7767c..109c789 100644 --- a/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/repository/ToDoRepository.java +++ b/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/repository/ToDoRepository.java @@ -13,4 +13,26 @@ public interface ToDoRepository extends CrudRepository<ToDo, Long> { List<ToDo> findByDone(boolean done); List<ToDo> findByMid(String mid); List<ToDo> findByMidAndDone(String mid, boolean done); + + // ソート機能を追加する. + List<ToDo> findByDoneOrderBySeqAsc(boolean done); + List<ToDo> findByDoneOrderBySeqDesc(boolean done); + List<ToDo> findByDoneOrderByTitleAsc(boolean done); + List<ToDo> findByDoneOrderByTitleDesc(boolean done); + List<ToDo> findByDoneOrderByMidAsc(boolean done); + List<ToDo> findByDoneOrderByMidDesc(boolean done); + List<ToDo> findByDoneOrderByCreatedAtAsc(boolean done); + List<ToDo> findByDoneOrderByCreatedAtDesc(boolean done); + List<ToDo> findByDoneOrderByDoneAtAsc(boolean done); + List<ToDo> findByDoneOrderByDoneAtDesc(boolean done); + + List<ToDo> findByMidAndDoneOrderBySeqAsc(String mid, boolean done); + List<ToDo> findByMidAndDoneOrderBySeqDesc(String mid, boolean done); + List<ToDo> findByMidAndDoneOrderByTitleAsc(String mid, boolean done); + List<ToDo> findByMidAndDoneOrderByTitleDesc(String mid, boolean done); + List<ToDo> findByMidAndDoneOrderByCreatedAtAsc(String mid, boolean done); + List<ToDo> findByMidAndDoneOrderByCreatedAtDesc(String mid, boolean done); + List<ToDo> findByMidAndDoneOrderByDoneAtAsc(String mid, boolean done); + List<ToDo> findByMidAndDoneOrderByDoneAtDesc(String mid, boolean done); + } diff --git a/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/service/ToDoService.java b/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/service/ToDoService.java index 57a6371..42bd8f5 100644 --- a/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/service/ToDoService.java +++ b/src/main/java/jp/ac/kobe_u/cs/itspecialist/todoapp/service/ToDoService.java @@ -1,9 +1,14 @@ package jp.ac.kobe_u.cs.itspecialist.todoapp.service; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; import jp.ac.kobe_u.cs.itspecialist.todoapp.dto.ToDoForm; @@ -48,35 +53,73 @@ public class ToDoService { * @param mid * @return */ - public List<ToDo> getToDoList(String mid) { - return tRepo.findByMidAndDone(mid, false); + public List<ToDo> getToDoList(String mid, String sortBy, String order) { + BiFunction<String, Boolean, List<ToDo>> finder = midAndDoneFinder.getOrDefault(Pair.of(sortBy, order), + (memberId, doneFlag) -> tRepo.findByMidAndDone(memberId, doneFlag)); + return finder.apply(mid, false); } /** * あるメンバーのDoneリストを取得する (R) * @param mid * @return */ - public List<ToDo> getDoneList(String mid) { - return tRepo.findByMidAndDone(mid, true); + public List<ToDo> getDoneList(String mid, String sortBy, String order) { + BiFunction<String, Boolean, List<ToDo>> finder = midAndDoneFinder.getOrDefault(Pair.of(sortBy, order), + (memberId, doneFlag) -> tRepo.findByMidAndDone(memberId, doneFlag)); + return finder.apply(mid, true); + } + + private final Map<Pair<String, String>, BiFunction<String, Boolean, List<ToDo>>> midAndDoneFinder = generateMidAndDoneFinder(); + private Map<Pair<String, String>, BiFunction<String, Boolean, List<ToDo>>> generateMidAndDoneFinder() { + Map<Pair<String, String>, BiFunction<String, Boolean, List<ToDo>>> map = new HashMap<>(); + map.put(Pair.of("seq", "asc"), (mid, done) -> tRepo.findByMidAndDoneOrderBySeqAsc(mid, done)); + map.put(Pair.of("seq", "desc"), (mid, done) -> tRepo.findByMidAndDoneOrderBySeqDesc(mid, done)); + map.put(Pair.of("title", "asc"), (mid, done) -> tRepo.findByMidAndDoneOrderByTitleAsc(mid, done)); + map.put(Pair.of("title", "desc"), (mid, done) -> tRepo.findByMidAndDoneOrderByTitleDesc(mid, done)); + map.put(Pair.of("created_at", "asc"), (mid, done) -> tRepo.findByMidAndDoneOrderByCreatedAtAsc(mid, done)); + map.put(Pair.of("created_at", "desc"), (mid, done) -> tRepo.findByMidAndDoneOrderByCreatedAtDesc(mid, done)); + map.put(Pair.of("done_at", "asc"), (mid, done) -> tRepo.findByMidAndDoneOrderByDoneAtAsc(mid, done)); + map.put(Pair.of("done_at", "desc"), (mid, done) -> tRepo.findByMidAndDoneOrderByDoneAtDesc(mid, done)); + return map; } /** * 全員のToDoリストを取得する (R) * @return */ - public List<ToDo> getToDoList() { - return tRepo.findByDone(false); + public List<ToDo> getToDoList(String sortBy, String order) { + Function<Boolean, List<ToDo>> finder = doneFinder.getOrDefault(Pair.of(sortBy, order), + (doneFlag) -> tRepo.findByDone(doneFlag)); + return finder.apply(false); } /** * 全員のDoneリストを取得する (R) * @return */ - public List<ToDo> getDoneList() { - return tRepo.findByDone(true); + public List<ToDo> getDoneList(String sortBy, String order) { + Function<Boolean, List<ToDo>> finder = doneFinder.getOrDefault(Pair.of(sortBy, order), + (doneFlag) -> tRepo.findByDone(doneFlag)); + return finder.apply(true); } + private final Map<Pair<String, String>, Function<Boolean, List<ToDo>>> doneFinder = generateDoneFinder(); + private Map<Pair<String, String>, Function<Boolean, List<ToDo>>> generateDoneFinder() { + Map<Pair<String, String>, Function<Boolean, List<ToDo>>> map = new HashMap<>(); + map.put(Pair.of("seq", "asc"), (doneFlag) -> tRepo.findByDoneOrderBySeqAsc(doneFlag)); + map.put(Pair.of("seq", "desc"), (doneFlag) -> tRepo.findByDoneOrderBySeqDesc(doneFlag)); + map.put(Pair.of("title", "asc"), (doneFlag) -> tRepo.findByDoneOrderByTitleAsc(doneFlag)); + map.put(Pair.of("title", "desc"), (doneFlag) -> tRepo.findByDoneOrderByTitleDesc(doneFlag)); + map.put(Pair.of("mid", "asc"), (doneFlag) -> tRepo.findByDoneOrderByMidAsc(doneFlag)); + map.put(Pair.of("mid", "desc"), (doneFlag) -> tRepo.findByDoneOrderByMidDesc(doneFlag)); + map.put(Pair.of("created_at", "asc"), (doneFlag) -> tRepo.findByDoneOrderByCreatedAtAsc(doneFlag)); + map.put(Pair.of("created_at", "desc"), (doneFlag) -> tRepo.findByDoneOrderByCreatedAtDesc(doneFlag)); + map.put(Pair.of("done_at", "asc"), (doneFlag) -> tRepo.findByDoneOrderByDoneAtAsc(doneFlag)); + map.put(Pair.of("done_at", "desc"), (doneFlag) -> tRepo.findByDoneOrderByDoneAtDesc(doneFlag)); + return map; + } + /** * ToDoを完了する * @param mid 完了者 diff --git a/src/main/resources/templates/alllist.html b/src/main/resources/templates/alllist.html index 8580517..fa723b4 100644 --- a/src/main/resources/templates/alllist.html +++ b/src/main/resources/templates/alllist.html @@ -15,10 +15,26 @@ <h2>ToDo</h2> <table border="1"> <tr> - <th>#</th> - <th>タイトル</th> - <th>作成者</th> - <th>作成日時</th> + <th> + # + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'seq'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'seq'}, order=${'desc'})}">↑</a> + </th> + <th> + タイトル + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'title'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'title'}, order=${'desc'})}">↑</a> + </th> + <th> + 作成者 + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'mid'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'mid'}, order=${'desc'})}">↑</a> + </th> + <th> + 作成日時 + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'created_at'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'created_at'}, order=${'desc'})}">↑</a> + </th> </tr> <tr th:each="todo: ${todos}"> <td>[[${todo.seq}]]</td> @@ -31,10 +47,26 @@ <h2>Done</h2> <table border="1"> <tr> - <th>#</th> - <th>タイトル</th> - <th>作成者</th> - <th>完了日時</th> + <th> + # + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'seq'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'seq'}, order=${'desc'})}">↑</a> + </th> + <th> + タイトル + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'title'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'title'}, order=${'desc'})}">↑</a> + </th> + <th> + 作成者 + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'mid'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'mid'}, order=${'desc'})}">↑</a> + </th> + <th> + 完了日時 + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'done_at'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos/all(mid=${member.mid}, sort_by=${'done_at'}, order=${'desc'})}">↑</a> + </th> </tr> <tr th:each="done: ${dones}"> <td>[[${done.seq}]]</td> diff --git a/src/main/resources/templates/list.html b/src/main/resources/templates/list.html index a2939b9..e9bda05 100644 --- a/src/main/resources/templates/list.html +++ b/src/main/resources/templates/list.html @@ -15,9 +15,21 @@ <h2>ToDo</h2> <table border="1"> <tr> - <th>#</th> - <th>タイトル</th> - <th>作成日時</th> + <th> + # + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'seq'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'seq'}, order=${'desc'})}">↑</a> + </th> + <th> + タイトル + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'title'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'title'}, order=${'desc'})}">↑</a> + </th> + <th> + 作成日時 + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'created_at'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'created_at'}, order=${'desc'})}">↑</a> + </th> <th>コマンド</th> </tr> <tr th:each="todo: ${todos}"> @@ -45,10 +57,26 @@ <h2>Done</h2> <table border="1"> <tr> - <th>#</th> - <th>タイトル</th> - <th>作成日時</th> - <th>完了日時</th> + <th> + # + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'seq'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'seq'}, order=${'desc'})}">↑</a> + </th> + <th> + タイトル + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'title'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'title'}, order=${'desc'})}">↑</a> + </th> + <th> + 作成日時 + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'created_at'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'created_at'}, order=${'desc'})}">↑</a> + </th> + <th> + 完了日時 + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'done_at'}, order=${'asc'})}">↓</a> + <a th:href="@{/{mid}/todos(mid=${member.mid}, sort_by=${'done_at'}, order=${'desc'})}">↑</a> + </th> </tr> <tr th:each="done: ${dones}"> <td>[[${done.seq}]]</td>