BoB 12기 프로젝트에서의 User Management를 위한 1차 Web-WAS / DB에 대한 기능 요구사항입니다.
# 1 | Spring ㅣ User Entity, Controller, Repository, Service 구현 |
# 2 | Node_Database, Node_Table, Node_Testdata를 생성하는 sql 파일 구현 |
# 3 | Spring + JPA + MySQL 연동 |
# 4 | Spring Dockerfile 작성 및 docker hub push |
# 5 | MySQL docker-compose.yml 파일 작성 및 최종 연동 테스트 수행 |
# 6 | hostname과 ip 주소를 추출 후 Database에 넣는 Bash 스크립트 개발 |
# 7 | 각 프로세스에 대한 Command 정리 및 윈도우 환경 테스트 수행 |
1. User Entity, Controller, Repository, Service 구현
# User Entity
@Entity
@Table(name="users")
@Getter @Setter
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NonNull
@Column(unique = true, length = 10)
private String hostname;
@NonNull
@Column(unique = true, length = 15)
private String ip;
}
# UserRepository
@Repository
@RequiredArgsConstructor
public class UserRepository {
private final EntityManager em;
public void save(User user) { this.em.persist(user); }
public User findOne(Long id) { return (User)this.em.find(User.class, id); }
public List<User> findAll() {
return this.em.createQuery("select u from User u", User.class).getResultList();
}
public List<User> findByHostname(String hostname) {
return this.em.createQuery("select u from User u where u.hostname = :hostname", User.class).setParameter("hostname", hostname).getResultList();
}
}
# UserService
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
@Transactional
public Long join(User user) {
// validate 필요
this.userRepository.save(user);
return user.getId();
}
private void validateDuplicateUser(User user) {
List<User> findUsers = this.userRepository.findByHostname(user.getHostname());
if(!findUsers.isEmpty()) {
throw new IllegalStateException("Already Exists");
}
}
public List<User>findUsers() {
return this.userRepository.findAll();
}
public User findOne(Long id) {
return this.userRepository.findOne(id);
}
}
# UserController
@Controller
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("/users")
public String list(Model model) {
List<User> users = this.userService.findUsers();
model.addAttribute("users", users); // test
return "users/userList";
}
}
# GET 요청 결과
2. sql 파일 작성하여 Database, Table, 테스트 데이터 구현
DB, Table, 가데이터를 작성하는 sql 파일을 구현합니다. 추후 docker-compose.yml 파일의 Volume 설정을 통해 이 파일을 로컬 환경에서 도커 컨테이너로 전달합니다.
우선 로컬 환경에서 설치한 MySQL에서 init_db.sql을 실행하여 DB, Table, 가데이터를 설정합니다.
SOURCE {PATH}/init_db.sql
# init_db.sql
DROP DATABASE IF EXISTS user_info;
CREATE DATABASE user_info DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
USE user_info;
DROP TABLE IF EXISTS users;
CREATE TABLE users (
id TINYINT NOT NULL AUTO_INCREMENT,
hostname VARCHAR(10) NOT NULL,
ip VARCHAR(15) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnODB DEFAULT CHARSET=utf8;
INSERT INTO users (hostname, ip) VALUES ('lee', '111.111.111.111');
INSERT INTO users (hostname, ip) VALUES ('young', '222.222.222.222');
INSERT INTO users (hostname, ip) VALUES ('jun', '333.333.333.333');
3. Spring + JPA + MySQL 연동
MySQL과 Spring JPA 연동을 위해 application.properties에 정의합니다.
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# {db_url}:{db_port}/{db_name}?serverTimezone=
spring.datasource.url=jdbc:mysql://localhost:3306/user_info?serverTimezone=Asia/Seoul
# username, password
spring.datasource.username=root
# hibernate가 실행한 모든 sql문 콘솔 출력
spring.jpa.properties.hibernate.show_sql=true
# sql문 가독성 있게 표현
spring.jpa.properties.hibernate.format_sql=true
# mysql 사용
spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
# 로깅 레벨
logging.level.org.hibernate=info
# 디버깅 정보 출력
spring.jpa.properties.hibernate.user_sql_comments=true
4. Spring Dockerfile 작성 및 docker hub push
DockerHub에 올리기 위해 project의 가장 상위에 Dockerfile을 작성합니다.
FROM openjdk:11
WORKDIR /usr/src/app
COPY ./build/libs/manage-0.0.1-SNAPSHOT.jar ./build/libs/manage-0.0.1-SNAPSHOT.jar
CMD ["java", "-jar", "./build/libs/manage-0.0.1-SNAPSHOT.jar"]
소스 코드 변경하는 경우 다시 빌드할 때 문제가 발생합니다. 현재 도커 컨테이너로 어플은 실행하는 과정은 다음과 같습니다.
① 도커 파일 작성
② 도커 이미지 생성
③ 도커 컨테이너 생성 후 앱 실행
이때 변경된 소스코드를 반영하여 어플리케이션을 실행하기 위해서는
jar 파일을 다시 생성하고,
이미지를 다시 생성하고,
컨테이너를 다시 실행해야 합니다.
jar 파일의 생성은 어쩔 수 없지만, jar 파일이 변경되었다고 해서 Docker Image 자체를 다시 생성하고, 컨테이너를 다시 생성하는 것은 비효율적입니다. 이에 Dockerfile의 COPY 옵션이 아닌, 컨테이너 실행 시(docker run)의 Volume 옵션을 통해 로컬 경로에 존재하는 파일들을 도커 컨테이너 내부에서 사용할 수 있도록 합니다.
docker run -p 8080:8080 -v 참조할경로(로컬):참조하는경로(컨테이너내부) 이미지식별자
1차 개발에서는 반영하지는 않았으나, 추후 논의해 볼 사항입니다.
이제 이미지로 빌드하고, Tag를 수정한 후 DockerHub에 Push합니다.
// Dockerfile 디렉터리 경로에서 실행
docker build . -t gwooteam-springbootapp --platform linux/amd64
// 이미지 Tag 수정
docker tag gwooteam-springbootapp james4239/gwooteam:1.0.1
// 이미지 Dockerhub PUSH
docker push james4239/gwooteam:1.0.1
// 로컬에서 sql 팡일로 데이터베이스 구축하기
sudo mysql -u root -p < init_db.sql
7. 출처
https://ttl-blog.tistory.com/761#Mac%20M1%20에서는%20이런%20오류가%20발생해요%20
'보안 > BoB 프로젝트 기술 학습' 카테고리의 다른 글
QUIC 프로토콜과 TLS 암호화(대칭키 계산 방식) (0) | 2023.10.28 |
---|