Object.equals() 는
== 도 비교하고, equals로도 비교한다
@SpringBootApplication
public class Application implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setWebApplicationType(WebApplicationType.NONE);
app.run(args);
}
또는
application.properties 파일에서
spring.main.web-application-type=none
우선순위가 높은건 properties 파일이 높다.
spring.main.web-application-type=servlet 톰캣서버로 구동시키겠다는 설정
WebApplicationType 설정 세가지
1. NONE : 웹으로 동작하지 않도록 설정
2. SERVLET : 기존의 스프링 MVC를 기반으로 웹 애플리케이션을 구동
3. REACTIVE : 비동기처리 & 논블로킹입출력을 지원하는 웹플럭스를 적용할때사용
자세한 properties 설정은 아래에서 확인
기존 스프링에서 스프링부트로 넘어오면서 추가된것
1. 스타터: 특정 모듈을 사용할수있도록 라이브러리들을 다운받아온다
2. AutoConfiguration: 스타터로 추가한 라이브러리를 자동으로 빈설정
3. properties
실제객체와 비슷한 가짜객체를 만들어서 테스트에 필요한 기능만 가지도록 모킹을하면 테스트가 쉬워진다. 모킹한 객체를 이용하면 의존성을 단절시킬수 있어서 쉽게 테스트할수 있다
모킹하기위해서는 아래와같은 애너테이션을 붙인다
@WebMvcTest : 컨트롤러만 테스트 (@Controller, @RestController)
@AutoConfigureMockMvc : 컨트롤러+ @Service , @Repository 테스트
@WebMvcTest 는 @SpringBootTest 를 같이 사용할수 없다. 각자 서로의 MockMvc를 모킹하기때문에 충돌이 발생한다.
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class BoardControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private BoardService boardService;
@Test
public void testHello() throws Exception {
/* 테스트 실행작업 */
when(boardService.hello("둘리")).thenReturn("Hello:둘리");
/* 검증작업 */
mockMvc.perform(get("/hello").param("name","둘리"))
.andExpect(status().isOk()) // 상태코드
.andExpect(content().string("Hello:둘리"))
.andDo(print());
}
}
perform() 메서드를 사용하면 URL 요청을하듯 컨트롤러를 실행시킬수있다
perform() 안에는 get(), post(), delete() 메서드를 제공한다.
andExpect() 메서드를 사용하면 서버의 응답 결과를 검증할수있다.
andExcept(view().name("hello")) 뷰이름검증
andExcept(redirectedUrl("/index")) index 화면으로 리다이렉트했는지 검증
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class BoardControllerTest {}
테스트할때 충돌될수있으므로 RANDOM_PORT 랜덤포트 사용
SLF4J 에서 제공하는 LoggerFactory를 사용
LoggingRunner.java
@Service
public class LoggingRunner implements ApplicationRunner {
/* LoggerFactory를 통해 Logger를 획득한다. */
private Logger logger = LoggerFactory.getLogger(LoggingRunner.class);
@Override
public void run(ApplicationArguments args) throws Exception {
logger.trace("TRACE 로그 메시지");
logger.debug("DEBUG 로그 메시지");
logger.info("INFO 로그 메시지");
logger.warn("WARN 로그 메시지");
logger.error("ERROR 로그 메시지");
}
}
application.properties
/* 로그레벨 변경 */
logging.level.com.fastcampus.springboot=trace
/* 로그저장 */
logging.file.name=src/main/resources/board_log.log
LogBack 사용 로그파일을 직접 관리하는방식. 여러가지 로깅패턴을 줄수있다.
src>main>resources>logback.xml
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="com.fastcampus.springboot" level="DEBUG" />
</configuration>
인텔리제이나 이클립스를 이용하여 애플리케이션을 실제 운영 서버에 배포하기 위해 배포 가능한 파일로 패키징해야한다.
- 자바프로젝트일경우 JAR 로 패키징 해야한다
→ 스프링부트는 JAR로 패키징하여 사용할수있도록 지원한다.
- 웹트로젝트일경우 WAR 로 패키징 해야한다
→ JAR파일과 다르게 내부 디렉터리 구조와 복잡한 파일들의 위치를 신경써야함
1. pom.xml 의존성 추가
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- 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.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.224</version>
</dependency>
경로 추가

Java Board 클래스 추가
package com.example.javaspringboot.domain;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.Date;
@Getter
@Setter
@ToString
@Entity
@Table(name="BOARD")
public class Board {
@Id
@GeneratedValue
private Long seq;
private String title;
private String writer;
private String content;
private Date createDate;
private Long cnt;
}
| 어노테이션 | 의미 |
|---|---|
| @Entity | 클래스가 데이터베이스 테이블에 매핑됨을 나타낸다 |
| @Table | 엔티티 클래스가 매핑될 데이터베이스 테이블에 대한 세부 정보를 지정할 때 사용 |
| @Id | 테이블의 기본키를의미 (PK) |
| @GeneratedValue | 기본키값을 자동으로 할당 (시퀀스) |
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence" version="3.0">
<persistence-unit name="ch4">
<class>com.example.javaspringboot.domain.Board</class>
<properties>
<!-- 필수 속성 -->
<property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="jakarta.persistence.jdbc.user" value="sa"/>
<property name="jakarta.persistence.jdbc.password" value=""/>
<property name="jakarta.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<!-- 옵션 -->
<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"/>
<!-- DB를 매번 새로 만들기 때문에 기존 데이터는 지워짐 -->
<property name="hibernate.hbm2ddl.auto" value="create"/>
<!-- DB를 누적, 기존에 테이블이 있으면 새롭게 생성하지않고 테이블을 재사용 -->
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
package com.example.javaspringboot;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Persistence;
import java.util.Date;
import com.example.javaspringboot.domain.Board;
public class JPAClient {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("ch4");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
tx.begin(); /* 트랜잭션 시작 */
Board board = new Board();
board.setTitle("JPA 제목");
...
em.persist(board); /* 글등록 */
tx.commit(); /* 커밋 */
} catch(Exception e){
e.printStackTrace();
tx.rollback(); /* 롤백 */
} finally {
em.close();
emf.close();
}
}
}
public class JPAClient {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("ch4");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
/* DB 작성글 조회 - Board클래스 타입의 기본 키 값이 1 */
/* 조회는 tx와 관련이 없기때문에 tx 사용 안함 */
Board searchBoard = em.find(Board.class, 1L);
System.out.println(searchBoard.toString());
} catch(Exception e){
e.printStackTrace();
} finally {
em.close();
emf.close();
}
}
}
