Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
Tags
- 리액트 네이티브 시작하기
- 백준 4358번
- 문자열
- 백준
- 머신러닝
- 리액트 네이티브 프로젝트 생성
- 모두의네트워크
- 백준 4358 자바
- 백준 4949번
- 리액트 네이티브
- 깃허브 토큰 인증
- 깃 연동
- 데이터베이스
- 백준 5525번
- 팀플회고
- 지네릭스
- 모두의 네트워크
- SQL
- 자바
- 모두를 위한 딥러닝
- 정리
- 모두를위한딥러닝
- 깃 터미널 연동
- 깃허브 로그인
- 데베
- 딥러닝
- React Native
- 네트워크
- 스터디
- HTTP
Archives
- Today
- Total
솜이의 데브로그
[SpringBoot] 웹 계층 개발(1) 본문
Reference : Inflearn 실전 스프링부트와 JPA 활용1 (김영한님 강의)
홈 컨트롤러 등록
package jpabook.jpashop.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@Slf4j
public class HomeController {
@RequestMapping("/")
public String home(){
log.info("home controller");
return "home";
}
}
로그를 찍을 때
@Slf4j 어노테이션을 사용하면
Logger log = LoggerFactory.getLogger(getClass());
다음과 같이 작성하는 것과 동일하다.
(Log4j 와 비슷한 기능을 제공하는 듯 하다)
위와 같은 코드를 짜면, home.html 을 찾아서 그 화면이 / 을 받았을 때 뿌려지게 된다.
resources/templates/home.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header">
<title>Hello</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div class="container">
<div th:replace="fragments/bodyHeader :: bodyHeader" />
<div class="jumbotron">
<h1>HELLO SHOP</h1>
<p class="lead">회원 기능</p> <p>
<a class="btn btn-lg btn-secondary" href="/members/new">회원 가입</a>
<a class="btn btn-lg btn-secondary" href="/members">회원 목록</a> </p>
<p class="lead">상품 기능</p> <p>
<a class="btn btn-lg btn-dark" href="/items/new">상품 등록</a>
<a class="btn btn-lg btn-dark" href="/items">상품 목록</a> </p>
<p class="lead">주문 기능</p> <p>
<a class="btn btn-lg btn-info" href="/order">상품 주문</a>
<a class="btn btn-lg btn-info" href="/orders">주문 내역</a> </p>
</div>
<div th:replace="fragments/footer :: footer" />
</div> <!-- /container -->
</body>
</html>
위와 같은 화면이 / 에서 뿌려지게 되고, 이 코드에서는 th:replace 를 통해 fragments 폴더 아래 header.html 이라는 파일, bodyHeader.html, footer.html 이라는 파일이 각각 대체하여 화면에 보여진다.
따라서 각각의 파일들을 작성해준다.
getbootstrap.com 을 통해 view 리소스를 등록할 수 있다. 예쁜 화면 가능!
resources/static 아래에 css, js 추가 가능.
회원 등록 (회원 가입)
폼 객체를 사용해 화면 계층과 서비스 계층을 분리해보자.
★ <a> 태그는 Link Page, 즉 일반적으로 페이지 연결을 위해 사용되며 연결 대상이 되는 페이지는 <a> 태그의 href 속성을 통해 정의한다.
회원 등록 컨트롤러 (MemberController)
- @NotEmpty : java 에서 validation을 통해 spring이 validation을 해준다. (값이 비어있는지 확인)
- Model 이란 : model.addAttribute("memberForm", new MemberForm); 으로 작성하면 컨트롤러에서 뷰로 넘어갈 때 데이터를 실어서 넘기게 된다.
- /members/new 를 post로 받은 경우, 멤버를 새로 join 하면서 저장한 후, 재로딩되면 좋지 않기 때문에 redirect해서 home으로 보낸다. (return "redirect:/")
-
- 오류가 난 경우는 BindingResult 를 이용한다. validate 한 뒤 BindingResult가 있는 경우, 오류가 result에 담겨서 코드가 실행된다.
- 따라서 result에 에러가 있다면 return 하도록 작성.
- 위와 같이 작성하면 이런 화면이 나타난다.
- Spring이 에러에 대한 데이터를 찾는데, 에러가 있을 경우 다시 createMemberForm으로 보내고, 그렇게 되면 폼에서 에러가 있는지 확인한다. (BindingResult를 통해 에러를 같이 보내게 됨)
회원 등록 폼 화면
<form role="form" action="/members/new" th:object="${memberForm}"
method="post">
<div class="form-group">
<label th:for="name">이름</label>
<input type="text" th:field="*{name}" class="form-control" placeholder="이름을 입력하세요"
th:class="${#fields.hasErrors('name')}? 'form-control
fieldError' : 'form-control'">
<p th:if="${#fields.hasErrors('name')}"
th:errors="*{name}">Incorrect date</p>
</div>
<div class="form-group">
<label th:for="city">도시</label>
<input type="text" th:field="*{city}" class="form-control" placeholder="도시를 입력하세요"> </div>
<div class="form-group">
<label th:for="street">거리</label>
<input type="text" th:field="*{street}" class="form-control" placeholder="거리를 입력하세요">
</div>
<div class="form-group">
<label th:for="zipcode">우편번호</label>
<input type="text" th:field="*{zipcode}" class="form-control"
placeholder="우편번호를 입력하세요"> </div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
- 컨트롤러에서 memberForm 을 넘겨주었으므로, 화면에서는 해당 객체에 접근할 수 있게 된다.
- th:object -> 해당 객체를 게속 사용하겠다는 뜻.
- th:field="*{name}" 이면 위의 object를 참고하겠다는 뜻.
- 위의 폼 데이터가, <button> submit 을 누르면 /members/new 에 method가 post로 넘어가겠다는 뜻.
- 그럼 이 post로 넘어온 데이터를 받는 내용을 컨트롤러에 작성.
회원 목록 조회
회원 목록 컨트롤러 추가 (MemberController에 추가)
- memberService.findMembers() 하면 JPA에서 JPQL로 짜서 모든 멤버를 조회해줌
- 가져와서 모델에 담아서, 화면에 넘겨줌.
- 즉, 조회한 상품을 뷰에 전달하기 위해 스프링 MVC가 제공하는 모델 (Model) 객체에 보관.
memberList.html
- table로 쭉 돌리면서 뿌림
- tr th : html 태그를 그대로 가져다 쓴다. 즉, 모델에서 넘긴 members list를 그대로 가져와서 바인딩이 된다.
- 루프로 돌리면서 그대로 찍기만 하면 나옴
- 타임리프에서 ? 를 사용하면 null. (null 이 있으면 더이상 진행하지 않음)
폼 객체 사용 vs 엔티티 직접 사용
- 요구사항이 단순한 경우에는 폼 없이 엔티티를 그대로 사용해도 된다.
- 그러나 실무에서는 1:1로 매칭되는 경우가 거의 없기 때문에, 엔티티가 화면을 처리하기 위한 기능이 너무 많아져서 유지보수하기 어려워진다. (엔티티가 화면에 종속적으로 변하게 됨)
- 엔티티는 최대한 순수하게 설계해야함! 즉, 엔티티는 핵심 비즈니스 로직만 가지고 있고, 화면을 위한 로직은 없어야 한다.
- 화면이나 API에 맞는 폼 객체나 DTO를 사용하자.
- API를 만들때는, 이유불문하고 절대 엔티티를 넘기면 안된다!!
- 그렇게 하면 엔티티에 로직을 추가하면 api 스펙이 변화해버림.
- 엔티티는 절대 외부로 노출해서는 안된다.
- 템플릿 엔진에서는 서버사이드에서 돌기 때문에 선택적으로 사용은 가능함.
더 공부해보고 싶은 것
- Slf4j 와 Log4j의 차이가 있는지?
- 타임리프(Thymeleaf)란?
- 계층형 레이아웃 사용해보기 (Hierarchical-style layouts)
- https://www.thymeleaf.org/doc/articles/layouts.html 참고
'dev > Spring Boot' 카테고리의 다른 글
List<>를 변수로 가지고 있을 때 엔티티 업데이트 (0) | 2023.02.04 |
---|---|
[Spring Boot] 웹 계층 개발(2) (0) | 2022.03.31 |
[Spring Boot] 주문 도메인 개발(2) (0) | 2021.12.03 |
[Spring Boot] 주문 도메인 개발(1) (0) | 2021.11.17 |
[Spring Boot] 상품 도메인 개발 (0) | 2021.11.15 |