Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: CI/CD to EC2

on:
push:
branches: [ "조은성/main", "조은성/6주차" ]

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- 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
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'
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ out/

# 환경 설정 및 민감 파일
.env
application.properties
docker/.env
*.key
*.pem
9 changes: 9 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
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
ENTRYPOINT ["java", "-jar", "app.jar"]
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<img width="532" alt="스크린샷 2025-03-28 오전 10 24 35" src="https://github.com/user-attachments/assets/9ba1120e-9884-41f5-b128-8ec88113daff" />


## 프로젝트 구조
## 프로젝트 구조
```
├── README.md
├── build.gradle
Expand Down Expand Up @@ -38,11 +38,9 @@
│   │   │   │   └── service
│   │   └── global
│   │   ├── auth
│   │   ├── common
│   │   │   └── request
│   │   │   └── response
│   │   ├── config
│   │   └── exception
│   │   └── config
│   └── resources
│   └── application.properties
└── test
Expand Down
11 changes: 11 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: '3.8'

services:
blog:
image: choes0101/blog-app:latest
container_name: blog-app
ports:
- "8080:8080"
env_file:
- .env
restart: always
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,10 @@ private RowMapper<Comment> commentRowMapper() {
rs.getTimestamp("updated_at").toLocalDateTime()
);
}

public List<Comment> findByAuthorId(UUID authorId) {
String sql = "SELECT * FROM comment WHERE author_id = ?";
return jdbcTemplate.query(sql, commentRowMapper(), authorId.toString());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,12 @@ public void updateComment(UUID id, CommentRequest request) {
public void deleteComment(UUID id) {
commentRepository.deleteById(id);
}

public List<CommentResponse> getCommentsByAuthor(UUID authorId) {
return commentRepository.findByAuthorId(authorId)
.stream()
.map(CommentResponse::from)
.collect(Collectors.toList());
}

}
5 changes: 0 additions & 5 deletions src/main/java/com/blog/domain/image/Image.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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<ImageResponse> upload(@RequestParam("file") MultipartFile file) {
ImageResponse response = imageService.upload(file);
return ResponseEntity.ok(response);
}
}
40 changes: 40 additions & 0 deletions src/main/java/com/blog/domain/image/domain/Image.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
27 changes: 27 additions & 0 deletions src/main/java/com/blog/domain/image/dto/ImageResponse.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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<Image> findById(UUID id) {
String sql = "SELECT * FROM image WHERE id = ?";
return jdbcTemplate.query(sql, rowMapper(), id.toString())
.stream().findFirst();
}

private RowMapper<Image> 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()
);
}
}
49 changes: 49 additions & 0 deletions src/main/java/com/blog/domain/image/service/ImageService.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,10 @@ private RowMapper<Post> postRowMapper() {
rs.getTimestamp("updated_at").toLocalDateTime()
);
}

public List<Post> findByAuthorId(String authorId) {
String sql = "SELECT * FROM post WHERE author_id = ?";
return jdbcTemplate.query(sql, postRowMapper(), authorId);
}

}
8 changes: 8 additions & 0 deletions src/main/java/com/blog/domain/post/service/PostService.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,12 @@ public void updatePost(UUID id, PostRequest request) {
public void deletePost(UUID id) {
postRepository.deleteById(id);
}

public List<PostResponse> getPostsByAuthor(UUID authorId) {
return postRepository.findByAuthorId(authorId.toString())
.stream()
.map(PostResponse::from)
.collect(Collectors.toList());
}

}
Loading