java 스프링부트 ( spring boot ) / JPA 활용예제

김동명·2022년 12월 19일
0

스프링부트

목록 보기
19/19
post-thumbnail

프로젝트 설정

application.properties > apllcation.yaml 로 파일 변경

  • application.yaml
server:
  port: 9090


spring:
  datasource:
    url: jdbc:oracle:thin:@localhost:1521:xe
    username: springjpa
    password: springjpa
    driver-class-name: oracle.jdbc.driver.OracleDriver

  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
        show_sql: true
        format_sql: true
      
logging.level:
  org.hibernate.SQL: debug
  org.hibernate.type: trace

서버 구동 확인

  • static > index.html 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	Hello
	<a href="/hello">hello</a>
</body>
</html>

  • 실행

  • cotroller 패키지 생성 > Controller.java 생성
@Controller
public class HelloController {

	@GetMapping("hello")
	public String hello(Model model) {
		model.addAttribute("data", "hello!");
		return "hello";
	}
}

  • templates > hello.html 생성
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<p th:text="'안녕하세요' + ${data}" ></p> 
</body>
</html>

  • hello 클릭시

  • build.gradle 수정
    • implementation 'org.springframework.boot:spring-boot-devtools' 추가 : 서버 재시작 없이도 클래스 변경시 서버가 자동으로 재기동 된다.
...
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-devtools'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.oracle.database.jdbc:ojdbc8'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
...

시작


1. Entity 구조 생성

  • 구현하기

domain 패키지 생성

  • domain 패키지 > Member.java 생성
@Entity
@Getter @Setter
public class Member {
	
	@Id @GeneratedValue
	@Column(name = "MEMBER_ID")
	private Long id;
	private String name;
	
	@Embedded
	private Address address;
	
	@OneToMany(mappedBy = "member")
	private List<Order> orders = new ArrayList<Order>();
}

  • domain 패키지 > Address.java 생성
@Embeddable
@Getter
public class Address {

	private String city;
	private String street;
	private String zipcode;
	
	public Address(String city, String street, String zipcode) {
		super();
		this.city = city;
		this.street = street;
		this.zipcode = zipcode;
	}
	
	// JPA 스펙상 만들어 놓은 기본 생성자
	// new를 통해서 생성하지 못하도록 한다.
	protected Address() {}
}

  • domain 패키지 > Order.java 생성
@Entity
@Getter @Setter
@Table(name = "orders")
public class Order {

	@Id @GeneratedValue
	@Column(name = "order_id")
	private Long id;
	
	@ManyToOne
	@JoinColumn(name = "member_id")
	private Member member;
	private LocalDateTime orderDate;
	
	@OneToMany(mappedBy = "order")
	private List<OrderItem> orderItems = new ArrayList<OrderItem>();
	
	// 주문상태 ( ORDRE , CANCEL ) -> Enum
	@Enumerated(EnumType.STRING)
	private OrderStatus orderStatus;
	
	// 연관관계 메서드
	public void setMember(Member member) {
		this.member = member;
		member.getOrders().add(this);
	}
	
	public void addOrderItem(OrderItem orderItem) {
		orderItems.add(orderItem);
		orderItem.setOrder(this);
	}
}

  • domain 패키지 > OrderStatus.java enum 파일 생성
public enum OrderStatus {
	ORDER, CANCEL
}

  • domain 패키지 > OrderItem.java 생성
@Entity
@Getter @Setter
public class OrderItem {

	@Id @GeneratedValue
	@Column(name = "order_item_id")
	private Long id;
	
	@ManyToOne
	@JoinColumn(name = "order_id")
	private Order order;
	
	@ManyToOne
	@JoinColumn(name = "item_id")
	private Item item;
	
	private int orderPrice;
	private int count;
}

  • domain 패키지 > Item.java 생성
@Entity
@Getter @Setter
public class Item {
	
	@Id @GeneratedValue
	@Column(name = "item_id")
	private Long id;
	
	private String name;
	private int price;
	private int stockQuantity;
}

  • 결과



2. 페이지 구성

  • 코드는 하단에 링크 걸어 두었습니다.

  • 작업 방향

    - controller, web : 웹 계층
    - service : 비즈니스 로직, 트랜잭션 처리
    - repository : JPA를 직접 사용하는 계층, 엔티티 매니저 사용
    - domain : 엔티티가 모여있는 계층, 모든 계층에서 사용 가능

3. Join


  • HelloController.java 수정
...
	@GetMapping("/")
	public String home() {
		return "home";
	}
}

-> 바로 Entity에 추가하지 않고 DTO를 추가해 데이터를 먼저 담아 준다.

  • dto 패키지 생성 > MemberForm.java 생성
@Getter @Setter
public class MemberForm {

	private String name;
	private String city;
	private String street;
	private String zipcode;
}

  • MemberController.java 생성
@Controller
public class MemberController {

	@GetMapping("/members/new")
	public String createForm(Model model) {
		model.addAttribute("memberForm", new MemberForm()); // html에서 thymeleaf를 사용하기 위해 빈 객체를 넘겨준다.
		return "members/createMemberForm";
	}
}

  • createMemberForm.html 생성
		<form role="form" action="/members/new" th:object="${memberForm}" method="post">
			<div class="form-group">
				<label th:for="name">이름</label> 
				<input type="text" class="form-control" th:field="*{name}"  placeholder="이름을 입력하세요" />
			</div>
			<div class="form-group">
				<label th:for="city">도시</label> 
				<input type="text" class="form-control" th:field="*{city}" placeholder="도시를 입력하세요">
			</div>
			<div class="form-group">
				<label th:for="street">거리</label> 
				<input type="text" class="form-control" th:field="*{street}" placeholder="거리를 입력하세요">
			</div>
			<div class="form-group">
				<label th:for="zipcode">우편번호</label> 
				<input type="text" class="form-control" th:field="*{zipcode}" placeholder="우편번호를 입력하세요">
			</div>
			<button type="submit" class="btn btn-primary">Submit</button>
		</form>

3-1. 라이브러리로 validation check 하기

  • build.gradle 수정
    • dependencies 수정
...
	implementation 'org.springframework.boot:spring-boot-devtools'
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	compileOnly 'org.projectlombok:lombok'
...    

  • MemberForm.java 수정
...
	@NotEmpty(message = "회원 이름은 필수입니다.")
	private String name;
...    

  • createMemberForm.html 수정
...
			<div class="form-group">
				<label th:for="name">이름</label> 
				<input type="text" class="form-control" th:field="*{name}"  placeholder="이름을 입력하세요" 
					th:class="${#fields.hasErrors('name')}? 'form-control fieldError' : 'form-control'"/>
				<p th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Incorrect data</p>
			</div>
...

  • MemberController.java 수정
	// BindingResult : @valid 다음에 파라미터로 Binding이 오면, error를 Binding에 담아준다.
	@PostMapping("/members/new")
	public String create(@Valid MemberForm form, BindingResult result) {
		
		// error 발생시
		if( result.hasErrors()) {
			return "members/createMemberForm";
		}
		
		// 정상, service
		
		
		return "redirect:/";
	}

3-2. Repository

  • repository 패키지 생성 > MemberRepository.java 생성
@Repository
@RequiredArgsConstructor
public class MemberRepository {
	
	// 기존에 JpaMain 등에서 사용했던 긴 문장들은 @RequiredArgsConstructor 와
	// private final EntityManager em; 로 모두 대체 가능하다.
	
	// @Autowired : spring boot lib 사용 시 @Autowired를 지원한다.
	@Autowired
	private final EntityManager em;
	
	// 저장
	public void save(Member member) {
		em.persist(member);
	}
	
	// 1건 조회
	public Member findOne( Long id) {
		return em.find(Member.class, id);
	}
	
	// 여러건 조회
	public List<Member> findAll(){
		return em.createQuery("select m from Member m ", Member.class).getResultList();
	}
	
	// 이름으로 조회
	public List<Member> findName(String name){
		return em.createQuery("select m from Member m where m.name = :name", Member.class)
				.setParameter("name", name).getResultList();
	}
	
}



3-3. Service

  • service 패키지 생성 > Memberservice.java 생성
@Service
@RequiredArgsConstructor
public class MemberService {

	private final MemberRepository memberRepository;
	
	// 회원가입
	@Transactional
	public Long Join(Member member) {
		memberRepository.save(member);
		return member.getId();
	}
}



3-4. Controller 수정

  • MemberController.java수정
@Controller
@RequiredArgsConstructor
public class MemberController {

	private final MemberService memberService;
...
		// 정상, service
		Address address = new Address(form.getCity(), form.getStreet(), form.getZipcode());
		Member member = new Member();
		member.setName(form.getName());
		member.setAddress(address);
		
		memberService.Join(member);
		
		return "redirect:/";
	}
...



  • 결과
    • 쿼리문
    • DBeaver



계속


소스코드

profile
코딩공부

0개의 댓글