Boot_test.txt
# 테스트 스타터
- 스프링 부트를 이용하여 프로젝트를 생성하면 테스트 스타터는 자동으로 추가 됨
# 기본 테스트 클래스
- 스프링 부트는 프로젝트를 생성할 때,
'src/test/java' 소스 폴더에 간단한 테스트 케이스를 제공
---------------------------------------------------------------------------------
# 스프링 부트 테스터
1. 테스트 케이스 실행
- Run As => JUnit test 로 실행하면, JUnit 뷰를 통해서 결과를 확인할 수 있음
2. 외부 프로퍼티 사용
- 테스트 케이스 작성시에 여러 테스트에서 공통으로 사용하는 데이터는
외부 프로퍼티에 등록하면 데이터를 변경하거나 재사용하기가 쉬워짐
---------------------------------------------------------------------------------
# MockMvc 이용한 테스트
1. 목 객체로 테스트하기
- Mock(목) 은 테스트를 위해서 만든 모형을 의미
Mocking : 테스트를 위해 실제 객체와 비슷한 모의 객체를 만드는 것
Mock-up : 모킹한 객체를 메모리에서 얻어내는 과정
- 웹 애플리케이션에서 컨트롤러를 테스트할 때 서블릿 컨테이너를 모킹하기 위해서는
@WebMvcTest 를 사용하거나, @AutoConfigureMockMvc 를 사용
---------------------------------------------------------------------------------
# Logback
- 안전하고 편리하게 log 를 관리해주는 Logging 라이브러리
# ANSI Escpae in Console 플러그인
- 로그를 로그 레벨별로 다른 색으로 출력
# log level
- TRACE > DEBUG > INFO > WARN > ERROR > FATAL
- FATAL : 애플리케이션 실행에 심각할 정도의 오류
- 아주 심각한 에러
ERROR : 애플리케이션은 실행 가능하지만 꽤 심각한 오류
- 요청 처리 중에 문제 발생
WARN : 애플리케이션에 잠재적 위험을 안기는 오류
- 처리 가능한 문제이지만, 향후 시스템 에러의 원인이 될 수 있는 경고
INFO : 애플리케이션의 주요 실행 정보
- 정보서 메시지
DEBUG : 애플리케이션의 내부 실행에 대한 정보
- 디버깅 정보
TRACE : 애플리케이션의 실행 내역에 대한 debug 보다 상세한 정보
spring.main.web-application-type=servlet
server.port=8080
# Spring Boot의 Devtools 에는 classpath 에 속해있는 파일들의 수정을 감시하고
# 자동으로 재시작해주는 기능이 포함되어 있다
spring.devtools.livereload.enabled=true
# Test Property Setting
author.name = Tester
author.age = 100
# Logging Setting
# package 이름
# log level : TRACE > DEBUG > INFO > WARN > ERROR > FATAL
logging.level.com.web=trace
#logging.file.name=src/main/resources/board_log.log
package com.web;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Service;
@Service
public class LoggingRunner implements ApplicationRunner{
private Logger logger = LoggerFactory.getLogger(LoggingRunner.class);
@Override
public void run(ApplicationArguments args) throws Exception {
// TODO Auto-generated method stub
logger.trace("trace 로그 메시지");
logger.debug("debug 로그 메시지");
logger.info("info 로그 메시지");
logger.warn("warn 로그 메시지");
logger.error("error 로그 메시지");
}
}
package com.web.controller;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.web.service.BoardService;
import com.web.vo.BoardVO;
/*
* # @RestController
* - RESTful 웹 서비스를 제공하는 컨트롤러 클래스를 정의할 때 사용됩니다
* 이 애너테이션을 사용하면 해당 컨트롤러가 HTTP 요청에 응답하고,
* JSON 또는 XML 형식의 데이터를 반환할 수 있습니다
* - JSP 같은 뷰(View)를 별도로 만들지 않는 대신에 컨트롤러 메서드가 리턴한
* 데이터 자체를 클라이언트로 전달합니다
* - 클라이언트에 전달되는 데이터는 대부분 문자열, VO 이거나 컬렉션 형태의 자바 객체 인데
* 자바 객체가 전달되는 경우 자동으로 JSON 으로 변환하여 처리합니다
*/
@RestController
public class BoardController {
@Autowired
private BoardService bs;
public BoardController() {
System.out.println("- BoardController -");
}
// @GetMapping("/hello")
// public String hello() {
// return "boot start";
// }
//
@GetMapping("/hello")
public String hello(String data) {
return bs.hello(data);
}
// VO 객체 반환
@GetMapping("/getBoard")
public BoardVO getBoard() {
// BoardVO board = new BoardVO();
// board.setSeq(1);
// board.setTitle("vo test");
// board.setWriter("테스트");
// board.setContent("devTools 입니다");
// board.setCreateDate(new Date());
// board.setCnt(0);
return bs.getBoard();
}
// collection 반환
@GetMapping("/getBoardList")
public List<BoardVO> getBoardList() {
// List<BoardVO> list = new ArrayList<>();
// for(int i=1 ; i<=5 ; i++) {
// BoardVO board = new BoardVO();
// board.setSeq(i);
// board.setTitle("제목 : " + i);
// board.setWriter("테스트 " + i);
// board.setContent(i + "번 내용입니다");
// board.setCreateDate(new Date());
// board.setCnt(0);
// list.add(board);
// }
return bs.getBoardList();
}
}
package com.web.service;
import java.util.List;
import com.web.vo.BoardVO;
public interface BoardService {
public String hello(String data);
public BoardVO getBoard();
public List<BoardVO> getBoardList();
}
package com.web.service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Service;
import com.web.vo.BoardVO;
@Service
public class BoardServiceImpl implements BoardService{
@Override
public String hello(String data) {
// TODO Auto-generated method stub
return "data - " + data;
}
@Override
public BoardVO getBoard() {
// TODO Auto-generated method stub
BoardVO board = new BoardVO();
board.setSeq(1);
board.setTitle("vo test");
board.setWriter("테스트");
board.setContent("devTools 입니다");
board.setCreateDate(new Date());
board.setCnt(0);
return board;
}
@Override
public List<BoardVO> getBoardList() {
// TODO Auto-generated method stub
List<BoardVO> list = new ArrayList<>();
for(int i=1 ; i<=5 ; i++) {
BoardVO board = new BoardVO();
board.setSeq(i);
board.setTitle("제목 : " + i);
board.setWriter("테스트 " + i);
board.setContent(i + "번 내용입니다");
board.setCreateDate(new Date());
board.setCnt(0);
list.add(board);
}
return list;
}
}
package com.web.vo;
import java.util.Date;
import lombok.Data;
@Data
public class BoardVO {
private int seq;
private String title;
private String writer;
private String content;
private Date createDate = new Date();
private int cnt;
}
project - properties - Project Facets에 jap 추가하기
Help 메뉴
1. Install new software...
2. Work with: 항목에 http://download.eclipse.org/releases/oxygen를 입력 후 엔터
3. 아래 Name 항목 여럿 중에서
"Web, XML, Java EE and OSGi Enterprise Development" 항목을 펼쳐서 JPA 관련 모든 항목을 체크한다
(이때 간단히 찾는 방법은 위의 "type filter text" 항목에 JPA라고 입력)
이렇게 설치과정을 진행 후 이클립스 재구동
pom.xml 에 의존성 추가
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.6.15.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc8 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>21.1.0.0</version>
</dependency>
# JPA ( JAVA Persistence API )
- ORM 을 보다 쉽게 사용할 수 있도록 표준화 시킨 것
# 엔티티 클래스
- JPA 는 테이블이 없으면 자바 클래스를 기준으로 매핑할 테이블을 자동으로 생성하는데
테이블과 매핑되는 자바 클래스 엔티티라고 한다
# JPA
- META-INF/persistence.xml 은 JPA 의 환경설정 파일이다
------------------------------------------------------------------------------------------------------
<properties>
<!-- 필수 속성 -->
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
<property name="javax.persistence.jdbc.user" value="dbtest" />
<property name="javax.persistence.jdbc.password" value="a1234" />
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521/xe"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<!-- 옵션 -->
<!-- SQL 을 콘솔에 출력 -->
<property name="hibernate.show_sql" value="true" />
<!-- SQL 을 출력할 때, 보기 좋은 포맷으로 출력 -->
<property name="hibernate.format_sql" value="true" />
<!-- SQL 에 포함된 주석도 같이 출력 -->
<property name="hibernate.use_sql_comments" value="false" />
<!-- key 생성 전략을 사용 -->
<property name="hibernate.id.new_generator_mappings" value="true" />
<!-- 테이블 CREATE, ALTER, DROP 와 같은 DDL 구문의 자동 실행 지정 -->
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
# Dialect
- 표준 SQL 인 ANSI SQL 외에, DBMS 인 Oracle, MySQL 등 각 DB 마다 문법과 함수가 조금씩 다름
이러한 SQL 표준을 지키지 않는 특정 벤더별 기능을 Dialect(방언) 이라고 부름
- JPA 에게 어떤 DBMS 를 사용하는지 알려주는 방법이 Dialect 를 설정이다
- 각 DB Dialect
org.hibernate.dialect.Oracle10gDialect
org.hibernate.dialect.H2Dialect
org.hibernate.dialect.MySQL5InnoDBDialect
org.hibernate.dialect.PostgreSQLDialect
org.hibernate.dialect.SQLServerDialect
org.hibernate.dialect.MariaDB103Dialect
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
- value 부분 값 고르면 됨
------------------------------------------------------------------------------------------------------
# 영속성 유닛
- 엔티티 객체를 관리하는 컨텍스트 입니다
- 연결하는 데이터베이스당 하나의 영속성 유닛 persistence-unit 을 지정
- 엔티티 매니저 팩토리를 통해서 생성되며, 엔티티 객체의 상태변화를 감지하고 데이터베이스를
package com.web.domain;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
/*
* # @Entity
* - 설정된 클래스를 엔티티라 하며
* - 기본적으로 클래스 이름과 동일한 테이블과 매핑됨
*
* # @Table
* - 엔티티 이름과 매핑될 테이블 이름이 다른 경우
* - name 속성을 사용하여 매핑 (엔티티 이름과 테이블이 동일하면 생략 가능)
*
* # @Id 😊중요
* - 테이블 기본키를 매핑 (primary key)
* 엔티티의 필수 @ 이므로 @Id 가 없는 엔티티는 사용하지 못 함
*
* # @GeneratedValue
* - @Id 가 선언된 필드에 키 값을 자동으로 할당
*
* # @Column
* - 엔티티 클래스의 멤버필드와 테이블의 컬럼을 매핑할 때 사용
* - 엔티티 클래스의 멤버필드 명과 컬럼 이름이 다를 경우에 사용
*
* # @Transient
* - 엔티티 클래스의 특정 멤버필드를 영속 필드에서 제외할 때 사용
*
* # @Temporal
* - java.util.Date 타입의 날짜 데이터를 매핑할 때 사용
* - 출력되는 날짜의 형식을 지정할 수 있다.
* > TemporalType.DATE 날짜 정보만 출력
* TemporalType.TIME 시간 정보만 출력
* TemporalType.TIMESTAMP 날짜와 시간 정보 모두 출력
*
* # 테이블 전략
* # @TableGenerator
* name: 키 생성기의 이름을 지정합니다.
* table: 키 생성 정보를 저장하는 테이블의 이름을 지정합니다.
* pkColumnName: 테이블에서 사용되는 기본 키 컬럼의 이름을 지정합니다.
* valueColumnName: 테이블에서 사용되는 키 값 컬럼의 이름을 지정합니다.
* pkColumnValue: 키 생성기를 식별하는 데 사용되는 값으로, 테이블에서 특정 행을 식별합니다.
* allocationSize: 키 값의 미리 할당되는 크기를 지정합니다.
*/
@Entity
@TableGenerator(name = "BOARD_SEQ_GENERATOR", // 테이블 이름
table = "ALL_SEQUENCE", // 시퀀스 생성
pkColumnValue = "BOARD_SEQ", // 시퀀스 이름
initialValue = 0, // 시퀀스 시작 값
allocationSize = 1) // 시퀀스 증가 값
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "BOARD_SEQ_GENERATOR") // Id, GeneratedValue 는 한 셋트
private Long seq; // @Id 했기 때문에 primary key 가 됨 seq 는 추가 시 1씩 올라갈거니까 위의 제네레이터를 써서 추가해 줘야 함
@Transient
private String searchKeyword;
// 웹에서 데이터를 받거나 줄 때 dto, vo 형식으로 주고 받으면 편하지만 db에는 넣지 않을 때
// @Transient 를 사용하면 될 듯?
@Column(name = "BOARD_TITLE", nullable = false, length = 30)
private String title;
private String writer;
private String contents;
@Temporal(TemporalType.DATE)
private Date createDate;
private Long cnt;
public Long getSeq() {
return seq;
}
public void setSeq(Long seq) {
this.seq = seq;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getContents() {
return contents;
}
public void setContents(String contents) {
this.contents = contents;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Long getCnt() {
return cnt;
}
public void setCnt(Long cnt) {
this.cnt = cnt;
}
@Override
public String toString() {
return "Board [seq=" + seq + ", title=" + title + ", writer=" + writer + ", contents=" + contents
+ ", createDate=" + createDate + ", cnt=" + cnt + "]";
}
}
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="P06_jpa">
<class>com.web.domain.Board</class>
<properties>
<!-- 필수 속성 -->
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
<property name="javax.persistence.jdbc.user" value="dbtest" />
<property name="javax.persistence.jdbc.password" value="a1234" />
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521/xe"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<!-- 옵션 -->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="false" />
<property name="hibernate.id.new_generator_mappings" value="true" />
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
</persistence-unit>
</persistence>
package com.web;
import java.util.Date;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import com.web.domain.Board;
public class JPAClient {
public static void main(String[] args) {
// EntityManager 생성
EntityManagerFactory factory = Persistence.createEntityManagerFactory("P06_jpa"); // unit name 으로 갖고 factory 생성
EntityManager manager = factory.createEntityManager();
// Transaction 생성
EntityTransaction tx = manager.getTransaction();
try {
// Transaction 시작
tx.begin();
Board board = new Board();
board.setTitle("JPA 테스트");
board.setWriter("JPA 작성자2");
board.setContents("JPA 내용");
board.setCreateDate(new Date());
board.setCnt(0L);
// 해당 VO 객체를 DB에 등록
manager.persist(board);
tx.commit();
// -----------------------------
// 글 상세 조회
// - 데이터를 조회 할 때 EntityManager 의 find() 메서드를 사용
Board searchBoard = manager.find(Board.class, 1L);
System.out.println("---> " + searchBoard.toString());
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
tx.rollback();
} finally {
factory.close();
manager.close();
}
}
}