본문 바로가기
Spring

oBootJpaApi01

by SSONG1521 2024. 9. 12.

 



Spring Starter Project oBootJpaApi01
package resources
yml application.yml
server:
  port: 8390
# Oracle Connect
spring:
  datasource:
    driver-class-name: oracle.jdbc.driver.OracleDriver
    url: jdbc:oracle:thin:@172.30.1.54:32768/xe  #docker(mydb)
    # url: jdbc:oracle:thin:@localhost:1521/xe
    # url: jdbc:oracle:thin:@l27.0.0.1:32772/xe  #docker
    # url: jdbc:oracle:thin:@172.30.1.54:32768/xe  #docker
    username: scottJpa
    password: tiger
    
  #Jpa Setting
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
            # @Entity라고 설정되어 있는 것들 만 update, none, create 등등
            # release 할 때에는 none으로 바꿔주어야 한다!!!!
            
logging.level:
  org.hibernate.SQL: debug  #logger를 통해 하이버네이트 실행 SQL
Console
 

 

 

 

 

 

 

 

Spring Starter Project oBootJpaApi01
package com.oracle.oBootJpaApi01
class WebConfig
package com.oracle.oBootJpaApi01;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//CORS는 한 도메인이 도메인 간의 요청을 가진 다른 도메인의 리소스에 액세스할 수 있게 해주는
//보안 메커니즘으로 최신 브라우저에서 구현된 동일 출처 정책 때문에 등장

@Configuration
public class WebConfig implements WebMvcConfigurer {
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		// TODO Auto-generated method stub
//		WebMvcConfigurer.super.addCorsMappings(registry);
		registry.addMapping("/**")
				.allowedOrigins("*")
				.allowedMethods("GET", "POST", "PUT","DELETE")
				.maxAge(3000);
		
	}
}
Console
 

 

 

 

Spring Starter Project oBootJpaApi01
package com.oracle.oBootJpaApi01.controller
class JpaRestApiController
package com.oracle.oBootJpaApi01.controller;

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

import javax.naming.spi.DirStateFactory.Result;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.DeleteMapping;
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.ResponseBody;
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;

//@Controller + @ResponseBody = @RestController
@RestController
//private static final Logger logger = LoggerFactory.getLogger(JpaRestApiController.class);
@Slf4j
@RequiredArgsConstructor
public class JpaRestApiController {
	private final MemberService memberService;
	
	@RequestMapping("/helloText")
	public String helloText() {
		System.out.println("JpaRestApiController Start...");
		String hello = "안녕";
		// 		StringConverter
		return hello;
	}
	
	//Bad Api
	@GetMapping("/restApi/v1/members")
	public List<Member> membersVer1() {
		System.out.println("JpaRestApiController /restApi//v1/members start...");
		//return return되어서 결국에는 listMember에 쌓일 것이다.
		List<Member> listMember = memberService.getListAllMember();
		System.out.println("JpaRestApiController /restApi//v1/members listMember.size() -> "+listMember.size());
		return listMember;
	}
	
	//Good Api Easy Version
	//목표 : 이름 & 급여 만 전송
	@GetMapping("/restApi/v21/members")
	public Result membersVer21() {
		List<Member> fineMembers = memberService.getListAllMember();
		System.out.println("JpaRestApiController restApi/v21/members findMembers.size()-> "+fineMembers.size());
		
		//보내주는 Data의 List를 새로 만들었다. (넘어온 list 값이 과도하기 때문에)
		List<MemberRtnDto> resultList = new ArrayList<MemberRtnDto>();
		
		//이전 목적 : 반드시 필요한 Data만 보여준다. (외부 노출 최대한 금지)
		//향상형 for문을 이용
		for(Member member: fineMembers) {
			//아래 문이 생성자가 없이도 잘 실행되는 이유 -> MemberRtnDto에 @AllArgsConstructor를 걸어주었기 때문에
			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);
	}
	
	//Good API 람다버전
	//목표 : 이름 & 급여 만 전송
	@GetMapping("/restApi/v22/members")
	public Result membersVer22() {
		List<Member> fineMembers = memberService.getListAllMember();
		System.out.println("JpaRestApiController restApi/v22/members findMembers.size()-> "
																	+fineMembers.size());
		// 자바 8에서 추가한 스트림(Streams)은 람다(->)를 활용할 수 있는 기술 중 하나
		//람다 형식 : 화살표 (->) 이용하는 것, stream()을 써 주어야지만 가능
		List<MemberRtnDto> memberCollect = 
				fineMembers.stream()
				//				m이라해도 되고 member라고 해도 된다.
				//				m이 있는 만큼 향상형 for문처럼 돌아가는 것
				//			하지만 map은 list로 수집을 하지는 못한다. 갖고만 있게 하는 로직
						   .map(m->new MemberRtnDto(m.getName(), m.getSal()))
						   //따라서 list로 만들어주는 작업을 해야한다.
						   .collect(Collectors.toList())
						   ;
		
		System.out.println("/restApi/v22/members memberCollect.size()-> "+memberCollect.size());
		//Result 생성자 (@AllArgsConstructor로 인해 생성자 정의 안해도 만들 수 있다.)
		//					 totCount				T data
		return new Result(memberCollect.size(), memberCollect);
	}
	
	@Data
	@AllArgsConstructor
	class Result<T> {
		private final int totCount;	//총 인원수 추가
		//들어오는 Data가 어떤 데이터형이든지 상관없이 T에 잡힌다. (Api의 경우는 T를 쓰는게 좋다.)
		private final T data;
	}
	
	//innerclass를 쓴 이유는 controller에서 값을 보내줄 때 딱 한번 쓰기 때문에
	//만일 이 로직을 service와 dao에도 넘겨준다면 domain(DTO)에 class를 만들어주면 된다.
	@Data
	//Data = getter + setter + Tostring
	//@AllArgsConstructor는 생성자
	@AllArgsConstructor
	class MemberRtnDto {
		//name과 sal만 뽑아서 data 전송해준다.
		//생성자가 없는 이유 -> AllArgsConstructor때문에!!
		//만약 하나를 final로 만들게 되면, @RequiredArgsConstructor로!!
		private String name;
		private Long   sal;
	}
	
	//Ver1. Bad
	@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-> "+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);
		//그냥 보내면 String으로 보내지지만(id), 생성자로 보내기 위해서 새로 만들어서 보내야 Json 으로 보내진다.
		return new CreateMemberResponse(id);
	}
	
	//Ver2.
	// 목적  : Entity Member member --> 직접 화면이나 API위한 Setting 금지
	// 예시  : @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->"+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());
		
		Long id = memberService.saveMember(member);
		return new CreateMemberResponse(id);
	}

	
	/*
	 *   단일 Id 조회 API
	 *   URI 상에서 '{ }' 로 감싸여있는 부분과 동일한 변수명을 사용하는 방법
	 *   해당 데이터가 있으면 업데이트를 하기에 
	 *  GET요청이 여러번 실행되어도 해당 데이터는 같은 상태이기에 멱등
	 */
	//BadApi (이유: 보안문제, 전부 다 보내줘서!!)
	@GetMapping("/restApi/v15/members/{id}")
	public Member membersVer15(@PathVariable("id") Long 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;
	}

	@Data
	static class CreateMemberRequest {
		@NotEmpty
		private String name;
		private Long sal;
	}
	
	@Data
	@RequiredArgsConstructor
	class CreateMemberResponse {
		private final Long id;
		//위에 @RequiredArgsConstructor를 썼기 때문에 생략해도 된다.
//		public CreateMemberResponse(Long id) {
//			this.id = id;
//		}
	}
	
	 @PutMapping("/restApi/v21/members/{id}")
	 public UpdateMemberResponse updateMemberV21(@PathVariable("id") Long id,
			                                     @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() );
	 }

	
//	@PutMapping("/restApi/v21/members/{id}")
//	public UpdateMemberResponse updateMemberV21(@PathVariable("id") Long id,
//												@RequestBody @Valid UpdateMemberRequest uMember) {
//		System.out.println("JpaRestApiController updateMemberV21 start...");
//		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());
//	}
	
	 //수정
	 @DeleteMapping("/restApi/v21/deleteMember/{id}")
	 													//{id}를 id로 놓고 쓰겠다.
	 public CreateMemberResponse deleteMemberV21(@PathVariable("id") Long id) {
		 System.out.println("JpaRestApiController /restApi/v21/deleteMember/{id} start...");
		 System.out.println("JpaRestApiController updateMemberV21 id-> "+id);
		 memberService.deleteMember(id);
		 //JSON 형태로 보내기
		 return new CreateMemberResponse(id);
	 }
	 

	@Data
	static class UpdateMemberRequest {
		private String name;
		private Long sal;
	}
	
	@Data
	@AllArgsConstructor
	class UpdateMemberResponse {
		private Long id;
		private String name;
		private Long sal;
	}
}
Console
 

 

 

 

 

 

Spring Starter Project oBootJpaApi01
package com.oracle.oBootJpaApi01.domain
class Member
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 lombok.Data;

@Entity
@Data
@Table(name = "member5")
//과제
//1. Sequence
//	1) 객체 name : member_seq_gen5
//	2) DB name : member_seq_generator5
// 	3) 초기값 1, 할당 1씩 증가
@SequenceGenerator(
					name = "member_seq_gen5",
					sequenceName = "member_seq_generator5",
					initialValue = 1,
					allocationSize = 1
					)
public class Member {
	
//	2. Id에 PK 잡아주고, member_seq_gen5를 이용해서 , name은 member_id로
	@Id
	@GeneratedValue(
					strategy = GenerationType.SEQUENCE,
					generator = "member_seq_gen5"
					)
	@Column(name = "member_id")
	private Long id;
	
//	3. name의 이름은 userName
	@Column(name = "userName")
	private String name;
	private Long sal;
	
	@ManyToOne
	@JoinColumn(name = "team_id")
	private Team team;
	
}
Console
 

 

 

 

 

 

Spring Starter Project oBootJpaApi01
package com.oracle.oBootJpaApi01.domain
class Team
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")
//과제
//1. Sequence
//	1) 객체 name : team_seq_gen5
//	2) DB name : team_seq_generator5
//	3) 초기값 1, 할당 1씩 증가
@SequenceGenerator(
					name = "team_seq_gen5",
					sequenceName = "team_seq_generator5",
					initialValue = 1,
					allocationSize = 1
					)
public class Team {
//	2. Id에 PK 잡아주고, team_seq_gen5를 이용해서
	@Id
	@GeneratedValue(
					strategy = GenerationType.SEQUENCE,
					generator = "team_seq_gen5"
					)
	//			카멜 표기법 : teamId, myValue
	private Long teamId;
	@Column(name = "teamName", precision = 50)
//	3. name의 이름은 teamName, size 50
	private String name;
}
Console
 

 

 

 

 

 

Spring Starter Project oBootJpaApi01
package com.oracle.oBootJpaApi01.repository
Interface MemberRepository
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);
	void 			deleteById(Long id);
}
Console
 

 

 

 

Spring Starter Project oBootJpaApi01
package com.oracle.oBootJpaApi01.repository
class JpaMemberRepository
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 {
	//JPA는 반드시 Entity Manager를 써야한다. -> 이 이후에 injection이 되어야한다.
	//										생성자 or @RequiredArgsConstructor로!!
	private final EntityManager em;
	
	//final은 반드시 생성자에 들어가야한다. instance를 받아줄 곳이 없다.
	//따라서 final은 생성자를 반드시 넣어주어야 한다.
	// 생성자에 넣어주지 않으면, EntityManager를 구현할 수 가 없다.
	// 하지만 이 대신에 @RequiredArgsConstructor 가 이것과 같은 역할을 한다.
//	@Autowired
//	public JpaMemberRepository(EntityManager em) {
//		this.em = em;
//	}

	@Override
	public Long save(Member member) {
		System.out.println("JpaMemberRepository save before...");
		em.persist(member);
		return member.getId();
	}

	@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;
	}

	@Override
	public Member findByMember(Long memberId) {
		Member member = em.find(Member.class, memberId);
		return member;
	}

	@Override
	public int updateByMember(Member member) {
		int result = 0;
		Member member3 = em.find(Member.class, member.getId());
		if (member3 != null) {
			// 회원 저장
			member3.setName(member.getName());
			member3.setSal(member.getSal());
			result = 1;
			System.out.println("JpaMemberRepository updateByMember Update...");
		} else {
			result = 0;
			System.out.println("JpaMemberRepository updateByMember No Exist..");
		}
		return result;
	}

	@Override
	public void deleteById(Long did) {
		System.out.println("JpaMemberRepository deleteById before...");
		Member member3 = em.find(Member.class, did);
		em.remove(member3);
		return;
		
	}

}
Console
 

 

 

 

Spring Starter Project oBootJpaApi01
package com.oracle.oBootJpaApi01.service
class MemberService
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 {
	//선언한 것에 불과한 얘를 instance화 시켜주기 위해선 @RequiredArgsConstructor로!!
	//아니면 생성자를 따로 만들어주어야 한다.
	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;
	}

	public Member findByMember(Long memberId) {
		Member member = memberRepository.findByMember(memberId);
		System.out.println("MemberService findByMember member-> "+member);
		return member;
	}

	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;
	}

	public void deleteMember(Long id) {
		System.out.println("MemberService deleteMember Start...");
		System.out.println("MemberService deleteMember id -> "+id);
		memberRepository.deleteById(id);
		return;
	}

}
Console
 

 

 

 

Spring Starter Project oBootJpaApi01
package com.oracle.oBootJpaApi01
class  

 

Console
 

 

 

 

'Spring' 카테고리의 다른 글

oBootMyBatis  (0) 2024.09.12
Day63 2024.08.21.수 #코딩일기  (0) 2024.08.21
Day62 2024.08.20.화 #코딩일기  (0) 2024.08.20
Day61 2024.08.19.월 #코딩일기  (0) 2024.08.19
Day60 2024.08.14.수 #코딩일기  (0) 2024.08.14