스프링부트 시작

dani Kim·2024년 8월 1일
Object.equals() 는
== 도 비교하고, equals로도 비교한다
  • Controller 위에 return을 view로 반환해야하는데 @RestController 를 사용할경우 view 화면을 만들 필요가 없이 JSON형식으로 변환하여 화면에 출력한다.
@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


MocmMvc 객체를 이용해서 테스트

  • 목(Mock) : 테스트를 위해만든 모형
  • 모킹(Mocking) : 테스트를위해 실제 객체와 비슷한 모의 객체를 만드는것
  • 목업(Mock-up) : 모킹한 객체를 메모리에서 얻어내는 과정

실제객체와 비슷한 가짜객체를 만들어서 테스트에 필요한 기능만 가지도록 모킹을하면 테스트가 쉬워진다. 모킹한 객체를 이용하면 의존성을 단절시킬수 있어서 쉽게 테스트할수 있다

모킹하기위해서는 아래와같은 애너테이션을 붙인다
@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 (Simple Logging Facade for Java)를 이용하여 로그를 관리한다.
    종류는 LogBack, SLF4J
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파일과 다르게 내부 디렉터리 구조와 복잡한 파일들의 위치를 신경써야함

하이버네이트. JPA, H2 DB 사용

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>
  1. 경로 추가

  2. 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기본키값을 자동으로 할당 (시퀀스)
  1. persistence.xml 작성
<?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>
  1. DTO 작성
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();
        }
    }
}

JPA 구동방식

profile
파라랑푸~~~

0개의 댓글