【初心者向け/ITスクール 69日】個人プロジェクトスタート3日目
はじめに
今日は、Spring BootのWEB MVCの基礎勉強が終わり、簡単なWEBアプリケーションを練習しました。
こちらを元にして、プロジェクトを設計し、作っていきたいと思います。
Domain(not DTO)
DTOはただのDataをViewに転送するためのオブジェクトらしいですが、
今まではDAOを一つに設計したので、その違いが分かりませんでした!
Domainは商品のようにDBに直接入力するためのオブジェクトです!
本来なら、Domainには@Dataをつけば、問題が起こる可能性があるようですが、練習の際には@Dataを付けます。
Domainということを表示するため、@Entityを付けるケースも多いらいしいです。
package hello.itemservice.domain.item;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class Item {
private Long id;
private String itemName;
private Integer price;
private Integer quantity;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
BootStrap
時間を節約するための最適のCSS,JSのライブラリ
Model(DBの値を出したり、入れたり)
@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class BasicItemController {
private final ItemRepository itemRepository;
@GetMapping
public String items(Model model){
List<Item> items = itemRepository.findAll();
model.addAttribute("items",items);
return "basic/items";
}
<tr th:each="item :${items}">
<td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
<td><a href="item.html" th:href="@{/basic/items/${item.id}}" th:text="${item.itemName}">상품명</a></td>
<td th:text="${item.price}">10000</td>
<td th:text="${item.quantity}">10</td>
PathVariable
作成したitemのURI(=商品のid, primary key)をマッピングするため、
@PathVariableを活用します。
@GetMapping("/{itemId}")
public String item(@PathVariable long itemId, Model model){
Item item = itemRepository.findById(itemId);
model.addAttribute("item",item);
return "basic/item";
}
model attribute
情報を追加する時、以前はrequest, responseオブジェクトを活用したのですが、
DTO、Domainなどでデーターを転送する際には@Model attributeを利用することが効果的です。
//@PostMapping("/add")
public String addItemV1(@RequestParam String itemName,
@RequestParam int price,
@RequestParam Integer quantity,
Model model){
Item item = new Item();
item.setItemName(itemName);
item.setPrice(price);
item.setQuantity(quantity);
itemRepository.save(item);
model.addAttribute("item", item);
return "basic/item";
}
//@PostMapping("/add")
public String addItemV2(@ModelAttribute("item") Item item, Model model){
itemRepository.save(item);
//model.addAttribute("item", item); //パラメータのModel省略可能
return "basic/item";
}
//@PostMapping("/add")
public String addItemV3(@ModelAttribute Item item){
//Item -> item
itemRepository.save(item);
//model.addAttribute("item", item); //パラメータのModel省略可能
return "basic/item";
}
//@PostMapping("/add")
public String addItemV4(Item item){
//Item -> item
itemRepository.save(item);
//model.addAttribute("item", item); //パラメータのModel省略可能
return "basic/item";
}
@PostMapping("/add")
public String addItemV5(@ModelAttribute Item item){
//Item -> item
itemRepository.save(item);
//model.addAttribute("item", item); //パラメータのModel省略可能
return "redirect:/basic/items/" + item.getId();
}
redirect attribute
redirect attributeは先ほどの問題を簡単に解決することができます。
URLをエンコーディングする機能とredirect時にrequestにsetattributeをする効果があります。
@PostMapping("/add")
public String addItemV6(@ModelAttribute Item item, RedirectAttributes redirectAttributes){
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/basic/items/{itemId}";
}
<h2 th:if="${param.status}" th:text="저장 완료"></h2>
PRG patterns
POST要請の際に使う、パターンで、必修です!
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId,@ModelAttribute Item item){
itemRepository.update(itemId, item);
return "redirect:/basic/items/{itemId}";
}
message
htmlのテキストは基本的にhard codingになっております。
例えば、100個のタグの中に「商品名」というテキストあると想像します。
その際に、いきなりすべての「商品名」を「商品」に変更することになる場合、
我々はいちいちtemplate engine内の全ての「商品名」を変更しなければならない状況に向かいます。
その際に変数のようにtextを保管する機能がSpring messageで、これによって、色々な国を支援することが可能です。
SpringBootはMessege機能が登録されているので、@beanで何かを登録する必要がありません。
spring.messages.basename=messages
独自の設定を行わない場合、デフォルトで "messages" という名前で登録されます。resources
フォルダーにmessages_en.properties、messages_ko.properties、messages.properties ファイルのみを登録すれば、自動的に認識されます。
hello=안녕
hello.name=안녕 {0}
hello=hello
hello.name=hello {0}
@SpringBootTest
public class MessageSourceTest {
@Autowired
MessageSource ms;
@Test
void helloMessage(){
String result = ms.getMessage("hello", null, null);
assertThat(result).isEqualTo("안녕");
}
@Test
void notFoundMessageCode(){
assertThatThrownBy(() -> ms.getMessage("no-code", null, null))
.isInstanceOf(NoSuchMessageException.class);
}
@Test
void notFoundMessageCodeDefaultMessage(){
String result = ms.getMessage("no-code", null, "기본 메시지", null);
assertThat(result).isEqualTo("기본 메시지");
}
@Test
void argumentMessage(){
String message = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
assertThat(message).isEqualTo("안녕 Spring");
}
@Test
void defaultLang(){
assertThat(ms.getMessage("hello", null, null)).isEqualTo("안녕");
assertThat(ms.getMessage("hello", null, Locale.KOREA)).isEqualTo("안녕");
}
@Test
void enLang(){
assertThat(ms.getMessage("hello", null, Locale.ENGLISH)).isEqualTo("hello");
}
}
messageの適用と国際言語支援
messageの適用
label.item.id=상품 ID
label.item.itemName=상품명
label.item.price=가격
label.item.quantity=수량
<th th:text="#{label.item.id}">ID</th>
<th th:text="#{label.item.itemName}">상품명</th>
<th th:text="#{label.item.price}">가격</th>
<th th:text="#{label.item.quantity}">수량</th>
th:text="#{}" でマッピングすることが可能です。
国際化
label.item.id=Item ID
label.item.itemName=Item Name
label.item.price=price
label.item.quantity=quantity
messages_en.propertiesに追加し、Chromeの設定から言語の優先順位を変更してみますと
Discussion