본문 바로가기
Spring/이론

SpringBoot

by 모스키토끼 2020. 4. 22.

SpringBoot를 왜 쓸까?

1 Auto Configuration

  • Spring 기반 앱의 복잡한 설정
  • 비슷한 기술 스택으로 다른 SpringMVC 애플리케이션을 개발하려면 구성을 복사 붙여 넣기를 한다. 
    => 반복되는 작업
  • SpringBoot는 이 작업을 자동으로 해준다.
    -> 클래스 path에 어떤 라이브러리가 있는지 확인 -> 무슨 라이브러리를 쓰는 지 확인 후 자동으로 Spring이 설정해준다. ( 의존성 추가와 필요한 Property만 세팅하면 끝 )
    -> But 기본적인 관례는 필요하다.(Convention over configuration) -> 관례를 기반으로 자동으로 설정해주는 것
    -> 따라서 필요한 것만 개발자가 수정해주면 된다.
  • Spring Boot 가 스캔하는 것 2가지
    • CLASSPATH에서 사용할 수 있는 프레임 워크가 존재하는 지 확인
    • 개발자가 커스터마이즈 한 것이 있는지 확인
  • auto-configuration 작동 요소
    • @Conditional annotation이 달린 AutoConfiguration classes( DataSourceAutoConfiguration.class )

2. Easy dependency Management

  • spring-boot-starter-* dependency 
    • 사전 설정되어 있음
    • 가장 일반적으로 사용되는 라이브러리를 가지고 있음
    • spring-boot-stater-web을 추가하면 추가되는 라이브러리들
      - Spring - core, beans, context, aop
      - Web MVC - (Spring MVC)
      - Jackson - for JSON Binding
      - Validation - Hibernate Validator, Validation API
      - Embedded Servlet Container - Tomcat
      - Logging - logback, slf4j
    • 다른 starter
      - spring-boot-starter-web - Web & RESTful applications
      - spring-boot-starter-test - Unit testing and Integration Testing
      - spring-boot-starter-jdbc - Traditional JDBC
      - spring-boot-starter-security - Authentication and Authorization
      - spring-boot-starter-data-jpa - Spring Data JPA with Hibernate
    • 알아서 Spring이 넣어준다. (서로 호환되는 버전들만 쭉 불러들인다.)

3. Embedded Servlet Container Support

  • tomcat 같은 servlet container가 내장이 되어있다.
  • boot는 main 메서드가 존재하고 main 메서드를 실행하면 내장된 Tomcat이 실행된다.
    - tomcat 설치 필요 x -> jar 파일 크기가 크다.(원래는 war 파일)
    --> 이것이 꼭 좋은 것만은 아니다.
  • 원래라면 하나의 톰캣 안에 여러 개의 web applictaion이 존재했는데 -톰캣 1개
    boot에서는 jar파일 안에 각각 tomcat이 내장되어있다. - 톰갯 jar파일 개수만큼
  • pom.xml의 패키징 유형은 'jar'이 아니라 'war'

4. SpringBoot Actuator

  • 애플리케이션의 고급 모니터링 및 추적을 가능하게 한다.
  • / beans 엔드 포인트는 애플리케이션에 등록된 모든 Bean을 보여준다.
    ex) localhost:8080/mappings -> 모든 @RequestMapping paths를 보여준다.
  • / mappings 엔드 포인트는 애플리케이션 URL, 맵핑 환경 세부 사항 및 구성 매개 변수 값을 보여준다.
  • / health 엔드 포인트는 diskSpace, 데이터베이스 등을 포함한 application의 상태를 보여준다.

 

Create SpringBoot Project

- 구조

※ Applictaion.properties: 커스터마이즈 해준 값

 

- pom.xml

<?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 https://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>2.2.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.kakao.daehwan</groupId>
	<artifactId>springBootStudy</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springBootStudy</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

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

</project>
  • spring-boot-starter-parent로 버전을 명시하면 다른 starter 의존성들에는 버전을 쓸 필요가 없다.
    ->필요한 라이브러리들은 이제 상속을 받아서 사용하기 때문에 따로 명시할 필요가 없다.
    ->부모 노드에서 잘 명시해놓아야 한다.
  • SpringBoot는 JSP대신 Thymeleaf를 사용한다.
    -> spring-boot-starter-thymeleaf
  • spring-boot-starter-web은 default로 DispatcherServlet을 URL 패턴 "/"로 한다.
  • spring-boot-starter-web은 default로 8080 포트에서 실행되는 embedded Servelt container인 Tomcat을 추가한다.
  • 실질적인 작업은 플러그인들이 하는데
    spring-boot-maven-plugin -> 이 플러그인으로 페키징 한다.
  • spring-boot-maven-plugin은 Maven에서 Spring Boot 지원을 제공한다.
    실행 가능한 jar 또는 war 아카이브를 패키 징하고 "제자리에서"응용 프로그램 실행한다.

- Application EntryPoint Class

package com.kakao.daehwan;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootStudyApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootStudyApplication.class, args);
	}

}

 

  • ★@SpringBootApplictaion( 3개의 annotation을 대신한다. ) 
    • @ Coniguration : 설정 파일이다., 
    • @ComponentScan: 이 클래스에 정의되어있는 빈들을 쭉 스캔하라, 
    • @EnableAutoConiguration: 자동 설정을 활성화하라

- MVC

1) HomeController.java

package com.kakao.daehwan.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {
	@GetMapping("/")
	public String home(Model model) {
		model.addAttribute("message", "스프링부트 공부중~");
		return "index";
	}
}
  • 전에 사용했던 방식
    - @RequestMapping(value=“/”, method = RequestMethod.GET).
    대신 @GetMapping을 사용

2) src/main/resources/templates/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
	<div> th:text = "${message}"</div>
</body>
</html>
  • 여기서 return이 되면 이제는 jsp를 사용하지 않으므로 view로써 사용되는 html로 간다.(index.html)
    보통 html을 사용한다 하면 정적인 페이지이라고 생각할 순 있지만 이 페이지를 보면 들어간 값에 따라서 달라지기 때문에 동적인 페이지이다.

3) SecurityConfig.java

- 의존성 추가

 <dependency

 <groupId> org.springframework.boot </groupId>groupId>org.springframework.boot</groupId>

 <artifactId> spring-boot-starter-security </artifactId>artifactId>spring-boot-starter-security</artifactId>

 </dependency>

- 설정

package com.kakao.daehwan.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Override
	protected void configure(HttpSecurity http) throws Exception{
		http.authorizeRequests()
			.anyRequest()
			.permitAll()
			.and()
			.csrf().disable();
	}
}

4) applications.properties

  • 스프링 부트 (Spring Boot)는 속성 파일에 대한 설정 접근법에 대한 전형적인 관습을 적용
  • Spring Boot는 "application.properties"파일이라는 기본 응용 프로그램 속성을 도입.
  • application.properties 파일을 "src / main / resources"디렉터리에 넣어야 한다.
  • ex) server.port = 9000

5) Logging

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>

<root level="INFO">
     <appender-ref ref="STDOUT" />
</root>

<logger name="com.kakao.daehwan" level="DEBUG" >
</logger>
</configuration>
  • ConsoleAppender를 사용하여 pattern에 맞춰 콘솔에 띄운다 설정
  • root level은 INFO, 내가 만든 패키지 level은 DEBUG로 주었다.

6) Running Application

- IDE: Run As -> Spring Boot App

- command line: mvn clean package -> java -jar target springBootStudy-0.0.1-SNAPSHOT.jar

 

SpringBoot에서 JPA 사용하기!!!( spring data JPA )

- ORM 업그레이드 과정
Spring jdbc -> hiberate -> spring data JPA

 

- Spring Data JPA

  • JPA (Java Persistence API)는 ORM (Object Relational Mapping) 프레임 워크.
  • Spring 프레임 워크는 보다 쉬운 방법으로 ORM 프레임 워크와 통합할 수 있는 Spring ORM 모듈을 제공
  • JPA를 사용하여 관계형 데이터베이스 작업을 위한 모듈 중 하나이다.
  • CRUD 작업, Pagination and Sorting을 즉시 지원하는 다양한 Repository abstractions를 제공
  • JPA에서 제공하는 인터페이스
    - CrudRepository: CRUD 기능 제공
    - PagingAndSortingRepository: pagination과 sorting records를 수행하는 메서드 제공
    - JpaRepositoryflushing the persistence context, delete record 같은 JPA 관련 메서드 제공
    각각 위에 것을 상속받는다. ( JpaRepository는 PagingAndSortingRepository를 상속받고 Pa... tory는 CrudRepository를 상속받는다. )
  • 만약 JpaRepository나 Paging... tory의 기능이 필요 없는 경우 CrudRepository를 사용하면 된다.

※ 클래스 대신 인터페이스를 사용하는 이유는 무엇인가?

: 클래스 간의 결합도를 줄이기 위해서!

 

- 활용 예제

  • PagingAndSortingRepository에서 findALL(pageable) - 결과에 대해서 페이 지화 해줌
  • JpaRepositoy는 위에 두 인터페이스를 상속받았기 때문에 가장 무겁다.
    -> 사용할 기능의 범위에 대해서 어떠한 인터페이스를 사용할 것인지 선택한다.
  • sorting 하는 방법
    Sort sort = new Sort(Direction.ASC, "name"); -> name에 대해서 오름차순으로 한다.
    List users = userRepository.findAll(sort); ->라는 인자를 넣어주면 repository에서 쭉 정렬해준다.

- Hibernate와 Spring Data JPA CRUD 구현 차이

  • Hibernate: CRUD 각각의 메서드에는 SessionFactory를 불러오는 코드와 받아온 값을 넣어주는 코드가 존재.
  • Spring Data JPA: 하나의 인터페이스를 정의하는 것으로 끝!
public interface ProductRepository 
		extends CrudRepository<Product, Integer> {
}

==> 어떤 모델에 대해서 crud를 할 것인지 id의 타입만 지정해주면 내부적으로 crud를 구현해준다.

 

 

Spring data JPA 사용 예시 코드

- 의존성 추가

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>


<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>

- application.properties

### Default server port #########
server.port=9000

spring.datasource.url=jdbc:mysql://localhost:3306/eStore
spring.datasource.username=root
spring.datasource.password=1234
spring.jpa.hibernate.ddl-auto=create

- Entity

@Entity
@Getter
@Setter
@NoArgsConstructor
public class Customer implements Serializable {

private static final long serialVersionUID = -3491880136674997165L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="customer_id")
private Long id;
 
@Column(name="firstname")
private String firstName;
 
@Column(name="lastname")
private String lastName;

public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}

- JPA Repository interface

이름을 정할 때 내 마음대로 해도 되긴 하지만 JPA를 사용할 경우 이름으로 DAO 대신에 Repository를 사용한다.

public interface CustomerRepository 
			extends CrudRepository<Customer, Long>{

	List<Customer> findByLastName(String lastName);

}
  • spring Data JPA는 즉시 CRUD 작업을 제공할 뿐만 아니라 메서드 이름을 기반으로 동적 쿼리 생성도 지원한다.
  • 이 경우에는 Customer이라는 모델을 사용하고 속성 Id의 자료형은 Long이다라고 설정한 것.
  • 위 코드와 같이 List <Customer> findByLastName (String lastName) 메서드를 정의하면 스프링 데이터는 자동으로 where 절을 "where lastName =? "로 사용하면서 쿼리를 생성한다.
  • JPA는 메서드 이름을 보고 기능을 유추 -> 동적인 sql문을 만들어서 메서드를 구현해준다.
    (모델의 속성들을 확인한 후 그것을 토대로 유추)
  • 심지어 @Repository라는 어노테이션도 안 달어줘도 된다.
  • MySQL 드라이버를 설정했으므로 SpringBoot는 자동으로 데이터 소스를 등록한다.
  • spring-boot-starter-data-jpa 의존성을 추가함에 따라 SpringBoot AutoConfiguration은 적절한 기본값으로 LocalContainerEntityManagerFactoryBean, TransactionManager 등과 같은 JPA 관련 Bean을 자동으로 생성한다. 

※ 결론: spring-boot-starter-data-jpa을 사용하면 관련 빈들을 등록하고 자동으로 설정을 해준다.

 

- Rest Controller

@RestController
@RequestMapping("/api")
public class CustomerController{

	static Logger logger = LoggerFactory.getLogger(CustomerController.class);
    
    @Autowired
    CustomerRepository repository;
    
    @GetMapping(value="/customers", produces=MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<List<Customer>> getAll(){
    
    	logger.debug("고객 전부 호출");
        
        List<Customer> list = new ArrayList<>();
        Iterable<Customer> customers = repository.findAll();
        
        customers.forEach(list::add);
        
        return new ResponseEntity<List<Customer>>(list, HttpStatus.OK);
    }
    ...
}

 

References

https://spring.io/guides/gs/accessing-data-jpa/

 

Spring

Level up your Java code and explore what Spring can do for you.

spring.io

https://spring.io/guides/tutorials/bookmarks/

 

Spring

Level up your Java code and explore what Spring can do for you.

spring.io

 

'Spring > 이론' 카테고리의 다른 글

Test  (0) 2020.06.03
JPQL  (0) 2020.05.17
Restful Web Service with Spring  (0) 2020.04.20
Restful Web Service  (0) 2020.04.19
Hibernate with Spring  (0) 2020.04.19

댓글