본문 바로가기
Spring

2024_08_07_수~08_08_목

by 알케니브 2024. 8. 7.

오늘의 코딩순서

(폴더: oBootJpaApi01) + postman 프로그램 사용

↳ postman프로그램이 View 역할을 함

(0807 일지)

  • application.yml 

ORACLE에서 TBL, Sequence, Foreign Key 만들기 (현장 HW 1)

  • Member.class + Team.class

1. API 생성하기

0. 기본 설정 + 1. Test용

  • MemberRepository.interface + JpaMemberRepository.class + MemberService.class + JpaRestApiController.class

2. Bad API 예시

  • JpaRestApiController.class

3. Good API 예시: Easy Version

  • JpaRestApiController.class

4. Good API 예시: 람다 Version

  • JpaRestApiController.class

(0808 일지)

5. Bad API 예시 2

  • Member.class + JpaRestApiController.class + MemberService.class + JpaMemberRepository.class 

6. 5번의 Bad API 예시를 개선한 것

  • JpaRestApiController.class

2. 조회 API  만들기

 단일 Id 조회 API

  • JpaRestApiController.class + MemberService.class + MemberRepository.interface + JpaMemberRepository.class 

3. API  수정하기

  • JpaRestApiController.class + MemberService.class + MemberRepository.interface + JpaMemberRepository.class 


오늘의 코딩 포인트

(폴더: oBootJpaApi01)

(0807 일지)

  • application.yml
server:
  port: 8386
# Oracle Connect
spring:
  datasource:
    driver-class-name: oracle.jdbc.OracleDriver
    url: jdbc:oracle:thin:@localhost:1521/xe
    username: scottJpa
    password: tiger
    
  #JPA Setting
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: create

#logger을 통해 hibernate를 실행하는 SQL      
logging.level:
  org.hibernate.SQL: debug

 

1. API 생성하기

  • Member.class (현장 HW 1)
package com.oracle.oBootJpaApi01.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import lombok.Data;

@Entity
@Data
@Table(name = "member5")
	// 현장 HW 1-1
	// 1. Sequence 
		// 1) 객체 nm : member_seq_gen5
		// 2) DB  nm : member_seq_generator5
		// 3) 초기 -> 1 , 할당 -> 1
@SequenceGenerator(
					name 			= "member_seq_gen5",
					sequenceName 	= "member_seq_generator5",
					initialValue 	= 1,
					allocationSize 	= 1
					)

public class Member {
	// 현장 HW 1-2 : PK를 id로 잡고, sequence는 member_seq_gen5로 잡기
	@Id
	@GeneratedValue(
					strategy 	= GenerationType.SEQUENCE,
					generator 	= "member_seq_gen5"
					)
	
					//	+ nm -> userName
	@Column(name = "member_id")
	private Long	id;
	
	@Column(name = "username")
	private String 	name;
	private Long	sal;

}
  • Team.class (현장 HW 2)
package com.oracle.oBootJpaApi01.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import lombok.Data;

@Entity
@Data
@Table(name = "team5")
	//현장 HW 1-3
	//1. Sequence 
		//1) 객체 nm : team_seq_gen5
		//2) DB  nm : team_seq_generator5
		//3) 초기 -> 1 , 할당 ->1
@SequenceGenerator(
					name 			= "team_seq_gen5",
					sequenceName 	= "team_seq_generator5",
					initialValue 	= 1,
					allocationSize 	= 1
					)		
public class Team {
	// 현장 HW 1-4 : PK를 id로 잡고, sequence는 team_seq_gen5로 잡기
	@Id
	@GeneratedValue(
					strategy 	= GenerationType.SEQUENCE,
					generator 	= "team_seq_gen5"
					)
	
	private Long	teamId;
	//				+ nm -> teamname , 50
	@Column(name = "teamname" , length = 50)
	private String	name;
}

  • MemberRepository.interface
package com.oracle.oBootJpaApi01.repository;

import java.util.List;

import com.oracle.oBootJpaApi01.domain.Member;

public interface MemberRepository {
	Long			save(Member member);
	List<Member>	findAll();

}
  • JpaMemberRepository.class
    Tip)
    • @RequiredArgsConstructor
      • Lombok으로 스프링에서 DI(의존성 주입)의 방법 중에 생성자 주입을 임의의 코드없이 자동으로 설정해주는 어노테이션
      • 지정된 속성들에 대해서만 생성자를 만들어 줌
      • @NoArgsConstructor: 파라미터를 받지 않는 생성자를 만들어 줌
      • @AllArgsConstructor: 모든 필드에 대한 생성자 생성함 ⭐⭐⭐(면접에서 비교질문 들어옴)
package com.oracle.oBootJpaApi01.repository;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.oracle.oBootJpaApi01.domain.Member;

import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
	// 
public class JpaMemberRepository implements MemberRepository {
	private final EntityManager em;
	
// @RequiredArgsConstructor가 아래 세 줄의 기능을 함    
//	@Autowired
//	public JpaMemberRepository(EntityManager em) {
//		this.em = em;
//	}
	
	// 1. 새로운 데이터 입력
	@Override
	public Long save(Member member) {
		System.out.println("JpaMemberRepository save before...");
		em.persist(member);
		return member.getId();
	}

	// 2. 데이터 조회
	@Override
	public List<Member> findAll() {
		List<Member> memberList = em.createQuery("select m from Member m", Member.class)
									.getResultList();
		System.out.println("JpaMemberRepository findAll memberList.size()->"+memberList.size());
		return memberList;
	}

}

 

  • MemberService.class
package com.oracle.oBootJpaApi01.service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.repository.MemberRepository;

import lombok.RequiredArgsConstructor;

@Service
@Transactional
@RequiredArgsConstructor
public class MemberService {
	private final MemberRepository memberRepository;

	// 전체회원 조회 API
	public List<Member> getListAllMember() {
		List<Member> listMember = memberRepository.findAll();
		System.out.println("memberService getListAllMember listMember.size()->"+listMember.size());
		return listMember;
	}
}

1. Test 용

  • JpaRestApiController.class
    Tip) http://localhost:8386/helloText로 접속
    • @RestController
      • @controller에 @ResponseBody를 추가한 어노테이션
    • @Slf4j
      • Simple Logging Facade for Java , 로깅에 대한 추상 레이어를 제공하는 인터페이스의 모음
      • 인터페이스이기 때문에 단독으로 사용이 불가능함
      • private static final Logger logger = LoggerFactory.getLogger(MemberController.class); 와 같은 역할
      • 개발할 때, SLF4J API를 사용하여 로깅 코드를 작성하고, 배포할 때는 바인딩된 Logging Framework가 실제 로깅 코드를 수행함
package com.oracle.oBootJpaApi01.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.oracle.oBootJpaApi01.service.MemberService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RestController
	// @controller에 @ResponseBody를 추가한 어노테이션

@Slf4j
	//private static final Logger logger 
			// = LoggerFactory.getLogger(MemberController.class); 와 같은 역할
@RequiredArgsConstructor
public class JpaRestApiController {
	private final MemberService memberService;
	
	// 0. Test
	@RequestMapping("/helloText")
	public String helloText() {
		System.out.println("JpaRestApiController start...");
		
		String  hello = "안녕";
			// StringConverter
		return hello;
	}
	
	
}

 


2. Bad API 예시

  • JpaRestApiController.class
package com.oracle.oBootJpaApi01.controller;

import java.util.List;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.service.MemberService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RestController
	// @controller와 @ResponseBody를 합한 기능을 가진 어노테이션

@Slf4j
	//private static final Logger logger 
			// = LoggerFactory.getLogger(MemberController.class); 와 같은 역할
@RequiredArgsConstructor
public class JpaRestApiController {
	private final MemberService memberService;
	
	// Bad API 예시
   	//	∵ 외부정보(고객용 정보)뿐 아니라, 내부정보(민감한 보안)까지 보여주는 API이기 때문에
	@GetMapping("/restApi/v1/members")
	public List<Member> membersVer1() {
		System.out.println("JpaRestApiController /restApi/v1/members start...");
		
		List<Member> listMember = memberService.getListAllMember();
		System.out.println("JpaRestApiController /restApi/v1/members listMember.size()->"+listMember.size());
		return listMember;
	}
	
}

 

http://localhost:8386/restApi/v1/members에 접속하면 ↓↓↓


3. Good API 예시: Easy Version

  • JpaRestApiController.class
    Tip)
    • @AllArgsConstructor: 모든 필드에 대한 생성자 생성함, 이 어노테이션을 사용하면 생성자를 만드는 것과 같은 효과를 봄
package com.oracle.oBootJpaApi01.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.service.MemberService;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RestController
	// @controller와 @ResponseBody를 합한 기능을 가진 어노테이션

@Slf4j
	//private static final Logger logger 
			// = LoggerFactory.getLogger(MemberController.class); 와 같은 역할
@RequiredArgsConstructor
public class JpaRestApiController {
	private final MemberService memberService;
	
	// Good API 예시: Easy Version
	// 목표: 이름과 급여를 뺀 정보 전송
	@GetMapping("/restApi/v21/members")
	public Result membersVer21() {
		List<Member> findMembers = memberService.getListAllMember();
		System.out.println("JpaRestApiController /restApi/v21/members findMembers.size()->"+findMembers.size());
		
		List<MemberRtnDto> resultList = new ArrayList<MemberRtnDto>();
		
		// 작성이유: 이전목적=> 반드시 필요한 Data만 보여준다(외부 노출 최대한 금지)
		for(Member member : findMembers) {
			MemberRtnDto memberRtnDto = new MemberRtnDto(member.getName(), member.getSal());
			System.out.println("/restApi/v21/members getName->"+memberRtnDto.getName());
			System.out.println("/restApi/v21/members getSal->"+memberRtnDto.getSal());
			resultList.add(memberRtnDto);
		}
		System.out.println("restApi/v21/members resultList.size()->"+resultList.size());
		return new Result(resultList.size(),resultList);
	}
	
	// Controller에서만 쓴다면 inner 클래스로 만들어 사용한다
	@Data
	@AllArgsConstructor
	class Result<T> {
   		// T: 내가 원하는 데이터가 어떤 형태이든 다 받아줌
		// 즉 유연성 ↑
		private final int	totCount;	// 총 인원수 추가
		private final T		data;
		
	}
	
	@Data
	@AllArgsConstructor		
		// 이 어노테이션을 사용하면 생성자를 만드는 것과 같은 효과를 봄
	class MemberRtnDto{
    	// DTO의 역할을 함	
		// 사용자에게만 보여줄 Data이며, Controller에서만 사용하고 Service 등등에서 사용하지 않음 
		// ∴내장 DTO로 만든다
		private String	name;
		private Long	sal;
	}
}

http://localhost:8386/restApi/v21/members 에 접속하면↓↓↓

 


4. Good API 예시: 람다(화살표표시) Version

  • JpaRestApiController.class
package com.oracle.oBootJpaApi01.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.service.MemberService;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RestController
	// @controller와 @ResponseBody를 합한 기능을 가진 어노테이션

@Slf4j
	//private static final Logger logger 
			// = LoggerFactory.getLogger(MemberController.class); 와 같은 역할
@RequiredArgsConstructor
public class JpaRestApiController {
	private final MemberService memberService;

	// 3. Good API 예시: 람다 Version
	// 목표: 이름과 급여만 전송
	@GetMapping("/restApi/v22/members")
	public Result membersVer22() {
		List<Member> findMembers = memberService.getListAllMember();
		System.out.println("JpaRestApiController restApi/v22/members findmembers.size()->"+findMembers.size());
		
		// Java 8에서 추가한 스트림(Streams)은 람다를 활용할 수 있는 기술 중 하나
		List<MemberRtnDto> memberCollect = 
						findMembers.stream()
								   .map(m->new MemberRtnDto(m.getName(), m.getSal()))
                                   		// ->표시를 람다라고 함
								   .collect(Collectors.toList())
								   ;
        System.out.println("restApi/v22/members memberCollect.size()->"+memberCollect.size());
		return new Result(memberCollect.size(), memberCollect);
	}





}

 

http://localhost:8386/restApi/v22/members에 접속하면 ↓↓↓


(0808 일지)

5. Bad API 예시 2

  • Member.class
    Tip)
    • @NotEmpty
      • null""둘 다 허용하지 않지만, " "(공백)은 허용함
      • 장점: 엔티티에 필요없는 어노테이션이 붙지 않으며, 필요한 데치터에 딱 맞는 데이터 형태로 전달하여 불필요한 검증이 생기지 않음
      • 단점: 전달하려는 데이터마다 DTO를 달리 만들어야 해서 엔티티가 복잡해질 수 있음
        + 전달하는 데이터가 엔티티와 동일하지 않아 비즈니스 로직에 필요없는 추가 정보들이 제공되기도 함
package com.oracle.oBootJpaApi01.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;

@Entity
@Data
@Table(name = "member5")
	// 현장 HW 1-1
	// 1. Sequence 
		// 1) 객체 nm : member_seq_gen5
		// 2) DB  nm : member_seq_generator5
		// 3) 초기 -> 1 , 할당 -> 1
@SequenceGenerator(
					name 			= "member_seq_gen5",
					sequenceName 	= "member_seq_generator5",
					initialValue 	= 1,
					allocationSize 	= 1
					)

public class Member {
	// 현장 HW 1-2 : PK를 id로 잡고, sequence는 member_seq_gen5로 잡기
	@Id
	@GeneratedValue(
					strategy 	= GenerationType.SEQUENCE,
					generator 	= "member_seq_gen5"
					)
	
					//	+ nm -> userName
	@Column(name = "member_id")
	private Long	id;
	// Bad API 2 예시 위해 아래 두 줄 추가
	@NotEmpty
	// nm -> username
	
	@Column(name = "username")
	private String 	name;
	private Long	sal;
	
	// 연관관계 설정
	@ManyToOne
	@JoinColumn(name = "team_id")
	private Team team;
	
	

}
  • JpaRestApiController.class
    Tip)
    • @Valid: 유효성 검증
      • @RequestBody로 들어오는 객체에 대한 제약조건을 검증하도록 지시하는 어노테이션
        이 검증의 세부적인 사항은 객체 안에 정의를 해두어야 함
      • 기본적으로 컨트롤러에서만 동작하며 기본적으로 다른 계층에서는 검증이 되지 않음
      • 다른 계층에서 파라미터를 검증하기 위해서는 @Validated와 결합되어야 함
        ↳ @Validated?
        • @Validated는 JSR 표준 기술이 아니며 Spring 프레임워크에서 제공하는 어노테이션 및 기능
        • 입력 파라미터의 유효성 검증은 컨트롤러에서 최대한 처리하고 넘겨주는 것이 좋지만, 개발을 하다보면 불가피하게 다른 곳에서 파라미터를 검증해야 할 수 있음 => Spring에서는 이를 위해 AOP 기반으로 메소드의 요청을 가로채서 유효성 검증을 진행해주는 @Validated를 제공함
        • 사용방법: 클래스에 @Validated를 붙여주고, 유효성을 검증할 메소드의 파라미터에 @Valid를 붙여주면 유효성 검증이 진행됨
      • 대표적으로 @RequestBody는 Json 메세지를 객체로 변환해주는 작업인 ArgumentResolver의 구현체인  
        RequestResponseBodyMethodProcessor가 처리하며, 
        이 내부에서 @Valid로 시작하는 어노테이션이 있을 경우에 유효성 검사를 진행함
        => 검증에 오류가 있다면 MethodArgumentNotValidException 예외가 발생하게 되고, 
        디스패처 서블릿에 기본으로 등록된 예외 리졸버(Exception Resolver)인 DefaultHandlerExceptionResolver에 의해 400 BadRequest 에러가 발생함
package com.oracle.oBootJpaApi01.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.service.MemberService;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RestController
//@controller에 @ResponseBody를 추가한 어노테이션

@Slf4j
	//private static final Logger logger 
			// = LoggerFactory.getLogger(MemberController.class); 와 같은 역할
@RequiredArgsConstructor
public class JpaRestApiController {
	private final MemberService memberService;
	
	// 5. Bad API 예시 2
	@PostMapping("/restApi/v1/memberSave")
    // @RequestBody : Json(member)으로 온것을  --> Member member Setting
	public CreateMemberResponse savememberV1(@RequestBody @Valid Member member) {
		System.out.println("JpaRestApiController /api/v1/memberSave member.getId()->"+member.getId());
		
		log.info("member.getName()-> {}.", member.getName());
		log.info("member.getSal()-> {}.", member.getSal());
		
		Long id = memberService.saveMember(member);
		return new CreateMemberResponse(id);
	}

	@Data
	static class CreateMemberRequest {
		
		@NotEmpty
		private String	name;
		private Long	sal;
	}
	
	@Data
	@RequiredArgsConstructor	
		// 이 어노테이션을 걸면 아래 주석 세 줄을 생략해도 됨
	class CreateMemberResponse {
		private final Long id;
//		public CreateMemberResponse(Long id) {
//			this.id = id;
//		}
	}

}
  • MemberService.class
package com.oracle.oBootJpaApi01.service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.repository.MemberRepository;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@Service
@Transactional
@RequiredArgsConstructor
public class MemberService {
	private final MemberRepository memberRepository;

	// 전체회원 조회 API
	public List<Member> getListAllMember() {
		List<Member> listMember = memberRepository.findAll();
		System.out.println("memberService getListAllMember listMember.size()->"+listMember.size());
		return listMember;
	}
	
	public Long saveMember(@Valid Member member) {
		System.out.println("MemberService join member.getName()->"+member.getName());
		
		Long id = memberRepository.save(member);
		return id;
	}
}
  • JpaMemberRepository.class 
package com.oracle.oBootJpaApi01.repository;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.oracle.oBootJpaApi01.domain.Member;

import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
	// 
public class JpaMemberRepository implements MemberRepository {
	private final EntityManager em;

// @RequiredArgsConstructor가 아래 세 줄의 기능을 함
//	@Autowired
//	public JpaMemberRepository(EntityManager em) {
//		this.em = em;
//	}
	
	// 1. 새로운 데이터 입력
	@Override
	public Long save(Member member) {
		System.out.println("JpaMemberRepository save before...");
		em.persist(member);
		return member.getId();
	}

	// 2. 데이터 조회
	@Override
	public List<Member> findAll() {
															// 객체 Member
		List<Member> memberList = em.createQuery("select m from Member m", Member.class)
									.getResultList();
		System.out.println("JpaMemberRepository findAll memberList.size()->"+memberList.size());
		return memberList;
	}

}

 

↳ 객체 중심으로 가기 때문에 name이라고 명명함 => 0808강의 10:15부분 보고 추가하기



6. 5번의 Bad API 예시를 개선한 것

목적  : Entity Member member --> 직접 화면이나 API위한 Setting 금지
예시  : @NotEmpty  --> @Column(name = "userName")

  • JpaRestApiController.class
package com.oracle.oBootJpaApi01.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.service.MemberService;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RestController
//@controller에 @ResponseBody를 추가한 어노테이션

@Slf4j
	//private static final Logger logger 
			// = LoggerFactory.getLogger(MemberController.class); 와 같은 역할
@RequiredArgsConstructor
public class JpaRestApiController {
	private final MemberService memberService;
	
	
	// 6. 5번의 Bad API를 개선하는 방법
		// 목적  : Entity Member member --> 화면이나 API를 직접 setting하는 것은 금지
		// 예시  : domain의 Member.class의 @NotEmpty  -->	@Column(name = "userName")
		@PostMapping("/restApi/v2/memberSave")
		// @RequestBody : Json(member)으로 온것을  --> Member member Setting
		public CreateMemberResponse savememberV2(@RequestBody @Valid CreateMemberRequest cMember) {
			System.out.println("JpaRestApiController /api/v2/memberSave cMember.getId()->"+cMember);
			
			log.info("member.getName()-> {}.", cMember.getName());
			log.info("member.getSal()-> {}.", cMember.getSal());
			
			Member member = new Member();
			member.setName(cMember.getName());
			member.setSal(cMember.getSal());
				// 선언 후 cMember를 member로 사용하기
			
			Long id = memberService.saveMember(member);
			return new CreateMemberResponse(id);
		}
	

	@Data
	static class CreateMemberRequest {
		
		@NotEmpty
		private String	name;
		private Long	sal;
	}
	
	@Data
	@RequiredArgsConstructor	
		// 이 어노테이션을 걸면 아래 주석 세 줄을 생략해도 됨
	class CreateMemberResponse {
		private final Long id;
//		public CreateMemberResponse(Long id) {
//			this.id = id;
//		}
	}

}


2. 조회 API  만들기

  • JpaRestApiController.class
    Tip)
    • 멱등: 어떤 명령어를 시행해도 상태값이 변하지 않는 것
package com.oracle.oBootJpaApi01.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.service.MemberService;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RestController
//@controller에 @ResponseBody를 추가한 어노테이션

@Slf4j
	//private static final Logger logger 
			// = LoggerFactory.getLogger(MemberController.class); 와 같은 역할
@RequiredArgsConstructor
public class JpaRestApiController {
	private final MemberService memberService;
	
// 2. API 조회 방법	
	// 단일 Id 조회 API
		// URI 상에서 '{ }' 로 감싸여있는 부분과 동일한 변수명을 사용하는 방법
		// 해당 데이터가 있으면 업데이트를 하기에 
		// PUT요청이 여러번 실행되어도 해당 데이터는 같은 상태이기에 멱등
	 
	@GetMapping("/restApi/v15/members/{id}")
	public Member membersVer15(@PathVariable("id") Long id) {
								// {id}를 id라고 선언하고 사용하겠다
		System.out.println("JpaRestApiController restApi/v15/members id->"+id);
		
		Member findMember = memberService.findByMember(id);
		System.out.println("JpaRestApiController restApi/v15/members findMember->"+findMember);
		
		return findMember;
	}
	
	

}

 

  • MemberService.class
package com.oracle.oBootJpaApi01.service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.repository.MemberRepository;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@Service
@Transactional
@RequiredArgsConstructor
public class MemberService {
	private final MemberRepository memberRepository;
	
	// 2. 단일 Id 조회 API
	public Member findByMember(Long memberId) {
		Member member = memberRepository.findByMember(memberId);
		System.out.println("MemberService findByMember member->"+member);
		return member;
	}
	
}
  • MemberRepository.interface
package com.oracle.oBootJpaApi01.repository;

import java.util.List;

import com.oracle.oBootJpaApi01.domain.Member;

public interface MemberRepository {
	Long			save(Member member);
	List<Member>	findAll();
	Member 			findByMember(Long memberId);

}
  • JpaMemberRepository.class 
package com.oracle.oBootJpaApi01.repository;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.oracle.oBootJpaApi01.domain.Member;

import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
	// 
public class JpaMemberRepository implements MemberRepository {
	private final EntityManager em;

// @RequiredArgsConstructor가 아래 세 줄의 기능을 함
//	@Autowired
//	public JpaMemberRepository(EntityManager em) {
//		this.em = em;
//	}


	// 3. 단일 Id 조회 API
	@Override
	public Member findByMember(Long memberId) {
		Member member = em.find(Member.class, memberId);
		return member;
	}

}

 


3. API  수정하기

  • JpaRestApiController.class 
package com.oracle.oBootJpaApi01.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.service.MemberService;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RestController
//@controller에 @ResponseBody를 추가한 어노테이션

@Slf4j
	//private static final Logger logger 
			// = LoggerFactory.getLogger(MemberController.class); 와 같은 역할
@RequiredArgsConstructor
public class JpaRestApiController {
	private final MemberService memberService;
	
	
// 3. API 수정 방법	
	
	@PutMapping("/restApi/v21/members/{id}")
	public UpdateMemberResponse updateMemberV21(@PathVariable("id") Long id,
    														// PK 입력
												@RequestBody @Valid UpdateMemberRequest uMember) {
		System.out.println("JpaRestApiController updateMemberV21 id->"+id);												
		System.out.println("JpaRestApiController updateMemberV21 uMember->"+uMember);	
		
		memberService.updateMember(id, uMember.getName(), uMember.getSal());
		Member findMember = memberService.findByMember(id);
		return new UpdateMemberResponse (findMember.getId(),findMember.getName(), findMember.getSal() );
	
	}
	
	@Data
	static class UpdateMemberRequest {
    	// 수정할 항목들
		private String	name;
		private Long	sal;
	}
	
	@Data
	@AllArgsConstructor
	class UpdateMemberResponse {
		private Long	id;
		private String	name;
		private Long	sal;
	}


}
  • MemberService.class 
package com.oracle.oBootJpaApi01.service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.repository.MemberRepository;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@Service
@Transactional
@RequiredArgsConstructor
public class MemberService {
	private final MemberRepository memberRepository;

	// 3. API 수정 방법	
	public void updateMember(Long id, String name, Long sal) {
		Member member = new Member();
		member.setId(id);
		member.setName(name);
		member.setSal(sal);
		System.out.println("MemberService updateMember member->"+member);
		
		memberRepository.updateByMember(member);
		return;
		
	}
	
}

 

  • MemberRepository.interface
package com.oracle.oBootJpaApi01.repository;

import java.util.List;

import com.oracle.oBootJpaApi01.domain.Member;

public interface MemberRepository {
	Long			save(Member member);
	List<Member>	findAll();
	Member 			findByMember(Long memberId);
	int 			updateByMember(Member member);

}
  • JpaMemberRepository.class 
package com.oracle.oBootJpaApi01.repository;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.oracle.oBootJpaApi01.domain.Member;

import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
	// 
public class JpaMemberRepository implements MemberRepository {
	private final EntityManager em;

// @RequiredArgsConstructor가 아래 세 줄의 기능을 함
//	@Autowired
//	public JpaMemberRepository(EntityManager em) {
//		this.em = em;
//	}

	// 4. API 수정 방법	
	@Override
	public int updateByMember(Member member) {
		int result = 0;
		Member member3 = em.find(Member.class, member.getId());
		
		if (member3 != null) {
			// member3의 값이 존재할 경우 회원 저장
			member3.setName(member.getName());
			member3.setSal(member.getSal());
			result = 1;
			System.out.println("JpaMemberRepository updateByMember Update...");
		} else {
			// member3의 값이 존재하지 않을 경우 회원 저장X
			result = 0;
			System.out.println("JpaMemberRepository updateByMember No Exist...");
		}
		return result;
		
	}

}

 


질문목록

 


수업교재

 

 


오늘의 숙제

'Spring' 카테고리의 다른 글

2024_08_12_월  (0) 2024.08.12
2024_08_08_목~08_12_월  (0) 2024.08.08
2024_08_06_화~08_07_수  (0) 2024.08.06
2024_08_05_월~08_06_화  (0) 2024.08.05
2024_08_02_금  (0) 2024.08.02