From f7daa27a77ee2e92bd2405c425a8e1a235d354b2 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Tue, 6 May 2025 23:02:27 +0900 Subject: [PATCH 01/16] =?UTF-8?q?feat=20:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blog/domain/user/dto/UpdateProfileImageRequest.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/java/com/blog/domain/user/dto/UpdateProfileImageRequest.java diff --git a/src/main/java/com/blog/domain/user/dto/UpdateProfileImageRequest.java b/src/main/java/com/blog/domain/user/dto/UpdateProfileImageRequest.java new file mode 100644 index 00000000..c8f1aeb7 --- /dev/null +++ b/src/main/java/com/blog/domain/user/dto/UpdateProfileImageRequest.java @@ -0,0 +1,9 @@ +package com.blog.domain.user.dto; + +public class UpdateProfileImageRequest { + private String profileImageUrl; + + public String getProfileImageUrl() { + return profileImageUrl; + } +} From 6131bfc8f4e9f9fd60cd737318a264037827d4ef Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Tue, 6 May 2025 23:03:39 +0900 Subject: [PATCH 02/16] =?UTF-8?q?feat=20:=20=EC=9C=A0=EC=A0=80=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/user/dto/UserProfileResponse.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/main/java/com/blog/domain/user/dto/UserProfileResponse.java diff --git a/src/main/java/com/blog/domain/user/dto/UserProfileResponse.java b/src/main/java/com/blog/domain/user/dto/UserProfileResponse.java new file mode 100644 index 00000000..962a6362 --- /dev/null +++ b/src/main/java/com/blog/domain/user/dto/UserProfileResponse.java @@ -0,0 +1,51 @@ +package com.blog.domain.user.dto; + +import com.blog.domain.user.domain.User; +import java.time.LocalDateTime; +import java.util.UUID; + +public class UserProfileResponse { + private UUID id; + private String nickname; + private String email; + private String profileImageUrl; + private LocalDateTime createdAt; + + public UserProfileResponse(UUID id, String nickname, String email, String profileImageUrl, LocalDateTime createdAt) { + this.id = id; + this.nickname = nickname; + this.email = email; + this.profileImageUrl = profileImageUrl; + this.createdAt = createdAt; + } + + public static UserProfileResponse from(User user) { + return new UserProfileResponse( + user.getId(), + user.getNickname(), + user.getEmail(), + user.getProfileImageUrl(), + user.getCreatedAt() + ); + } + + public UUID getId() { + return id; + } + + public String getNickname() { + return nickname; + } + + public String getEmail() { + return email; + } + + public String getProfileImageUrl() { + return profileImageUrl; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } +} From 2aa6791874899a357698013225fb3a6dae0d205b Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Tue, 6 May 2025 23:05:49 +0900 Subject: [PATCH 03/16] =?UTF-8?q?feat=20:=20=EB=8C=93=EA=B8=80=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blog/domain/comment/repository/CommentRepository.java | 6 ++++++ .../com/blog/domain/comment/service/CommentService.java | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/main/java/com/blog/domain/comment/repository/CommentRepository.java b/src/main/java/com/blog/domain/comment/repository/CommentRepository.java index 2cb1c151..fcebe34d 100644 --- a/src/main/java/com/blog/domain/comment/repository/CommentRepository.java +++ b/src/main/java/com/blog/domain/comment/repository/CommentRepository.java @@ -66,4 +66,10 @@ private RowMapper commentRowMapper() { rs.getTimestamp("updated_at").toLocalDateTime() ); } + + public List findByAuthorId(UUID authorId) { + String sql = "SELECT * FROM comment WHERE author_id = ?"; + return jdbcTemplate.query(sql, commentRowMapper(), authorId.toString()); + } + } diff --git a/src/main/java/com/blog/domain/comment/service/CommentService.java b/src/main/java/com/blog/domain/comment/service/CommentService.java index eca0ebbd..f4de874a 100644 --- a/src/main/java/com/blog/domain/comment/service/CommentService.java +++ b/src/main/java/com/blog/domain/comment/service/CommentService.java @@ -54,4 +54,12 @@ public void updateComment(UUID id, CommentRequest request) { public void deleteComment(UUID id) { commentRepository.deleteById(id); } + + public List getCommentsByAuthor(UUID authorId) { + return commentRepository.findByAuthorId(authorId) + .stream() + .map(CommentResponse::from) + .collect(Collectors.toList()); + } + } From 021510d94c1bdc22e6d024c5855bc6cfd585d3c0 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Tue, 6 May 2025 23:06:10 +0900 Subject: [PATCH 04/16] =?UTF-8?q?feat=20:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/blog/domain/post/repository/PostRepository.java | 6 ++++++ .../java/com/blog/domain/post/service/PostService.java | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/main/java/com/blog/domain/post/repository/PostRepository.java b/src/main/java/com/blog/domain/post/repository/PostRepository.java index f3f90bc3..eaae4eda 100644 --- a/src/main/java/com/blog/domain/post/repository/PostRepository.java +++ b/src/main/java/com/blog/domain/post/repository/PostRepository.java @@ -67,4 +67,10 @@ private RowMapper postRowMapper() { rs.getTimestamp("updated_at").toLocalDateTime() ); } + + public List findByAuthorId(String authorId) { + String sql = "SELECT * FROM post WHERE author_id = ?"; + return jdbcTemplate.query(sql, postRowMapper(), authorId); + } + } diff --git a/src/main/java/com/blog/domain/post/service/PostService.java b/src/main/java/com/blog/domain/post/service/PostService.java index 044d8313..eef4b079 100644 --- a/src/main/java/com/blog/domain/post/service/PostService.java +++ b/src/main/java/com/blog/domain/post/service/PostService.java @@ -64,4 +64,12 @@ public void updatePost(UUID id, PostRequest request) { public void deletePost(UUID id) { postRepository.deleteById(id); } + + public List getPostsByAuthor(UUID authorId) { + return postRepository.findByAuthorId(authorId.toString()) + .stream() + .map(PostResponse::from) + .collect(Collectors.toList()); + } + } From ddf62a12aaeec10542120a583c93edfe2acc9655 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Tue, 6 May 2025 23:06:22 +0900 Subject: [PATCH 05/16] =?UTF-8?q?feat=20:=20=ED=9A=8C=EC=9B=90=20=ED=83=88?= =?UTF-8?q?=ED=87=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserController.java | 78 +++++++++++++++++-- .../user/repository/UserRepository.java | 6 ++ .../blog/domain/user/service/UserService.java | 15 +++- 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/blog/domain/user/controller/UserController.java b/src/main/java/com/blog/domain/user/controller/UserController.java index 52eefa15..c1d43d76 100644 --- a/src/main/java/com/blog/domain/user/controller/UserController.java +++ b/src/main/java/com/blog/domain/user/controller/UserController.java @@ -1,18 +1,33 @@ package com.blog.domain.user.controller; +import com.blog.domain.comment.dto.CommentResponse; +import com.blog.domain.comment.service.CommentService; +import com.blog.domain.post.dto.PostResponse; +import com.blog.domain.post.service.PostService; import com.blog.domain.user.domain.User; +import com.blog.domain.user.dto.UpdateProfileImageRequest; +import com.blog.domain.user.dto.UserProfileResponse; +import com.blog.domain.user.service.UserService; import com.blog.global.auth.service.AuthService; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController public class UserController { private final AuthService authService; + private final UserService userService; + private final PostService postService; + private final CommentService commentService; - public UserController(AuthService authService) { + public UserController(AuthService authService, UserService userService , PostService postService , CommentService commentService) { this.authService = authService; + this.userService = userService; + this.postService = postService; + this.commentService = commentService; } @GetMapping("/protected-resource") @@ -21,5 +36,58 @@ public ResponseEntity getProtectedResource( User user = authService.getUserInfoFromToken(token); return ResponseEntity.ok(user); } -} + @GetMapping("/me") + public ResponseEntity getMyInfo( + @RequestHeader("Authorization") String token) { + User user = getUserFromToken(token); + return ResponseEntity.ok(UserProfileResponse.from(user)); + } + + @DeleteMapping("/me") + public ResponseEntity> deleteMyAccount( + @RequestHeader("Authorization") String token) { + User user = getUserFromToken(token); + userService.deleteByEmail(user.getEmail()); + + Map response = Map.of("message", "회원 탈퇴가 완료되었습니다."); + return ResponseEntity.ok(response); + } + + @PatchMapping("/me/profile-image") + public ResponseEntity> updateProfileImage( + @RequestHeader("Authorization") String token, + @RequestBody UpdateProfileImageRequest request) { + User user = getUserFromToken(token); + userService.updateProfileImage(user.getEmail(), request.getProfileImageUrl()); + + Map response = new HashMap<>(); + response.put("message", "프로필 이미지가 성공적으로 변경되었습니다."); + response.put("profileImageUrl", request.getProfileImageUrl()); + + return ResponseEntity.ok(response); + } + + private User getUserFromToken(String token) { + User decoded = authService.getUserInfoFromToken(token); + return userService.findUserByEmail(decoded.getEmail()) + .orElseThrow(() -> new RuntimeException("User not found")); + } + + @GetMapping("/me/posts") + public ResponseEntity> getMyPosts( + @RequestHeader("Authorization") String token) { + User user = getUserFromToken(token); + List posts = postService.getPostsByAuthor(user.getId()); + return ResponseEntity.ok(posts); + } + + @GetMapping("/me/comments") + public ResponseEntity> getMyComments( + @RequestHeader("Authorization") String token) { + User user = getUserFromToken(token); + List comments = commentService.getCommentsByAuthor(user.getId()); + return ResponseEntity.ok(comments); + } + +} diff --git a/src/main/java/com/blog/domain/user/repository/UserRepository.java b/src/main/java/com/blog/domain/user/repository/UserRepository.java index 40f372fb..ccc8486f 100644 --- a/src/main/java/com/blog/domain/user/repository/UserRepository.java +++ b/src/main/java/com/blog/domain/user/repository/UserRepository.java @@ -45,6 +45,12 @@ public Optional findById(String id) { return users.stream().findFirst(); } + public void deleteByEmail(String email) { + String sql = "DELETE FROM user WHERE email = ?"; + jdbcTemplate.update(sql, email); + } + + private RowMapper userRowMapper() { return (rs, rowNum) -> new User( UUID.fromString(rs.getString("id")), diff --git a/src/main/java/com/blog/domain/user/service/UserService.java b/src/main/java/com/blog/domain/user/service/UserService.java index 73de8675..1e86e5dd 100644 --- a/src/main/java/com/blog/domain/user/service/UserService.java +++ b/src/main/java/com/blog/domain/user/service/UserService.java @@ -11,15 +11,18 @@ import java.util.Base64; import java.util.Optional; import java.util.UUID; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; @Service public class UserService { private final UserRepository userRepository; + private final JdbcTemplate jdbcTemplate; private static final String SALT = "random_salt_value"; - public UserService(UserRepository userRepository) { + public UserService(UserRepository userRepository, JdbcTemplate jdbcTemplate) { this.userRepository = userRepository; + this.jdbcTemplate = jdbcTemplate; } public void registerUser(String nickname, String password, String email, String profileImageUrl) { @@ -42,4 +45,14 @@ private String hashPassword(String password) { public Optional findUserByEmail(String email) { return userRepository.findByEmail(email); } + + public void deleteByEmail(String email) { + userRepository.deleteByEmail(email); + } + + public void updateProfileImage(String email, String imageUrl) { + String sql = "UPDATE user SET profile_image_url = ?, updated_at = ? WHERE email = ?"; + jdbcTemplate.update(sql, imageUrl, LocalDateTime.now(), email); + } + } From 0a812e33aa218ba0738182f61cb3d7aecf96b947 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Tue, 20 May 2025 19:54:10 +0900 Subject: [PATCH 06/16] =?UTF-8?q?feat=20:=20image=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/blog/domain/image/Image.java | 5 -- .../image/controller/ImageController.java | 23 +++++++++ .../com/blog/domain/image/domain/Image.java | 40 +++++++++++++++ .../blog/domain/image/dto/ImageResponse.java | 27 ++++++++++ .../image/repository/ImageRepository.java | 45 +++++++++++++++++ .../domain/image/service/ImageService.java | 49 +++++++++++++++++++ 6 files changed, 184 insertions(+), 5 deletions(-) delete mode 100644 src/main/java/com/blog/domain/image/Image.java create mode 100644 src/main/java/com/blog/domain/image/controller/ImageController.java create mode 100644 src/main/java/com/blog/domain/image/domain/Image.java create mode 100644 src/main/java/com/blog/domain/image/dto/ImageResponse.java create mode 100644 src/main/java/com/blog/domain/image/repository/ImageRepository.java create mode 100644 src/main/java/com/blog/domain/image/service/ImageService.java diff --git a/src/main/java/com/blog/domain/image/Image.java b/src/main/java/com/blog/domain/image/Image.java deleted file mode 100644 index 0da3b162..00000000 --- a/src/main/java/com/blog/domain/image/Image.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.blog.domain.image; - -public class Image { - -} diff --git a/src/main/java/com/blog/domain/image/controller/ImageController.java b/src/main/java/com/blog/domain/image/controller/ImageController.java new file mode 100644 index 00000000..ada6b212 --- /dev/null +++ b/src/main/java/com/blog/domain/image/controller/ImageController.java @@ -0,0 +1,23 @@ +package com.blog.domain.image.controller; + +import com.blog.domain.image.dto.ImageResponse; +import com.blog.domain.image.service.ImageService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +@RestController +@RequestMapping("/images") +public class ImageController { + private final ImageService imageService; + + public ImageController(ImageService imageService) { + this.imageService = imageService; + } + + @PostMapping("/upload") + public ResponseEntity upload(@RequestParam("file") MultipartFile file) { + ImageResponse response = imageService.upload(file); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/com/blog/domain/image/domain/Image.java b/src/main/java/com/blog/domain/image/domain/Image.java new file mode 100644 index 00000000..edcf2aa7 --- /dev/null +++ b/src/main/java/com/blog/domain/image/domain/Image.java @@ -0,0 +1,40 @@ +package com.blog.domain.image.domain; + +import java.time.LocalDateTime; +import java.util.UUID; + +public class Image { + private UUID id; + private String originalName; + private String storedName; + private String url; + private LocalDateTime createdAt; + + public Image(UUID id, String originalName, String storedName, String url, LocalDateTime createdAt) { + this.id = id; + this.originalName = originalName; + this.storedName = storedName; + this.url = url; + this.createdAt = createdAt; + } + + public UUID getId() { + return id; + } + + public String getOriginalName() { + return originalName; + } + + public String getStoredName() { + return storedName; + } + + public String getUrl() { + return url; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } +} diff --git a/src/main/java/com/blog/domain/image/dto/ImageResponse.java b/src/main/java/com/blog/domain/image/dto/ImageResponse.java new file mode 100644 index 00000000..f4566e9c --- /dev/null +++ b/src/main/java/com/blog/domain/image/dto/ImageResponse.java @@ -0,0 +1,27 @@ +package com.blog.domain.image.dto; + +import com.blog.domain.image.domain.Image; + +import java.util.UUID; + +public class ImageResponse { + private UUID id; + private String url; + + public ImageResponse(UUID id, String url) { + this.id = id; + this.url = url; + } + + public static ImageResponse from(Image image) { + return new ImageResponse(image.getId(), image.getUrl()); + } + + public UUID getId() { + return id; + } + + public String getUrl() { + return url; + } +} diff --git a/src/main/java/com/blog/domain/image/repository/ImageRepository.java b/src/main/java/com/blog/domain/image/repository/ImageRepository.java new file mode 100644 index 00000000..ba133b9d --- /dev/null +++ b/src/main/java/com/blog/domain/image/repository/ImageRepository.java @@ -0,0 +1,45 @@ +package com.blog.domain.image.repository; + +import com.blog.domain.image.domain.Image; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Repository; + +import java.sql.Timestamp; +import java.util.Optional; +import java.util.UUID; + +@Repository +public class ImageRepository { + private final JdbcTemplate jdbcTemplate; + + public ImageRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public void save(Image image) { + String sql = "INSERT INTO image (id, original_name, stored_name, url, created_at) VALUES (?, ?, ?, ?, ?)"; + jdbcTemplate.update(sql, + image.getId().toString(), + image.getOriginalName(), + image.getStoredName(), + image.getUrl(), + Timestamp.valueOf(image.getCreatedAt())); + } + + public Optional findById(UUID id) { + String sql = "SELECT * FROM image WHERE id = ?"; + return jdbcTemplate.query(sql, rowMapper(), id.toString()) + .stream().findFirst(); + } + + private RowMapper rowMapper() { + return (rs, rowNum) -> new Image( + UUID.fromString(rs.getString("id")), + rs.getString("original_name"), + rs.getString("stored_name"), + rs.getString("url"), + rs.getTimestamp("created_at").toLocalDateTime() + ); + } +} diff --git a/src/main/java/com/blog/domain/image/service/ImageService.java b/src/main/java/com/blog/domain/image/service/ImageService.java new file mode 100644 index 00000000..f98fbea7 --- /dev/null +++ b/src/main/java/com/blog/domain/image/service/ImageService.java @@ -0,0 +1,49 @@ +package com.blog.domain.image.service; + +import com.blog.domain.image.domain.Image; +import com.blog.domain.image.dto.ImageResponse; +import com.blog.domain.image.repository.ImageRepository; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.util.UUID; + +@Service +public class ImageService { + private static final String UPLOAD_DIR = System.getProperty("user.dir") + "/uploads/"; + private final ImageRepository imageRepository; + + public ImageService(ImageRepository imageRepository) { + this.imageRepository = imageRepository; + } + public ImageResponse upload(MultipartFile file) { + try { + String originalName = file.getOriginalFilename(); + String ext = originalName.substring(originalName.lastIndexOf(".")); + String storedName = UUID.randomUUID() + ext; + Path storedPath = Path.of(UPLOAD_DIR + storedName); + + Files.createDirectories(storedPath.getParent()); // 디렉토리 없으면 생성 + file.transferTo(storedPath.toFile()); + + String url = "/images/" + storedName; + + Image image = new Image( + UUID.randomUUID(), + originalName, + storedName, + url, + LocalDateTime.now() + ); + + imageRepository.save(image); + return ImageResponse.from(image); + } catch (Exception e) { + throw new RuntimeException("이미지 저장 실패", e); + } + } +} From 6ab305eefb9dacac1f89fd81c7094c082d87f9a7 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Tue, 20 May 2025 20:26:20 +0900 Subject: [PATCH 07/16] =?UTF-8?q?feat=20:=20CICD=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/ci-cd.yml diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 00000000..42ad046b --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,28 @@ +name: Deploy to EC2 + +on: + push: + branches: [ "main" ] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Decode PEM key + run: | + echo "${{ secrets.EC2_KEY }}" | base64 -d > ec2-key.pem + chmod 600 ec2-key.pem + + - name: Deploy to EC2 + run: | + ssh -o StrictHostKeyChecking=no -i ec2-key.pem ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }} << 'EOF' + pkill -f java || true + cd ${{ secrets.PROJECT_NAME }} || git clone https://github.com/${{ github.repository }} ${{ secrets.PROJECT_NAME }} && cd ${{ secrets.PROJECT_NAME }} + git pull origin main + ./gradlew bootJar --no-daemon + java -jar build/libs/*.jar > app.log 2>&1 & + EOF From ba118134c38d124be321facd71b3a7da01d0a70a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9D=80=EC=84=B1?= <166037587+choes0101@users.noreply.github.com> Date: Tue, 20 May 2025 20:32:52 +0900 Subject: [PATCH 08/16] =?UTF-8?q?fix:=20CICD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 42ad046b..74e8bbce 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -2,7 +2,7 @@ name: Deploy to EC2 on: push: - branches: [ "main" ] + branches: [ "조은성/main", "조은성/6주차" ] jobs: deploy: From 0fe2adde48d7a3907b295039515a6065ec76a1c2 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Tue, 20 May 2025 20:55:46 +0900 Subject: [PATCH 09/16] =?UTF-8?q?test=20:=20=EB=B0=B0=ED=8F=AC=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 42ad046b..74e8bbce 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -2,7 +2,7 @@ name: Deploy to EC2 on: push: - branches: [ "main" ] + branches: [ "조은성/main", "조은성/6주차" ] jobs: deploy: From f15ef8ad885832e1f8809705c159f19d5d8d24e4 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Tue, 20 May 2025 23:21:03 +0900 Subject: [PATCH 10/16] =?UTF-8?q?feat=20:=20Dockerfile=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..28ac828d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +# 빌드 환경 +FROM gradle:8.4.0-jdk21 AS builder +WORKDIR /app +COPY . . +RUN ./gradlew bootJar --no-daemon + +# 실행 환경 +FROM eclipse-temurin:21-jdk +WORKDIR /app +COPY --from=builder /app/build/libs/*.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java", "-jar", "app.jar"] From 291c063971e43c4186128e8b9e6cff9084865fbf Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Tue, 20 May 2025 23:46:59 +0900 Subject: [PATCH 11/16] =?UTF-8?q?feat=20:=20docker-compoes.yml=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 4 ++++ docker/docker-compoes.yml | 11 +++++++++++ 2 files changed, 15 insertions(+) create mode 100644 docker/docker-compoes.yml diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 74e8bbce..04abec9d 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -20,6 +20,10 @@ jobs: - name: Deploy to EC2 run: | ssh -o StrictHostKeyChecking=no -i ec2-key.pem ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }} << 'EOF' + sudo apt-get update + sudo apt-get install -y openjdk-21-jdk + java -version + pkill -f java || true cd ${{ secrets.PROJECT_NAME }} || git clone https://github.com/${{ github.repository }} ${{ secrets.PROJECT_NAME }} && cd ${{ secrets.PROJECT_NAME }} git pull origin main diff --git a/docker/docker-compoes.yml b/docker/docker-compoes.yml new file mode 100644 index 00000000..c4ec83df --- /dev/null +++ b/docker/docker-compoes.yml @@ -0,0 +1,11 @@ +version: '3.8' + +services: + blog: + build: . + container_name: blog-app + ports: + - "8080:8080" + environment: + - SPRING_PROFILES_ACTIVE=prod + restart: always From 3b59096661fdccfedf9e72edae3b5608efbc8000 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Mon, 26 May 2025 17:36:00 +0900 Subject: [PATCH 12/16] =?UTF-8?q?fix=20:=20ci-cd.yml=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 39 ++++++++++++++++++++++++++----------- Dockerfile | 5 +---- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 04abec9d..c78e69b3 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -1,4 +1,4 @@ -name: Deploy to EC2 +name: CI/CD to EC2 on: push: @@ -9,9 +9,22 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout code + - name: Checkout uses: actions/checkout@v3 + - name: Docker login + run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and Push Docker Image + run: | + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + -t ${{ secrets.DOCKER_USERNAME }}/blog-app:latest \ + --push . + - name: Decode PEM key run: | echo "${{ secrets.EC2_KEY }}" | base64 -d > ec2-key.pem @@ -20,13 +33,17 @@ jobs: - name: Deploy to EC2 run: | ssh -o StrictHostKeyChecking=no -i ec2-key.pem ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }} << 'EOF' - sudo apt-get update - sudo apt-get install -y openjdk-21-jdk - java -version - - pkill -f java || true - cd ${{ secrets.PROJECT_NAME }} || git clone https://github.com/${{ github.repository }} ${{ secrets.PROJECT_NAME }} && cd ${{ secrets.PROJECT_NAME }} - git pull origin main - ./gradlew bootJar --no-daemon - java -jar build/libs/*.jar > app.log 2>&1 & + docker pull ${{ secrets.DOCKER_USERNAME }}/blog-app:latest + + docker stop blog-app || true + docker rm blog-app || true + + cd ~ + echo "KAKAO_CLIENT_ID=abc123" > .env + echo "KAKAO_CLIENT_SECRET=xyz456" >> .env + + docker run -d -p 8080:8080 \ + --name blog-app \ + --env-file .env \ + ${{ secrets.DOCKER_USERNAME }}/blog-app:latest EOF diff --git a/Dockerfile b/Dockerfile index 28ac828d..772e1f72 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,9 @@ -# 빌드 환경 -FROM gradle:8.4.0-jdk21 AS builder +FROM gradle:8.4.0-jdk21 as builder WORKDIR /app COPY . . RUN ./gradlew bootJar --no-daemon -# 실행 환경 FROM eclipse-temurin:21-jdk WORKDIR /app COPY --from=builder /app/build/libs/*.jar app.jar -EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"] From 6f13c50dda94d913b2cc2c036435479f3289d2cc Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Mon, 26 May 2025 18:05:48 +0900 Subject: [PATCH 13/16] =?UTF-8?q?fix=20:=20ci-cd.yml=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - src/main/resources/application.properties | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/application.properties diff --git a/.gitignore b/.gitignore index 42c1ad51..333fc754 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,5 @@ out/ # 환경 설정 및 민감 파일 .env -application.properties *.key *.pem diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 00000000..4fa1de49 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,15 @@ +spring.application.name=blog +spring.datasource.url=${DB_URL} +spring.datasource.username=${DB_USERNAME} +spring.datasource.password=${DB_PASSWORD} +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.web.resources.static-locations=classpath:/static/,file:uploads/ + +logging.level.org.springframework.jdbc.core=DEBUG +logging.level.org.springframework.jdbc.datasource=DEBUG + +kakao.token-url=https://kauth.kakao.com/oauth/token +kakao.user-url=https://kapi.kakao.com/v2/user/me +kakao.client-id=${KAKAO_CLIENT_ID} +kakao.redirect-uri=http://localhost:8080/auth/kakao/callback From 66f6d2b40ed7bb0dada3b607a7e9c2a14755d812 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Mon, 26 May 2025 18:37:41 +0900 Subject: [PATCH 14/16] =?UTF-8?q?fix=20:=20docker=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + docker/docker-compoes.yml | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 333fc754..7fb273ee 100644 --- a/.gitignore +++ b/.gitignore @@ -38,5 +38,6 @@ out/ # 환경 설정 및 민감 파일 .env +docker/.env *.key *.pem diff --git a/docker/docker-compoes.yml b/docker/docker-compoes.yml index c4ec83df..d5ed70a0 100644 --- a/docker/docker-compoes.yml +++ b/docker/docker-compoes.yml @@ -2,10 +2,10 @@ version: '3.8' services: blog: - build: . + image: choes0101/blog-app:latest container_name: blog-app ports: - "8080:8080" - environment: - - SPRING_PROFILES_ACTIVE=prod + env_file: + - .env restart: always From f9e2765b8efe11fbbdbbc3e41acd0d424096c9d3 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Mon, 26 May 2025 19:03:46 +0900 Subject: [PATCH 15/16] =?UTF-8?q?fix=20:=20docker-compose.yml=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/{docker-compoes.yml => docker-compose.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docker/{docker-compoes.yml => docker-compose.yml} (100%) diff --git a/docker/docker-compoes.yml b/docker/docker-compose.yml similarity index 100% rename from docker/docker-compoes.yml rename to docker/docker-compose.yml From c06363e3d1f4f63c172ba681efc00c8881771578 Mon Sep 17 00:00:00 2001 From: choes0101 <166037587+choes0101@users.noreply.github.com> Date: Mon, 26 May 2025 19:30:40 +0900 Subject: [PATCH 16/16] =?UTF-8?q?fix=20:=20ci/cd=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++---- src/main/java/com/blog/global/common/Common.java | 5 ----- src/main/java/com/blog/global/exception/Exception.java | 5 ----- 3 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 src/main/java/com/blog/global/common/Common.java delete mode 100644 src/main/java/com/blog/global/exception/Exception.java diff --git a/README.md b/README.md index 40e33870..7acf0f96 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ 스크린샷 2025-03-28 오전 10 24 35 -## 프로젝트 구조 +## 프로젝트 구조 ``` ├── README.md ├── build.gradle @@ -38,11 +38,9 @@ │   │   │   │   └── service │   │   └── global │   │   ├── auth - │   │   ├── common │   │   │   └── request │   │   │   └── response - │   │   ├── config - │   │   └── exception + │   │   └── config │   └── resources │   └── application.properties └── test diff --git a/src/main/java/com/blog/global/common/Common.java b/src/main/java/com/blog/global/common/Common.java deleted file mode 100644 index eda2b68a..00000000 --- a/src/main/java/com/blog/global/common/Common.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.blog.global.common; - -public class Common { - -} diff --git a/src/main/java/com/blog/global/exception/Exception.java b/src/main/java/com/blog/global/exception/Exception.java deleted file mode 100644 index 18a99e94..00000000 --- a/src/main/java/com/blog/global/exception/Exception.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.blog.global.exception; - -public class Exception { - -}