AccountController.java
에 추가한다.
Form에 단일항목체크를 설정하고 있기 때문에 @Validated
어노테이션과 BindingResult
인터페이스를 사용하여 벨리데이션을 완성한다.
/**
* 등록
* @param accountForm
* @param bindingResult
* @param model
* @param redirectAttributes
* @return
*/
@PostMapping("/insert")
public String insert (@Validated AccountForm accountForm, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes) {
// Form에서 Entity로 리필
Account account = new Account();
account.setId(accountForm.getId());
account.setName(accountForm.getName());
account.setMail(accountForm.getMail());
account.setPassword(accountForm.getPassword());
// 입력 확인
if(!bindingResult.hasErrors()) {
service.insertAccount(account);
redirectAttributes.addFlashAttribute("complete", "등록이 완료되었습니다.");
return "redirect:/account";
} else {
// 오류가 발생하면 목록표시 프로세스 호출
return showList(accountForm, model);
}
}
@Validated
는 request후 서버측에서 데이터를 바인딩 할때 데이터가 유효한지 아닌지 검사해주는 데이터 유효성 검증 어노테이션이다.
BindingResult
는 에러를 담아내는 인터페이스로서, @Validated
어노테이션으로 오류를 내놓았을때 오류에 대한 정보를 저장하는 역할을 한다.
인터페이스가 가지고 있는 hasErrors
의 메소드의 리턴값은 Boolean으로 (true: 오류 / false: 무오류) 오류유무를 확인 할 수 있다.
RedirectAttributes
를 인수로 설정하여, 리다이렉트 시 넘겨주고 싶은 값을 설정한다.
addAttribute
라는 메소드도 가지고 있지만, 쿼리에 표시가 되어야 하므로, String으로 변환이 가능한 원시타입만 넘길 수 있고, 쿼리에도 표시가 되기 때문에 보안에 좋지 않다.
따라서 리다이렉트를 할때 객체를 넘기거나 보안문제가 있다면 세션에 이를 넣고 리다이렉트 페이지에서 해당 세션을 지우는 방법을 쓰는데 이를 FlashAttribute
라고 하며, 이를 저장하는 1회성 세션을 Flash Scope
라고 한다.
따라서 addFlashAttribute
를 실행하면 Flash Scope
라는 스코프가 되어서 한번 리다이렉션 할 때만 유효한 스코프가 된다.
다 작성을 했다면 실행을 해보자
정상적으로 실행이 되는 모습이다.
/**
* 업데이트 보여주기
* @param accountForm
* @param key
* @param model
* @return
*/
@GetMapping("/{key}")
public String showUpdate (AccountForm accountForm, @PathVariable Integer key, Model model) {
// Account 얻기
Optional<Account> accountOptional = service.selectOneByKey(key);
if(accountOptional.isPresent()) {
// AccountForm으로 다시 채우기
Optional<AccountForm> accountFormOptional = accountOptional.map(t -> makeAccountForm(t));
accountForm = accountFormOptional.get();
}
// 업데이트를 위한 모델 만들기
makeUpdateModel (accountForm, model);
return "crud";
}
/**
* 업데이트 실행
* @param accountForm
* @param bindingResult
* @param model
* @param redirectAttributes
* @return
*/
@PostMapping("/update")
public String update (@Validated AccountForm accountForm, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes) {
// AccountForm에서 Account로 다시 채우기
Account account = makeAccount(accountForm);
if (!bindingResult.hasErrors()) {
service.updateAccount(account);
redirectAttributes.addFlashAttribute("complete", "변경이 끝났습니다");
return "redirect:/account/" + account.getKey();
} else {
makeUpdateModel(accountForm, model);
return "crud";
}
}
// 업데이트를 위한 메소드들
private void makeUpdateModel (AccountForm accountForm, Model model) {
model.addAttribute("key", accountForm.getKey());
model.addAttribute("accountForm", accountForm);
model.addAttribute("title", "변경입력양식");
}
private Account makeAccount(AccountForm accountForm) {
Account account = new Account();
account.setKey(accountForm.getKey());
account.setId(accountForm.getId());
account.setName(accountForm.getName());
account.setMail(accountForm.getMail());
account.setPassword(accountForm.getPassword());
return account;
}
private AccountForm makeAccountForm(Account account) {
AccountForm form = new AccountForm();
form.setKey(account.getKey());
form.setId(account.getId());
form.setName(account.getName());
form.setMail(account.getMail());
form.setPassword(account.getPassword());
return form;
}
showUpdate
메소드는 업데이트 화면에서 기존의 값을 보여주기 위한 메소드다. 따라서 get으로 얻어낸 회원 key에 해당하는 엔티티를 가져온다.
@PathVariable
은 파라미터를 받을때 value라는 변수에 따라 /API_NAME/{value}
형식, 즉 Restfull하게 받는 형식을 위한 어노테이션이다.
전에 언급했듯이 findById
의 return 값이 Optional이므로(null 방지) 마찬가지로 accountOptional
의 값은 Optional로 한다.
map(t -> makeAccountForm(t))
의 기술 방법은 람다식을 쓰고 있다. 여기서 map 메소드는 Optional의 메소드로 값이 존재할 때만, 값을 무언가에 넣는다.
여기서 makeAccountForm
메소드는 Account
에서 AccountForm
으로 값을 채워주기 위한 메소드다.
마지막으로 makeUpdateModel
로 AccountForm
형태로 된 Optional형 데이터를 model에 넣게 한다. 이후 crud.html
에 리턴하여 값을 보낸다.
update
메소드는 업데이트란에 수정한 데이터를 업데이트하기 위한 메소드다.
<form method="POST"th:action="${accountForm.newAccount}? @{/account/insert} : @{/account/update}"th:object="${accountForm}">
아래와같이 crud.html
에서 POST방식으로 update
데이터가 오면 캐치하여 메소드를 실행한다.
makeAccount
메소드를 이용하여 AccountForm
로 받은 값을 Account
로 변환시켜준다.
이후 과정이 끝난다음 에러가 없다면 /account/key
값으로 리다이렉트 해준다.
이 또한 실행을 해보자.
잘 실행되고 있음을 알 수 있다.
지정된 회원정보의 key값을 입력했을때 삭제하는 메소드를 만든다.
delete
메소드를 추가해준다.
@PostMapping("/delete")
public String delete (@RequestParam("key") String key, Model model, RedirectAttributes redirectAttributes) {
// 1개 삭제 작업
service.deleteAccountByKey((Integer.parseInt(key)));
redirectAttributes.addFlashAttribute("decomplete", "삭제완료!");
return "redirect:/account";
}
@RequestParam
은 단일 파라미터를 받을때 쓰는 어노테이션이다.
<form method="POST" th:action="@{/account/delete}"> <input type="hidden" name="key" th:value="${obj.key}"> <input type="submit" value="삭제"> </form>
위의 crud.html
에서 name이 key일때의 value를 어노테이션 @RequestParam
으로 받아, String key로 삼아서 메소드를 실행한다.
삭제가 완료 되면 /account
로 리다이렉트 된다.
마찬가지로 정상적으로 삭제됨을 알 수 있다.