오늘의 코딩순서
(폴더: 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: 모든 필드에 대한 생성자 생성함 ⭐⭐⭐(면접에서 비교질문 들어옴)
- @RequiredArgsConstructor
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가 실제 로깅 코드를 수행함
- Simple Logging Facade for Java , 로깅에 대한 추상 레이어를 제공하는 인터페이스의 모음
- @RestController
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를 달리 만들어야 해서 엔티티가 복잡해질 수 있음
+ 전달하는 데이터가 엔티티와 동일하지 않아 비즈니스 로직에 필요없는 추가 정보들이 제공되기도 함
- @NotEmpty
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 에러가 발생함
- @RequestBody로 들어오는 객체에 대한 제약조건을 검증하도록 지시하는 어노테이션
- @Valid: 유효성 검증
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 |