본문 바로가기
Spring

2024_08_05_월~08_06_화

by 알케니브 2024. 8. 5.

오늘의 코딩순서

1. Jar 방식 배포방법

2. (폴더: oBootBoardWarPorn) => gradle이 아닌, Maven 방식으로 만들기

메인페이지 http://localhost:8583/list

배포페이지 http://localhost:8181/oBootBoardWarporm/list

 

3. Lombok 설치

4. (폴더: oBootJpa01) 

메인페이지 http://localhost:8384/list

 

0. 기본 설정

  • application.yml(create, update, none) + scottJpa 계정 만들기

1.신규생성

  • Member.class(getter and setter 버전, 어노테이션 버전) + MemberRepository.interface + JpaMemberRepository.class + MemberService.class + MemberController.class
    + index.html + createMemberForm.html

2. List 조회

  • memberList.html + MemberController.class + MemberService.class + JpaMemberRepository.class

3. 회원이름 검색

  • memberList.html + MemberController.class + MemberService.class + JpaMemberRepository.class

 


오늘의 코딩 포인트

1. Jar 방식 배포방법==> 테스트 할때는 CMD는 키고, STS는 꺼놔야함

1. cd C:\Spring\springSrc17\oBootHello (원하는 폴더 경로 주소)타이핑해서 경로 변경

2. gradlew build 타이핑하여 Jar로 배포하기, BUILD SUCCESSFUL 확인

 

3. 원하는 소스의 build 내의 lib있는 주소 타이핑(C:\Spring\springSrc17\oBootHello\build\libs>)해서 경로 변경

4. >dir 타이핑하여 경로변경

5.C:\Spring\springSrc17\oBootHello\build\libs 뒤에 java -jar oBootHello-version.1.0.jar(위에 나온 배포주소) 적용하여 만들기

 

6. http://localhost:8381/ 접속하면 탐캣 서버와 jar가 포함된 주소로 이동되어 배포가 가능해짐 

7. 같은 방법으로 oBootBoard폴더를 배포해보려고 하면 서버 접속이 불가능함 ==> JSP는 Jar로 배포가 어렵기 때문


(0805, 0806 이틀에 걸쳐서 수업함)

2. (폴더: oBootBoardWarPorm) ==>  Maven 형식으로 만들어서 myBatis와 연계하기

Maven 는 pom.xml로 설정

  • SpringConfig.class ==> com.oracle.oBootBoardWarPorm패키지에 넣기
package com.oracle.oBootBoardWarporm;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.oracle.oBootBoardWarporm.dao.BDao;
import com.oracle.oBootBoardWarporm.dao.JdbcDao;


@Configuration
public class SpringConfig {
	private final DataSource dataSource;
	public SpringConfig(DataSource dataSource) {
		 this.dataSource = dataSource;
	}
	
	@Bean
	public BDao jdbcDao() {
		return new JdbcDao(dataSource);
		//return new MemoryMemberRepository();
	}

}
  • pom.xml ==> dependency 부분에 jstl 추가하고, 그래도 오류나면 맨 윗줄의 https를 http로 고치기
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.3.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.oracle</groupId>
	<artifactId>oBootBoardWarporm</artifactId>
	<version>version.1.0</version>
	<packaging>war</packaging>
	<name>oBootBoardWarporm</name>
	<description>oBootBoardWarporm project for Spring Boot</description>
	<url/>
	<licenses>
		<license/>
	</licenses>
	<developers>
		<developer/>
	</developers>
	<scm>
		<connection/>
		<developerConnection/>
		<tag/>
		<url/>
	</scm>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.oracle.database.jdbc</groupId>
			<artifactId>ojdbc11</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		
				<!-- jstl -->
		<!-- https://mvnrepository.com/artifact/jakarta.servlet.jsp.jstl/jakarta.servlet.jsp.jstl-api -->
		<dependency>
			<groupId>jakarta.servlet.jsp.jstl</groupId>
			<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
			<version>3.0.0</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
		<dependency>
			<groupId>jakarta.servlet</groupId>
			<artifactId>jakarta.servlet-api</artifactId>
			<version>6.0.0</version>
			<scope>provided</scope>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.glassfish.web/jakarta.servlet.jsp.jstl -->
		<dependency>
			<groupId>org.glassfish.web</groupId>
			<artifactId>jakarta.servlet.jsp.jstl</artifactId>
			<version>3.0.1</version>
		</dependency>
		
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<scope>provided</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

 

  • war로 배포하기

1. war export하기

 

2. tomcat 폴더 안에 war파일 복붙

 

3. 서비스 설정에 들어가 tomcat 중지 후 다시 시작하기

 

 

4. http://localhost:8181/oBootBoardWarporm/list 로 접속

yml 파일에서 설치한 내장포트번호(8583)이 아닌, tomcat 서버의 포트 번호( 8181 )를 넣어야함

∵ Maven의 특성상 war로 배포해야하며, 이래야 com.oracle.oBootBoardWarporm 패키지의 context가 가동한다


(0805 일지)

3. Lombok 설치

lombok.jar
1.92MB

1. cmd에 cd 타이핑하고 spring 위치 주소 복붙

2. dir 타이핑

 

3. java -jar lombok.jar 타이핑해서 lombok 설치 시작

4. sts 폴더의 SpringToolSuite4.exe선택한 뒤 install하기

 


(0805 일지)

4. (폴더: oBootJpa01) 

 

1)  신규생성

==> request.getparemeter 할 필요없이, DTO와 Entity 방식으로 곧장 삽입하는 방법

 

  • application.yml ==> create
    Tip)
    • Database 언어의 종류: DDL, DML, DCL
      1. DDL
        • 데이터 정의어로, RDBMS 내 데이터 관리를 위해 테이블을 포함한 여러 객체를 생성, 수정, 삭제하는 명령어
        • 예시로는 Create table와 Alter table가 있음
      2. DML
        1. 데이터 조작어, 최초 사용자이며 RDBMS 내 테이블의 데이터를 저장, 수정, 삭제하는 명령어
        2. 예시로는 Select, Insert, Delete, Update가 있음
      3. DCL은 데이터 사용 권한과 관련된 명령어이며, 데이터베이스의 규정이나 기법을 정의하고 제어하는 언어이다.
        예시로는 Grant와 Revoke가 있다.
server:
  port: 8384
# Oracle Connect
spring:
  datasource:
    driver-class-name: oracle.jdbc.OracleDriver
    url: jdbc:oracle:thin:@localhost:1521/xe
    username: scott
    password: tiger
    
  #JPA Setting
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: create

 

  • application.yml ==> update
    Tip)
    기존의 데이터를 삭제하지 않고 업데이트 및 갱신하는 법
server:
  port: 8384
# Oracle Connect
spring:
  datasource:
    driver-class-name: oracle.jdbc.OracleDriver
    url: jdbc:oracle:thin:@localhost:1521/xe
    username: scott
    password: tiger
    
  #JPA Setting
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
  • application.yml ==> none
server:
  port: 8384
# Oracle Connect
spring:
  datasource:
    driver-class-name: oracle.jdbc.OracleDriver
    url: jdbc:oracle:thin:@localhost:1521/xe
    username: scott
    password: tiger
    
  #JPA Setting
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: none
  • scottJpa 계정 만들기
Create user scottJpa IDENTIFIED BY tiger;
GRANT DBA to scottJpa;

  • Member.class (Source로 Getter and Setter 추가한 버전) => run as 할때 Spring boot 로 run as 하기
    Tip) @Id는 annotation이 아닌 jakarta로 import하기
    이 로직으로 scottJpa TBL에 Member TBL 만들수 있음
    • @Entity ⭐
      • @Entity가 붙은 클래스는 JPA  엔티티임을 나타내며, 이 클래스는 데이터베이스 테이블에 매핑되어 JPA를 통해 데이터베이스 조작이 가능해짐
      • 데이터베이스 테이블 매핑: 엔티티 클래스는 데이터베이스 테이블의 행(row) 하나를 나타내며, 클래스의 각 필드는 테이블의 열(column)에 매핑됨
      • JPA는 리플렉션을 사용하여 엔티티 인스턴스를 생성하기 때문에, 매개변수가 없는 기본 생성자가 필요함
      • 엔티티 클래스는 주로 Serializable 인터페이스를 구현하여 직렬화할 수 있어야 함
      • final 클래스, enum, interface, inner class 에는 사용할 수 없음
      • 필드에 직접 접근하는 방식과 getter/setter 메서드를 통해 접근하는 방식이 있으며, JPA 설정에 따라 적절한 접근 방식을 사용해야 함

        1.  
    • @Id
      • 기본키(PK)를 지정하는 어노테이션
      • id 필드를 지정된 JPA 엔티티의 기본 키로 설정함
      • 기본타입, 기본 래퍼 유형, String, java.util.Date, java.sql.Date, java.math.BigDecimal, java.math.BigInteger 중 하나여야 함
      • @Column 어노테이션을 지정하지 않으면 열 이름은 기본 키 속성 또는 필드의 이름으로 가정함
      • @GeneratedValue 없이 @Id 어노테이션만 사용한다면 직접 할당이 됨
        즉, persist() 메서드를 호출하기 전에 애플리케이션에서 직접 실별자 값을 할당해야 하며, 식별자 값이 없을 경우 에러를 발생시킴
    • @Table
      • 데이터베이스에 키 생성 전용 테이블을 하나 만들고 이를 사용하여 기본키를 생성함
      • 기본적으로 엔티티 클래스의 이름은 데이터베이스 테이블의 이름으로 사용되지만, @Table 어노테이션을 사용하여 테이블 이름을 명시적으로 지정할 수 있음
      • 엔티티와 매핑할 테이블을 지정하며, 생략시 매핑한 엔티티 이름을 테이블 이름으로 사용
      • 속성
        1. Name : 매핑할 테이블 이름 (default. 엔티티 이름 사용)
        2. Catalog : catalog 기능이 있는 DB에서 catalog 를 매핑 (default. DB 명)
        3. Schema : schema 기능이 있는 DB에서 schema를 매핑
        4. uniqueConstraints : DDL 생성 시 유니크 제약조건을 만듦
          스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용
    • @GeneratedValue: 기본 키의 자동 생성 전략을 지정
    • @Column: 필드를 데이터베이스 열과 매핑하며, 열의 이름, 길이, 고유성 등의 속성을 지정할 수 있음

+++ @Entity와 DTO의 차이점

종류 @Entity DTO (Data Transfer Object)
이점 엔티티와 DTO를 분리함으로써 시스템의 유연성과 보안성을 높일 수 있음
목적 데이터베이스와 직접적인 상호작용을 위해 사용됨

즉, 데이터베이스의 테이블 구조와 1:1로 매핑되어 데이터베이스의 데이터를 객체로 변환하고, 객체의 데이터를 데이터베이스에 저장하는 역할을 함
1. 계층 간 데이터 전송을 목적으로 사용됨
일반적으로 컨트롤러에서 서비스나 서비스에서 프론트엔드로 데이터를 전달할 때 사용함

2.  데이터 캡슐화: 클라이언트에 불필요한 내부 구현을 숨기고 필요한 데이터만 노출하여 보안과 효율성을 높
데이터베이스 연관성 직접적 (영속성)
↳ 영속성 컨텍스트: @Entity 객체는 JPA의 영속성 컨텍스트에 의해 관리되며, 엔티티 매니저를 통해 CRUD 작업을 수행
없음 (비영속성)
DTO는 데이터베이스와 직접적인 연관이 없으며, 단순히 데이터를 운반하는 역할만 함
포함 데이터 데이터베이스 테이블 전체 필요한 데이터만 포함하므로, 엔티티와는 다르게 데이터의 일부분만을 포함할 수 있음
관계 매핑 가능
↳ 엔티티 클래스는 다른 엔티티와의 관계(예: @OneToMany, @ManyToOne)를 정의할 수 있음
없음
상태 변화 추적 JPA에 의해 엔티티 객체의 상태 변화를 추적하여 데이터베이스와 동기화함 수동으로 관리
변환 필요성 없음 엔티티와 DTO 간 변환 필요함
일반적으로 서비스 계층에서 엔티티를 DTO로 변환하거나 그 반대로 변환하는 로직을 작성함
     
     

@ID는 jakarta로

↳ @Table를 입력하면 TBL을 자유자재로 조종할수 있음

 

package com.oracle.oBootJpa01.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "member1")
public class Member {
		@Id
		private Long	id;
		private String	name;
		
		public Long getId() {
			return id;
		}
		public void setId(Long id) {
			this.id = id;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		
		
		
}

 

  • Member.class (@Getter, @Setter로 추가한 버전)
    ==> 어노테이션으로 걸면 source로 getter and setter을 추가할 필요가 없음
package com.oracle.oBootJpa01.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;

@Entity
@Table(name = "member2")
@Getter
@Setter
public class Member {
		@Id
		private Long	id;
		private String	name;
		
//		public Long getId() {
//			return id;
//		}
//		public void setId(Long id) {
//			this.id = id;
//		}
//		public String getName() {
//			return name;
//		}
//		public void setName(String name) {
//			this.name = name;
//		}
		
	
}

  • Member.class (@Override 추가 버전)
package com.oracle.oBootJpa01.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;

@Entity
@Table(name = "member1")
@Getter
@Setter
public class Member {
		@Id
		private Long	id;
		private String	name;
		
//		public Long getId() {
//			return id;
//		}
//		public void setId(Long id) {
//			this.id = id;
//		}
//		public String getName() {
//			return name;
//		}
//		public void setName(String name) {
//			this.name = name;
//		}
		
	@Override
	public String toString() {
		String returnStr = "[id:" + this.id + ", name:" + this.name + "]";
		return returnStr;
	}
	
}
  • Member.class (@ToString 버전)
package com.oracle.oBootJpa01.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Entity
@Table(name = "member1")
@Getter
@Setter
@ToString
public class Member {
		@Id
		private Long	id;
		private String	name;
		
//		public Long getId() {
//			return id;
//		}
//		public void setId(Long id) {
//			this.id = id;
//		}
//		public String getName() {
//			return name;
//		}
//		public void setName(String name) {
//			this.name = name;
//		}
		
//	@Override
//	public String toString() {
//		String returnStr = "[id:" + this.id + ", name:" + this.name + "]";
//		return returnStr;
//	}
	
}

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

import java.util.List;

import com.oracle.oBootJpa01.domain.Member;

public interface MemberRepository {
	Member			memberSave(Member member);
	List<Member>	findAllMember();
	List<Member>	findByNames(String searchName);
	
}

 

  • JpaMemberRepository.class
    Tip)
    • EntityManager:  DB table과 mapping된 객체인 Entity에 대한 CRUD 작업을 수행하기 위한 method들을 제공하며, Entity의 라이프 사이클과 영속성 관리등을 담당함

package com.oracle.oBootJpa01.repository;

import java.util.List;

import org.springframework.stereotype.Repository;

import com.oracle.oBootJpa01.domain.Member;

import jakarta.persistence.EntityManager;

@Repository
public class JpaMemberRepository implements MemberRepository {
	// JPA DML --> EntityManager 필수 ***
	private final EntityManager em;
	public JpaMemberRepository(EntityManager em) {
		this.em = em;
	}

	@Override
	public Member memberSave(Member member) {
		em.persist(member);
		System.out.println("JpaMemberRepository memberSave member After...");
		return null;
	}

	@Override
	public List<Member> findAllMember() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<Member> findByNames(String searchName) {
		// TODO Auto-generated method stub
		return null;
	}

}

 

  • MemberService.class
    Tip)
    • @transactional
package com.oracle.oBootJpa01.service;

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

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

import jakarta.transaction.Transactional;

@Service
@Transactional
public class MemberService {
	private final MemberRepository memberRepository;
	@Autowired
		// 옛날거랑 호환을 위해 @Autowired 임포트하기
	public MemberService(MemberRepository memberRepository) {
		this.memberRepository = memberRepository;
	}
	
	// 회원가입
	public Long memberSave (Member member) {
		System.out.println("MemberSave memberSave->"+member);
		memberRepository.memberSave(member);
		System.out.println("MemberService memberSave After...");
		return member.getId();
	}
}

 

  • MemberController.class
package com.oracle.oBootJpa01.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

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

@Controller
public class MemberController {
	private static final Logger logger = LoggerFactory.getLogger(MemberController.class);
	private final MemberService memberService;
	
	@Autowired
	public MemberController(MemberService memberService) {
		this.memberService = memberService;
	}
	
    	// List 신규 등록
	@GetMapping(value="/members/new")
	public String createForm() {
		System.out.println("MemberController /members/new start...");
		return "members/createMemberForm";
	}
	
	@PostMapping(value = "members/save")
	public String memberSave(Member member) {
		System.out.println("MemberController memberSave start..."); 
		System.out.println("MemberController member->"+member);
		System.out.println("MemberController mkember.getId()->"+member.getId()); 
		System.out.println("MemberController member.getName()->"+member.getName());
		
		memberService.memberSave(member);
		System.out.println("MemberController memberSave After...");
		
		return "redirect:/";		
	}

}
  • index.html ==> 메인 화면
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<a href="/members/new">Member 신규생성</a><p>
	<a href="/members">Member List 조회</a>
</body>
</html>

  • createMemberForm.html
<!DOCTYPE html>
<html xmlns="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>JPA 회원 등록</h1>
	<div class="container">
		<form action="/members/save" method="post">
			ID	:	<input type="text" id="id"	name="id"	required="required"><p>
			이름 :	<input type="text" id="id"	name="name" placeholder="이름을 입력하세요">
			<button type="submit">등록</button>
		</form>
	</div>	<!-- container -->
</body>
</html>

 


2) List 조회

  • memberList.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>JPA01 회원 조회</h1>
	<div>
		<form action="/members/search" method="post">
					회원이름 검색 : <input type="text" name="name" placeholder="회원검색 이름을 입력하세요">
			<button type="submit">검색 </button>
		</form>
	</div>
	
	<div class="container">
		<div>
			<table border="1">
				<thead>
					<tr>
						<th>NO</th>
						<th>이름</th>
					</tr>
				</thead>
				<tbody>
					<tr th:each="member : ${members}">
						<td th:text="${member.id}"></td>
						<td th:text="${member.name}"></td>
					</tr>
				</tbody>
			</table>
		</div>
	</div>	<!-- /container -->

</body>
</html>

 

  • MemberController.class
package com.oracle.oBootJpa01.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

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

@Controller
public class MemberController {
	private static final Logger logger = LoggerFactory.getLogger(MemberController.class);
	private final MemberService memberService;
	
	@Autowired
	public MemberController(MemberService memberService) {
		this.memberService = memberService;
	}
	
	// List 신규 등록
	@GetMapping(value="/members/new")
	public String createForm() {
		System.out.println("MemberController /members/new start...");
		return "members/createMemberForm";
	}
	
	@PostMapping(value = "members/save")
	public String memberSave(Member member) {
		System.out.println("MemberController memberSave start..."); 
		System.out.println("MemberController member->"+member);
		System.out.println("MemberController mkember.getId()->"+member.getId()); 
		System.out.println("MemberController member.getName()->"+member.getName());
		
		memberService.memberSave(member);
		System.out.println("MemberController memberSave After...");
		
		return "redirect:/";		
	}
	
	
	// List 조회
	@GetMapping(value = "/members")
	public String listMember(Model model) {
		List<Member> memberList = memberService.getListAllMember();
		logger.info("memberList.size->"+memberList.size());
		model.addAttribute("members",memberList);
		return "members/memberList";
	}
	

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

import java.util.List;

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

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

import jakarta.transaction.Transactional;

@Service
@Transactional
public class MemberService {
	private final MemberRepository memberRepository;
	@Autowired
		// 옛날거랑 호환을 위해 @Autowired 임포트하기
	public MemberService(MemberRepository memberRepository) {
		this.memberRepository = memberRepository;
	}
	
	// 회원가입
	public Long memberSave (Member member) {
		System.out.println("MemberSave memberSave->"+member);
		memberRepository.memberSave(member);
		System.out.println("MemberService memberSave After...");
		return member.getId();
	}

	// List 조회
	public List<Member> getListAllMember() {
		List<Member> listMember = memberRepository.findAllMember();
		System.out.println("MemberService getListAllMember listMember.size()->"+listMember.size());
		return listMember;
	}
}

 

  • JpaMemberRepository.class
package com.oracle.oBootJpa01.repository;

import java.util.List;

import org.springframework.stereotype.Repository;

import com.oracle.oBootJpa01.domain.Member;

import jakarta.persistence.EntityManager;

@Repository
public class JpaMemberRepository implements MemberRepository {
	// JPA DML --> EntityManager 필수 ***
	private final EntityManager em;
	public JpaMemberRepository(EntityManager em) {
		this.em = em;
	}
	
	// 회원 추가
	@Override
	public Member memberSave(Member member) {
		em.persist(member);
		System.out.println("JpaMemberRepository memberSave member After...");
		return null;
	}

	// List 조회
	@Override
	public List<Member> findAllMember() {
											// from 뒤의 Member는 객체명
		List<Member> memberList = em.createQuery("select m from Member m",Member.class)
									.getResultList()
									;
		System.out.println("JpaMemberRepository findAllMember memberList.size()->"+memberList.size());
		return memberList;
	}

	@Override
	public List<Member> findByNames(String searchName) {
		// TODO Auto-generated method stub
		return null;
	}

}


3) 회원이름 검색

  • MemberController.class
package com.oracle.oBootJpa01.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

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

@Controller
public class MemberController {
	private static final Logger logger = LoggerFactory.getLogger(MemberController.class);
	private final MemberService memberService;
	
	@Autowired
	public MemberController(MemberService memberService) {
		this.memberService = memberService;
	}
	
	// List 신규 등록
	@GetMapping(value="/members/new")
	public String createForm() {
		System.out.println("MemberController /members/new start...");
		return "members/createMemberForm";
	}
	
	@PostMapping(value = "members/save")
	public String memberSave(Member member) {
		System.out.println("MemberController memberSave start..."); 
		System.out.println("MemberController member->"+member);
		System.out.println("MemberController mkember.getId()->"+member.getId()); 
		System.out.println("MemberController member.getName()->"+member.getName());
		
		memberService.memberSave(member);
		System.out.println("MemberController memberSave After...");
		
		return "redirect:/";		
	}
	
	
	// List 조회
	@GetMapping(value = "/members")
	public String listMember(Model model) {
		List<Member> memberList = memberService.getListAllMember();
		logger.info("memberList.size->"+memberList.size());
		model.addAttribute("members",memberList);
		return "members/memberList";
	}
	
	
	// 회원 이름 검색
	@PostMapping(value = "members/search")
	public String memberSearch(Member member, Model model) {
		System.out.println("members/search member.getName()->"+member.getName());
		List<Member> memberList = memberService.getListSearchMember(member.getName());
		System.out.println("/members/search memberList.size()->"+memberList.size());
		model.addAttribute("members",memberList);
		return "members/memberList";
	}

}

 

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

import java.util.List;

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

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

import jakarta.transaction.Transactional;

@Service
@Transactional
public class MemberService {
	private final MemberRepository memberRepository;
	@Autowired
		// 옛날거랑 호환을 위해 @Autowired 임포트하기
	public MemberService(MemberRepository memberRepository) {
		this.memberRepository = memberRepository;
	}
	
	// 회원가입
	public Long memberSave (Member member) {
		System.out.println("MemberSave memberSave->"+member);
		memberRepository.memberSave(member);
		System.out.println("MemberService memberSave After...");
		return member.getId();
	}

	// List 조회
	public List<Member> getListAllMember() {
		List<Member> listMember = memberRepository.findAllMember();
		System.out.println("MemberService getListAllMember listMember.size()->"+listMember.size());
		return listMember;
	}
	
	// 회원이름 검색
	public List<Member> getListSearchMember(String searchName) {
		System.out.println("MemberService getListSearchMember start...");
		System.out.println("MemberService getListSearchMember searchName->"+searchName);
		List<Member> listMember = memberRepository.findByNames(searchName);
		System.out.println("MemberService getListSearchMember listMember.size()->"+listMember.size());
		return listMember;
	}
}
  • JpaMemberRepository.class
package com.oracle.oBootJpa01.repository;

import java.util.List;

import org.springframework.stereotype.Repository;

import com.oracle.oBootJpa01.domain.Member;

import jakarta.persistence.EntityManager;

@Repository
public class JpaMemberRepository implements MemberRepository {
	// JPA DML --> EntityManager 필수 ***
	private final EntityManager em;
	public JpaMemberRepository(EntityManager em) {
		this.em = em;
	}
	
	// 회원 추가
	@Override
	public Member memberSave(Member member) {
		em.persist(member);
		System.out.println("JpaMemberRepository memberSave member After...");
		return null;
	}

	// List 조회
	@Override
	public List<Member> findAllMember() {
											// from 뒤의 Member는 객체명
		List<Member> memberList = em.createQuery("select m from Member m",Member.class)
									.getResultList()
									;
		System.out.println("JpaMemberRepository findAllMember memberList.size()->"+memberList.size());
		return memberList;
	}

	
	// 회원이름 검색
	@Override
	public List<Member> findByNames(String searchName) {
		String pname = searchName + '%';
		System.out.println("JpaMemberRepository findByNames pname->"+pname);
		List<Member> memberList = em.createQuery("select m from Member m where name Like :name", Member.class)
									.setParameter("name", pname)
									.getResultList()
									;
		System.out.println("JpaMemberRepository memberList.size()->"+memberList.size());
		return memberList;
	}

}


질문목록

 


수업교재

1. FrameWork ⭐⭐

2. 종류 ==> 면접에 질문이 나오면  정의와 함께 종류 다섯 가지를 설명하기

4. ORM(Object Relational Mapping)

  • Object(객체)를 RDB형식으로 Mapping함, 즉 객체 지향 프로그래밍과 관계형 데이터베이스의 데이터를 매핑하는 기술
    • RDB형식?: 관계형 데이터베이스로, 가장 성공적인 방식이며 행과 열을 나누어 데이터를 보관
  • 가장 널리 사용되는 ORM 프레임워크
  • Spring에서는 주로 Hibernate를 비롯한 JPA(Java Persistence API) 기반 ORM 프레임워크를 사용함
비교
⭐⭐
(면접 필수 질문!)
MyBatis ⭐⭐⭐ Hibernate(JPA)
정의 객체지향 언어인 JAVA의 관계형 데이터베이스 프로그래밍을 좀 더 쉽게 할 수 있게 도와주는 persistence framework JPA의 구현체 중 하나

Java Persistence API
: 자바 ORM 기술에 대한 API 표준 명세로 ORM을 사용하기 위한 인터페이스를 모아둔 것
특징과 장점 1. 성능↑: JDBC의 단점(길어지는 코드, 낮은 유연성)을 개선하여 개발자가 작성한 SQL 명령어와 자바 객체를 매핑해주는 기능을 제공함
 ↳ JDBC: 모든 Persistence Framework에는 내부적으로 JDBC API를 사용함

2. 생산성↑: 기존에 사용하던 SQL 명령어를 재사용하여 코드의 중복과 무의미한 코드 작성을 생략할 수 있음
- JDBC로 처리하는 상당부분의 코드와 파라미터 설정, 결과 매핑을 지원해줌,
- 기존 JDBC를 사용할 때 DB 관련 여러 설정(Connection 생성, Statement 생성 및 쿼리 수행, 결과값(ResultSet) 처리)을 다루어야 했으나, 자바 객체를 실제 SQL 쿼리문에 연결함으로써 빠른 개발과 편리한 테스트를 할 수 있음

3. SQL문을 xml 파일에 작성하여 변환이 자유롭고 가독성이 좋음

4. 간단하여 배우기 쉬움

5. 설계를 향상시켜 유지보수성을 높임

6.  작업을 분배하여 팀을 세분화하는 것을 도움

7. 이식성이 높아 어떤 프로그래밍 언어로도 구현 가능함
1. 1차캐시, 쓰기지연, 변경감지, 지연로딩을 제공하여 성능상 이점을 얻을 수 있음

2. 코드 레벨로 관리 되므로 사용하기 용이하고 생산성이 높음

3. 컴파일 타임에 오류를 확인할 수 있음

4. 데이터베이스에 종속적이지 않으므로 특정 쿼리를 사용하지 않아 추상적으로 기술 구현이 가능함

5. 엔티티로 관리되므로 스키마 변경시 엔티티만 수정하게 되면 엔티티를 사용하는 관련 쿼리는 자동으로 변경된 내역이 반영됨 

6. 개발 초기에는 쿼리에 대한 이해가 부족해도 코드 레벨로 어느 정도 커버가 가능함

7. 객체지향적으로 데이터를 관리할 수 있음

8. 부족한 부분은 다양한 쿼리 빌더와 호환하여 보안할 수 있음


단점 1. 스키마 변경시 SQL 쿼리를 직접 수정해주어야 함

2.
반복된 쿼리가 발생하여 반복 작업이 있음

3.
런타임시에 오류를 확인할 수 있음

4.
쿼리를 직접 작성하기 때문에 데이터베이스에 종속된 쿼리문이 발생할 수 있음

5.
데이터베이스 변경시 로직도 함께 수정해주어야 함
1. JPA만 사용하여 복잡한 연산을 수행하기에는 다소 무리가 있으며, 로직이 복잡하거나 불필요한 쿼리가 발생할 수 있음

2. 초기에는 생산성이 높을 수 있으나 점차 사용하다 보면 성능상 이슈가 발생할 수 있음

3. 고도화 될수록 학습 곡선이 높아질 수 있으며, 성능 이슈의 연장선으로 해결 방안에 따라 복잡한 내부 로직을 이해해야 할 필요가 있음
차이점 SQL Mapper의 한 종류이며, SQL Query문을 통해 데이터를 조작함. 즉, 직접 Query 문을 작성해야함
ex) MyBatis, JDBC Templetes
DB 데이터와 객체(Object)를 직접 맵핑해주는 ORM 기술임
1. SQL Query가 아니라 직관적인 코드(메소드)로서 데이터를 조작할 수 있음
2. 객체간의 관계로 SQL을 자동 생성함
  ex) JPA,Hibernate
사용방식 1. xml만을 이용한 SQL문을 설정,
DAO에서는 XML을 찾아서 실행하는 코드로 작성
  장점: 
SQL문은 별도로 xml로 작성되어 SQL문의 수정이나 유지 보수에 적합함
  단점: 개발시 코드의 양이 많아지고, 복잡성이 증가함

2. Annotation과 인터페이스만을 이용하여 SQL을 설정
  장점:
별도의 DAO 없이도 개발이 가능하여 생산성이 크게 증가함
  단점: 
SQL 문을 Annotation으로 작성하므로, 수정이 필요할 경우 매번 다시 컴파일을 해야함

3. 인터페이스와 xml로 작성된 SQL 문 활용
  장점: 
간단한 SQL문은 Annotation으로, 복잡한 SQL문은 xml로 처리할 수 있어 유연성이 좋음
  단점: 개발자에 따라 개발 방식 차이로 인해, 유지보수가 중요한 프로젝트에서는 부적합함
 
Maping Partial Mapping Full Mapping
SQL 상대 ↑ 상대 ↓
적용기법 SQL Mapping - 객체단위로 업무를 수행함
객체 단위로 접근할때 DAO를 Repository라고 하며, DTO는 Entitiy 라고 함

2. Boot

1. 설치방법

2. Lombok annotation

Lombok Annotation 내용
@NonNull Null 값이 될 수 없다는 것을 명시
@Getter/Setter 코드가 컴파일될 때 속성들에 대해서 Getter/Setter 메소드들을 생성
@ToString toString() 메소드를 생성
@EqualsAndHashCode 해당 객체의 equals() 와 hashCode() 메소드를 생성
@NoArgsConstructor 파라미터를 받지 않는 생성자를 만들어 줌
@RequiredArgsConstructor 지정된 속성들에 대해서만 생성자를 만들어 줌
@AllArgsConstructor 모든 속성들에 대해서 값을 받는 생성자를 만듬
@Data ⭐⭐ @ToString, @EqualsAndHashCode, @Getter(모든 속성), @Setter(final 이 아닌 속성), @RequiredArgsConstructor를 합쳐둔 어노테이션
@Value 불변 클래스를 생성
@Log 자동으로 생기는 log 라는 변수를 이용해서 로그를 찍을 수 있음
자동으로 logging 위한 필드인 private static Logger logger 생성

3. gradle와 Maven 비교⭐⭐(면접 질문)

항목 Gradle Maven
공통점 둘 다 Java 프로젝트를 빌드하고 관리하기 위한 도구임
사용 Project
⭐⭐⭐
Spring-Boot, Android SpringProject, Spring-Boot
사용 용도 별도의 Build 스크립트(Build.gradle 파일)를 통하여 사용할 어플리케이션버전, Library 등의 항목을 설정 - Build.gradle 파일이 없으며, Maven Dependencies Library를 통해 설정가능

- .m2 파일
을 통해 내가 사용할 Library뿐만 아니라 ,해당 Library가 작동하는데 필요한 다른 Library들까지 관리하여 NW를 통해 자동으로 D/L

적용 이유 Script언어로 구성되어 있기 때문에, XML과 달리 변수선언, if, else, for 등의 Logic 구현가능하여 간결하게 구성가능 - 프로젝트의 전체적인 Life cycle을 관리하는 도구이며, 많은 편리함과 이점이 있어 널리 사용
- 현재 많이 사용
관리/ Life cycle - Library관리: Maven 레파지토리를 동일하게 사용할 수 있어서 설정된 서버를 통하여 Library를 D/L 받아 모두 동일한 의존성을 가진 환경을 수정가능하며 자신이 추가한 Library도 Repository 서버에 Up 가능
- Project관리: 모든 Project가 일관된 Directory 구조를 가지고 build Process를 유지 support .
- 단위테스트 시 의존성관리: junit등을사용하기 위해서명시
- Clean: 이전 빌드에서 생성된 파일들을 삭제하는 단계
- Validate : 프로젝트가 올바른지 확인하고 필요한 모든 정보를 사용할 수 있는지 확인하는 단계
- Compile : 프로젝트의 소스코드를 컴파일하는 단계 - Package : 실제 컴파일된 소스코드와 리소스들을 jar등의 배포를 위한 패키지로 만드는단계
- Verify : 통합테스트 결과에 대한 검사를 실행하여  품질기준을 충족하는지 확인하는 단계
- Install : 패키지를 로컬저장소에 설치하는 단계
- Site : 프로젝트 문서를 생성하는 단계
- Deploy : 만들어진 Package를 원격 저장소에 release하는 단계
- 생명주기:  run as의 maven clean과 maven install을 통해 해결 가능
사용 요소
⭐⭐⭐
Build.gradle⭐
1.
복잡한 빌드 시나리오가 필요한 프로젝트
2. 빠른 빌드 성능이 중요한 대규모 프로젝트
3. Kotlin, Scala 등 다양한 언어 지원이 필요한 경우
POMpom.xml파일을 말하며, Maven의 기능을 이용하기 위해 POM 사용

1. 표준화된 프로젝트 구조가 필요한 경우
2. 풍부한 플러그인과 문서 지원이 중요한 프로젝트.
3. 의존성 관리가 중요하지만, 성능보다는 안정성이 중요한 경우
장점 1. 설정 내용 간결, 가독성 향상

2. 유연성: Gradle은 Groovy 또는 Kotlin DSL을 사용하여 스크립트를 작성할 수 있어 매우 유연하고 강력한 빌드 스크립트를 작성할 수 있음

3.우수한 의존성 관리: Gradle은 의존성 관리를 효율적으로 처리할 수 있으며, Maven Central Repository와 같은 다양한 저장소를 지원

4. 성능: Gradle은 빌드 시간을 단축시켜, 대규모 프로젝트에서 빌드 속도가 빨라짐

5. 다중 언어 지원: Gradle은 Java뿐만 아니라 Kotlin, Scala, Groovy 등 다양한 언어를 지원함
1. 표준화된 구조: Maven은 표준 프로젝트 구조와 생명주기를 제공하여 프로젝트 설정과 유지관리가 쉬움

2. 광범위한 플러그인: Maven은 다양한 플러그인을 제공하여 빌드, 테스트, 배포 등을 쉽게 설정할 수 있음

3. 의존성 관리: Maven Central Repository와의 통합으로 의존성 관리를 용이하게 할 수 있음

4. 문서화: Maven은 풍부한 문서와 예제를 제공하여 사용법을 쉽게 익힐 수 있음
단점 1. 학습 곡선: Gradle의 유연성과 강력한 기능 때문에 초기 학습 곡선이 가파를 수 있음

2. 복잡성: 프로젝트가 복잡해질수록 빌드 스크립트 관리가 어려워질 수 있음
1. 의존성 관리: 의존관계가 복잡한 프로젝트 설정하기에는 부적절

2. 속도: Gradle에 비해 빌드 속도가 느릴 수 있음

3. 유연성 부족: XML 기반 설정으로 인해 빌드 스크립트의 유연성이 떨어질 수 있음

4. 복잡한 설정: 복잡한 프로젝트에서는 POM 파일이 매우 길어지고 관리가 어려워질 수 있음

3. JPA 1장

1. 정의 

  • Java Persistence API
    • Persistence ?: 프로그램이 종료되더라도 사라지지 않는 데이터의 특성 (영속성)
      => 어플리케이션을 종료하고 다시 실행하더라도 이전에 저장한 데이터를 다시 불러올 수 있는 기술
    • Persistence Framework?
      - 데이터베이스와의 연동되는 시스템을 빠르게 개발하고 안정적인 구동을 보장해주는 프레임워크
      - 종류: SQL Mapper(Mybatis), ORM(Hibernate, JPA)
    • PersistenceContext(영속성 컨텍스트)?
      - 영속화 되어있는 entity identity에 대해 unique한 entity 인스턴스가 존재하는 entity 인스턴스의 집합
      -  entity의 영속화에 관여함
      -  entity들이 DB로 바로 가지 않고 entity를 저장하는 환경으로서의 역할을 하도록 함
      -- 장점
      1. 성능 향상: 영속성 컨텍스트를 사용하면 엔티티를 메모리에 캐시함으로서 빈번하게 데이터베이스에 접근하는것을 줄일 수 있고, 데이터베이스 로드 또한 줄일 수 있음
      2. 간소화된 데이터베이스 엑세스: 엔티티를 관리하기 위한 단순화된 API를 제공하여 데이터베이스 액세스를 단순화함. 이를 통해 개발자는 낮은 수준의 데이터베이스 엑세스를 위한 쿼리에 집중하기 보다는 애플리케이션의 비즈니스 로직에 집중할 수 있음
      3. 데이터 일관성의 향상: 엔티티 라이프사이클즉 엔티티의 상태에 대한 관리를 자동적으로 관리함으로서 엔티티가 일관성있도록 보장해줌
      4. 향상된 scalability(확장성): 데이터베이스에대한 접근과 엔티티의 상태관리를 자동적으로 하기 때문에 확장성에서도 이점을 가짐
    • EntityManager.persist(entity);
      EntityManager.persist를 활용하여 해당 entity를 영속성 컨텍스트로 보내고, 영속성 컨텍스트를 통해서 해당 데이터를 영속화 한다 라는 의미
  • 자바진영의 ORM 기술표준
  • 개념도: Java Program(일반적으로 DAO)에서 JPA에 접근(Entity) => JPA에서 일반적 SQL 자동생성(Query로 만들수도 있음) => JDBC API 통해 DML 작업수행

2. JPA 동작(저장& 조회)

  • 저장: Entiry 분석 => insert Emp SQL 자동 생성 => JDBC API 수행 => DML 작업 수행
  • 조회:  find안에 PK를 넘겨 줌 => JDBC API수행 => 조회된 객체를 전달

3. JPA 표준명세와 특징

1. JPA 표준명세

  • JPA는 Interface 모음
  • JPA 2.1 표준 명세를 구현한 3가지 구현체
  • 하이버네이트, EclipseLink, DataNucleus - JPA 2.0(JSR 317) 2009년 : 대부분의 ORM 기능을 포함, JPA Criteria 추가
  • JPA 2.1(JSR 338) 2013년 : 스토어드 프로시저 접근, 컨버터(Converter), Entity 그래프 기능이 추가

2. JPA 특징

  • SQL 중심적인 개발에서 객체 중심으로 개발
  • 생산성
  • 유지보수
  • 성능
  • 데이터 접근 추상화와 벤더 독립성
  • 표준

3. SQL별로 표준을 지키지 않은 데이터베이스만의 고유한 기능, 데이터베이스 방언

 

4. JPA CRUD

  1. 저장: jpa.persist(emp) Entitymanager를 통해 영속성 Context에 저장
  2. 조회: Empemp= jpa.find(empno)
  3. 수정: emp.setEname(“변경할이름”)
  4. 삭제: jpa.remove(emp)

오늘의 숙제

 

'Spring' 카테고리의 다른 글

2024_08_07_수~08_08_목  (0) 2024.08.07
2024_08_06_화~08_07_수  (0) 2024.08.06
2024_08_02_금  (0) 2024.08.02
2024_08_01_목  (0) 2024.08.01
2024_07_31_수  (0) 2024.07.31