Spring 애플리케이션 처음부터 끝까지 6) - 애플리케이션 계층 (2) 등록, 편집, 삭제기능

27030 단어 JavaSpringJava

등록기능 생성

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으로 값을 채워주기 위한 메소드다.

마지막으로 makeUpdateModelAccountForm 형태로 된 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로 리다이렉트 된다.

마찬가지로 정상적으로 삭제됨을 알 수 있다.

좋은 웹페이지 즐겨찾기