이번시간에는 앞서 다뤘던 프로젝트에 H2 DataBse를 연동 해 보겠습니다.
H2 Database
H2 Database는 최소한의 리소스로 실행 가능한 경량 DB로서 지금과 같은 학습용 또는 테스트 용도로 사용하기에 알맞은 DB입니다.
서버 요구사항도 낮고, 하나의 jar파일을 실행하기만 하면 DB를 사용할 수 있다는 장점이 있습니다.
Downloads
Downloads Version 2.1.214 (2022-06-13) Windows Installer (SHA1 checksum: 5f7cd83d394df5882ed01553935463a848979f29) Platform-Independent Zip (SHA1 checksum: 5ff027217098bf6c800ef96b98f3a381b320e53d) Version 2.1.212 (2022-04-09) Windows Installer (SHA1 check
www.h2database.com
저는 가장 최신버전인 2.1.214 버전을 사용하겠습니다.
위 주소에서 Platform-Independent.zip을 다운로드하여 원하는 위치에 압축을 해제합니다.
실행하기 위해서는
CMD에서 압축 푼 파일을 기준으로 /bin에 접속하여
h2.bat 명령어를 사용 해 주면 됩니다.
해당 명령어를 사용하기 위해서는 java가 설치되어 있어야 합니다.
실행하면 아래와 같은 화면이 나오게 됩니다.
지정한 설정 및 설정 이름은 Generic H2 (Server)로 선택합니다.
이후 연결을 눌렀을 때 아래와 같은 에러가 발생했습니다.
해당 에러는 위 경로에 데이터베이스가 생성되지 않았기 때문입니다.
💡 참고 h2 1.4.198 이후 버전부터는 보안문제로 데이터베이스가 자동으로 생성되지 않기 때문에 데이터베이스를 직접 생성하지 않으면 위와같은 에러가 발생합니다. |
위 사진과 같이 Generic H2 (Embedded)로 설정한 후 연결을 누르면
데이터베이스가 자동으로 생성되고, 콘솔에 연결됩니다.
해당 경로에 Data Base File이 생성된 것도 확인할 수 있습니다.
build.gradle에 라이브러리 추가
스프링에서 H2로 접속하기 위한 설정을 해주어야 합니다.
build.gradle파일에 아래와 같이 H2라이브러리 설정을 추가합니다.
dependencies {
// 생략
runtimeOnly("com.h2database:h2")
// 생략
}
application.yml에 접속 정보 추가
application.yml에 H2 Database의 접속 정보를 설정합니다.
url : DB 접속 주소
driver-class-name : DB 접속을 위해 사용할 디바이스 드라이버
username : DB접속 user 명
database-platform : jpa에서 사용할 DB로 H2를 세팅하겠다는 뜻
properties.hibernate.hbm2ddl.auto : 시작하면서 도메인 객체 구성과 DB의 스키마를 비교해 필요한 테이블이나 컬럼이 없을 경우 도메인 객체에 맞춰 DB 스키마를 변경
showSql : jpa가 실행하는 쿼리를 console 로그로 출력하기 위한 설정
H2에 저장된 table의 데이터를 다루는 코드 작성
우선 table 데이터 맵핑을 위한 Model을 하나 생성합니다.
com.ziaho.ziahorestapi 패키지 하위에 entity 라는 package를 생성하고 그 안에 User라는 class를 하나 생성합니다.
entity란 DB table 간의 구조와 관계를 jpa가 요구하는 형태로 만든 model입니다.
table에 있는 컬럼 값들의 정보, table간의 연관 관계(1:N, N:1 등) 정보를 담고 있습니다.
Lombok 어노테이션을 사용하면 소스를 간단하게 구성 할 수 있으므로 편리합니다.
package org.ziaho.ziahorestapi.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Builder // builder를 사용할 수 있게 됩니다.
@Entity // jpa entity임을 알립니다.
@Getter // user 필드값의 getter를 자동으로 생성합니다.
@NoArgsConstructor // 인자가 없는 생성자를 자동으로 생성합니다.
@AllArgsConstructor // 인자를 모두 갖춘 생성자를 자동으로 생성합니다.
@Table(name = "user") // 'user' 테이블과 매핑됨을 알립니다.
public class User {
@Id // primaryKey임을 명시합니다.
@GeneratedValue(strategy = GenerationType.IDENTITY)
// pk생성전략을 DB에 위임한다는 의미.
// primaryKey 필드를 auto_increment로 설정하는 경우와 같다.
private long msrl;
@Column(nullable = false, unique = true, length = 30)
// uid colum을 명시, null값이 될 수 없으며(필수값) 유니크한 필드이고 최대 길이는 30
private String uid;
@Column(nullable = false, length = 100)
// name column을 명시, null값이 될 수 없으며(필수값) 최대 길이는 100
private String name;
}
Lombok을 사용하지 않는다면 생성자, 변수들에 대한 getter / setter를 직접 설정 해 주어야 합니다.
Table에 질의를 요청하기 위한 Repository 생성
생성한 entity를 이용해서 Table에 질의를 요청하기 위한 Repository를 생성합니다.
org.ziaho.ziahorestapi 하위에 repo package를 생성하고, 하위에 UserJpaRepo 라는 이름의 interface를 하나 생성합니다.
package org.ziaho.ziahorestapi.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.ziaho.ziahorestapi.entity.User;
public interface UserJpaRepo extends JpaRepository<User, Long> {
}
Interface
- 동일한 목적 하에 동일한 기능을 수행하게끔 강제하는 역할
- Java의 다형성을 극대화 하여 개발코드의 수정을 줄이고, 유지보수성을 높여준다.
Controller에 Repository 설정
Jpa Repo를 사용하는 Controller를 하나 생성합니다.
org.ziaho.ziahorestapi.controller 하위에 v1 package를 만들고 UserController를 생성합니다.
package org.ziaho.ziahorestapi.controller.v1;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.ziaho.ziahorestapi.entity.User;
import org.ziaho.ziahorestapi.repo.UserJpaRepo;
import java.util.List;
@RequiredArgsConstructor // class상단에 선언하면 class내부에 final로 선언된 객체에 대해서 Constructor Injection(의존성 주입)을 수행합니다.
// 해당 어노테이션을 사용하지 않고 선언된 객체에 @Autowired를 사용해도 됩니다.
@RestController // 결과 데이터를 JSON형식으로 내보냅니다.
@RequestMapping(value = "/v1") // api resource를 버전별로 관리하기 위해 /v1 을 모든 리소스 주소에 적용되도록 합니다.
public class UserController {
private final UserJpaRepo userJpaRepo;
@GetMapping(value = "/user")
public List<User> findAllUser() { // user테이블에 있는 데이터를 모두 읽어옵니다. 데이터가 한개 이상 일 수 있으므로 리턴타입은 List<User>로 선언합니다.
// Jpa를 사용하면 기본적으로 CRUD에 대해서는 별다른 설정없이 쿼리를 질의할 수 있도록 메소드를 지원합니다.
// select * from user와 같음
return userJpaRepo.findAll();
}
@PostMapping(value = "/user")
public User save() {
// user 테이블에 데이터 1건을 입력합니다.
// Jpa를 사용하면 기본적으로 CRUD에 대해서는 별다른 설정없이 쿼리를 질의할 수 있도록 메소드를 지원합니다.
// insert into user(msrl, name, uid) values(null, ?, ?)와 같음
User user = User.builder()
.uid("test1@test.com")
.name("테스트1")
.build();
return userJpaRepo.save(user);
}
}
@RequireArgsContructor
class상단에 선언하면 class내부에 final로 선언된 객체에 대해서 Constructor Injection(의존성 주입)을 수행합니다.
@RestController
결과 데이터를 JSON형식으로 내보냅니다.
@RequestMapping(value = "/v1")
api resource를 버전별로 관리하기 위해 /v1 을 모든 리소스 주소에 적용되도록 처리합니다.
@GetMapping(value = "/user")
user테이블에 있는 데이터를 모두 읽어옵니다. 데이터가 한개 이상 일 수 있으므로, 리턴타입은 List<User>로 선언합니다.
Jpa를 사용하면 기본적으로 CRUD에 대해서는 별다른 설정없이 쿼리를 질의할 수 있도록 메소드를 지원합니다.
select * from user와 같음
userJpaRepo.findAll()
Jpa를 사용하면 기본적으로 CRUD에 대해서는 별다른 설정없이 쿼리를 질의할 수 있도록 메소드를 지원합니다.
insert into user(msrl, name, uid) values(null, ?, ?)와 같음
@PostMapping(value = "/user")
user 테이블에 데이터 1건을 입력합니다.
Jpa를 사용하면 기본적으로 CRUD에 대해서는 별다른 설정없이 쿼리를 질의할 수 있도록 메소드를 지원합니다.
insert into user(msrl, name, uid) values(null, ?, ?)와 같음
결과 확인
결과확인을 위해 프로젝트를 구동시켰는데
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "..."; expected "identifier"; SQL statement:
다음과 같은 에러가 발생하였다...
해당 에러는 도메인안에 order, group와 같은 예약어가 있으면 테이블이 생성될 수 없어 에러가 발생한다고 한다.
내가 만든 Entity에는 예약어가 없는데 라고 생각했으나
H2 Database 2.1.212 버전 이후부터는 user 키워드가 예약어로 지정되어있다고 한다...!
따라서 해결방법으로는
1. H2의 버전을 2.1.212 이전 버전으로 변경
2. application.yml url에 NON_KEYWORDS=USER 설정 추가
3. table 명 변경
저는 2번째 방법으로 해결하였습니다!!
웹 브라우저를 열고 localhost:8080/v1/user 를 실행합니다.
현재는 데이터가 없으므로 []만 리턴됩니다.
데이터 입력을 위해 POST 방식으로 localhost:8080/v1/user 를 실행합니다.
웹 브라우저에서의 입력으로는 GET 방식만 호출 할 수 있기 때문에 테스트를 위해
POSTMAN이라는 프로그램을 아래 링크에서 다운받아 사용하겠습니다.
Download Postman | Get Started for Free
Download Postman | Get Started for Free
Try Postman for free! Join 25 million developers who rely on Postman, the collaboration platform for API development. Create better APIs—faster.
www.postman.com
설치 이후 아래와 같이 설정한다.
Basic Auth를 활용하는 이유는 프로젝트 생성시에 Spring Security Api를 포함하였기 때문이다.
GET 방식은 정상적으로 값을 가져온다.
POST 방식은?
401 에러와 함께 작동하지 않는다....
내용을 찾아보니 프로젝트 생성할때 지정했던 Spring Security 때문에 발생하는 문제인것 같다.
우선은 테스트를 위해 build.gradle에서 Spring Security 부분을 모두 주석처리 해 주었다.
(Spring Security Api를 사용하면서도 에러가 발생하지 않는 방법을 찾아 볼 예정 ㅠ)
그랬더니
springboot로 Rest api 만들기(3) H2 Database 연동 (tistory.com)
springboot로 Rest api 만들기(3) H2 Database 연동
전체 소스코드 https://github.com/GHGHGHKO/Springboot/tree/main/pepega_chapter_3 GitHub - GHGHGHKO/Springboot: 블로그에 업로드 된 소스코드 블로그에 업로드 된 소스코드. Contribute to GHGHGHKO/Springboot development by creating a
pepega.tistory.com
해당 글을 참고하여,
Spring Security를 적용하기 위해서는 추가적인 설정(Config)가 필요하다는 사실을 알았다.
org.ziaho.ziahoretapi 아래에 config package를 생성하고, WebSecurityConfig 클래스를 생성한다.
하지만 스피링 버전이 향상됨에 따라 WebSecurityConfigurerAdapter가 deprecated 되었고, 설정의 방법이 달라졌다.
Deprecated된 WebSecurityConfigurerAdapter, 어떻게 대처하지? (velog.io)
Deprecated된 WebSecurityConfigurerAdapter, 어떻게 대처하지?
스프링 버전이 업데이트 됨에 따라 WebSecurityConfigurerAdapter와 그 외 몇 가지들이 Deprecated 됐습니다.스프링에서는 다른 방식으로 시큐리티 설정을 권장하고 있는 듯 해보였는데요. 방식이 바뀐 탓
velog.io
WebSecurityConfigurerAdapter를 상속받지 않고 모두 Bean으로 등록하여 사용한다.
package org.ziaho.ziahorestapi.config;
import org.springframework.context.annotation.Bean;
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.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpS) throws Exception {
httpS.cors().and().csrf().disable();
return httpS.build();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList("*"));
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
}
위 Config 파일을 설정하고 나면
정상적으로 데이터가 등록이 된다.
위 소스는 임시로 작성한 내용이고, 추후 포스팅 예정인 SpringSecurity를 본격적으로 활용하는 포스팅에서 수정하도록 하겠다.
===== springSecurity를 주석처리 한 경우 ========
잘 된다!
POST 방식으로 입력한 이후 다시 GET 방식으로 데이터를 조회 해 보니
데이터가 1건 있으므로 해당 데이터가 출력된다!
DB Table 자동 생성
이번 실습에서는 테이블을 따로 생성해 주지 않았는데도
POST방식으로 전송 했을 때,
User 테이블 생성 시 오류가 발생하지 않고
데이터기 잘 입력 되었다.
설정을 따로 해주지 않으면 entity(package)의 정보를 토대로 서버 실행 시
테이블이 자동 생성되기 때문이다.
개발 시에는 편리하지만
서비스에 사용할 경우에 테이블의 자동 생성은 위험할 수 있다.
아래와 같이 설정하여 자동 생성되지 않도록 해야한다.
application.yml
properties.hibernate.hbm2ddl.auto: none
hbm2ddl.auto
- create - 서버 시작할 때 모든 테이블 생성
- create-drop - 서버 시작할 때 테이블 생성, 종료시 삭제
- update - 서버 시작 시 entity, table 비교 후 변경된 내용 반영, table이 없으면 새로 생성
- validate - 서버 시작 시 entitiy, table 비교하여 다르면 시작하지 않고 종료
- none - 아무런 처리를 하지 않음
실습 프로젝트에서는 update로 설정 해 두었기 때문에 테이블이 자동으로 생성 된 것입니다.
출처
SpringBoot2로 Rest api 만들기(3) – H2 Database 연동 (daddyprogrammer.org)
SpringBoot2로 Rest api 만들기(3) – H2 Database 연동
이번 시간에는 SpringBoot에 Database를 연동하는 방법을 실습합니다. 실습은 H2 database로 진행하겠습니다. H2 Database H2는 최소한의 리소스로 실행 가능한 경량 DB로서 테스트 용으로 사용하기 알맞은 DB
www.daddyprogrammer.org
codej99/SpringRestApi: SpringBoot2, SpringSecurity, JWT, Stateless Restful API (github.com)
GitHub - codej99/SpringRestApi: SpringBoot2, SpringSecurity, JWT, Stateless Restful API
SpringBoot2, SpringSecurity, JWT, Stateless Restful API - GitHub - codej99/SpringRestApi: SpringBoot2, SpringSecurity, JWT, Stateless Restful API
github.com
H2 Database 설치, 서버 실행, 접속 방법 (Windows, MacOS) (tistory.com)
H2 Database 설치, 서버 실행, 접속 방법 (Windows, MacOS)
H2 Database 설치, 서버 실행, 접속 방법 (Windows, MacOS) H2 데이터베이스는 설치가 필요 없고 용량이 매우 가벼우며 웹용 콘솔(쿼리툴)을 제공하여 개발용 로컬 DB로 사용하기 좋은 데이터베이스이다. H
atoz-develop.tistory.com
'Spring Boot' 카테고리의 다른 글
SpringBoot를 활용한 Rest api 만들기(6) - ControllerAdvice를 이용한 Exception처리 (0) | 2023.03.06 |
---|---|
SpringBoot를 활용한 Rest api 만들기(5) - API 인터페이스 및 결과 데이터 구조 설계 (0) | 2023.03.04 |
SpringBoot를 활용한 Rest api 만들기(4) - Swagger Api 문서 자동화 설정하기 (0) | 2023.02.27 |
SpringBoot를 활용한 Rest api 만들기(2) - Hello, World 찍기 (0) | 2023.02.24 |
SpringBoot를 활용한 Rest api 만들기(1) - Intellij, start.spring.io, 프로젝트 생성 (0) | 2023.02.23 |