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를 수행하는 메서드 제공
- JpaRepository : flushing 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/
https://spring.io/guides/tutorials/bookmarks/
'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 |
댓글