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 |