-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19 from co-co-gong/feat#18
feat: friend crud, exception handler, controller style
- Loading branch information
Showing
35 changed files
with
927 additions
and
217 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
## Docs | ||
|
||
- [docker-compose](docs/docker-compose.md) | ||
- [package-structure](docs/package-structure.md) | ||
- [Package 구조](docs/package-structure.md) | ||
- [Service layer 개발 방법](docs/service.md) | ||
- [Controller 개발 방법](docs/controller.md) | ||
- [Docker Compose 사용 방법](docs/docker-compose.md) | ||
- [Kubernetes 사용 방법](docs/kubernetes.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
## Controller 규약 | ||
|
||
```java | ||
@ResponseStatus(HttpStatus.OK) // 정상적 응답에 대한 HTTP status 작성 | ||
@GetMapping("/${URI}") // API 접근 URI 명시 | ||
@Operation(summary = "${SUMMARY}", description = "${DESCRIPTION}") // Swagger 내 문서화를 위한 설명 작성 | ||
// Controller의 모든 응답에 ApiResponseDto class 사용 | ||
// Generic을 통해 응답의 data type 명시 | ||
public ApiResponseDto<T> methodName( | ||
HttpServletRequest request, // 직접적인 요청 정보가 필요할 때 사용 | ||
@RequestParam String param1, // 쿼리 스트링 또는 폼 데이터의 요청 파라미터 | ||
@PathVariable Long param2, // URL 경로의 변수 매핑 | ||
@RequestBody Dto param3, // 요청 본문(JSON 등)을 객체로 받음 | ||
HttpServletResponse response // 직접적인 응답 설정이 필요할 때 사용 | ||
) { | ||
// Request header 사용 예시 | ||
String authHeader = request.getHeader("Authorization"); | ||
|
||
// 결과를 위한 business logic 실행 | ||
T data = domainService.businessLogic(); | ||
|
||
// Response header 추가 예시 | ||
response.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); | ||
|
||
// 정상적인 응답 시 사용할 HTTP status 및 응답 data | ||
return ApiResponseDto.success(HttpStatus.OK.value(), data); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
## Run | ||
|
||
```bash | ||
$ kubectl create ns co-co-gong | ||
namespace/co-co-gong created | ||
$ kubectl apply -n co-co-gong -f k8s | ||
deployment.apps/backend created | ||
service/backend created | ||
ingressroute.traefik.io/co-co-gong created | ||
deployment.apps/postgres created | ||
service/postgres created | ||
configmap/postgres-config created | ||
secret/postgres-secret created | ||
secret/oauth-secret created | ||
secret/jwt-secret created | ||
$ kubectl get all -n co-co-gong | ||
NAME READY STATUS RESTARTS AGE | ||
pod/backend-7ff75486b8-dtmh2 1/1 Running 0 3m39s | ||
pod/postgres-58585c55b4-7vsrs 1/1 Running 0 3m39s | ||
|
||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE | ||
service/backend ClusterIP 10.99.127.11 <none> 8080/TCP 3m39s | ||
service/postgres ClusterIP 10.109.182.198 <none> 5432/TCP 3m39s | ||
|
||
NAME READY UP-TO-DATE AVAILABLE AGE | ||
deployment.apps/backend 1/1 1 1 3m39s | ||
deployment.apps/postgres 1/1 1 1 3m39s | ||
|
||
NAME DESIRED CURRENT READY AGE | ||
replicaset.apps/backend-7ff75486b8 1 1 1 3m39s | ||
replicaset.apps/postgres-58585c55b4 1 1 1 3m39s | ||
``` | ||
|
||
## Logs | ||
|
||
```bash | ||
$ kubectl logs -n co-co-gong deploy/backend | ||
Downloading https://services.gradle.org/distributions/gradle-8.8-bin.zip | ||
.............10%.............20%.............30%.............40%.............50%.............60%..............70%.............80%.............90%........... | ||
..100% | ||
|
||
Welcome to Gradle 8.8! | ||
|
||
Here are the highlights of this release: | ||
- Running Gradle on Java 22 | ||
- Configurable Gradle daemon JVM | ||
- Improved IDE performance for large projects | ||
|
||
For more details see https://docs.gradle.org/8.8/release-notes.html | ||
|
||
Starting a Gradle Daemon (subsequent builds will be faster) | ||
> Task :compileJava | ||
> Task :processResources UP-TO-DATE | ||
> Task :classes | ||
> Task :resolveMainClassName | ||
> Task :bootJar | ||
> Task :jar | ||
> Task :assemble | ||
> Task :compileTestJava UP-TO-DATE | ||
> Task :processTestResources NO-SOURCE | ||
> Task :testClasses UP-TO-DATE | ||
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended | ||
2024-10-25T09:16:56.853+09:00 INFO 286 --- [co-co-gong-server] [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactor | ||
y for persistence unit 'default' | ||
2024-10-25T09:16:56.855+09:00 INFO 286 --- [co-co-gong-server] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiat | ||
ed... | ||
2024-10-25T09:16:56.857+09:00 INFO 286 --- [co-co-gong-server] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown complet | ||
ed. | ||
> Task :test | ||
> Task :check | ||
> Task :build | ||
|
||
BUILD SUCCESSFUL in 28s | ||
7 actionable tasks: 5 executed, 2 up-to-date | ||
|
||
. ____ _ __ _ _ | ||
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ | ||
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ | ||
\\/ ___)| |_)| | | | | || (_| | ) ) ) ) | ||
' |____| .__|_| |_|_| |_\__, | / / / / | ||
=========|_|==============|___/=/_/_/_/ | ||
:: Spring Boot :: (v3.3.2) | ||
``` | ||
## Stop | ||
```bash | ||
$ kubectl delete ns co-co-gong | ||
namespace "co-co-gong" deleted | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
## Exception Handling | ||
|
||
> Service layer의 exception handling은 [`GlobalExceptionHandler`](../src/main/java/com/server/global/error/handler/GlobalExceptionHandler.java)를 통해 관리 | ||
```java | ||
@RestControllerAdvice | ||
public class GlobalExceptionHandler { | ||
|
||
@ExceptionHandler(AuthException.class) | ||
public ResponseEntity<ApiResponseDto<Object>> handleFriendException(AuthException e) { | ||
return ResponseEntity.status(e.getStatus()).body(ApiResponseDto.error(e.getStatus(), e.getMessage())); | ||
} | ||
|
||
@ExceptionHandler(BusinessException.class) | ||
public ResponseEntity<ApiResponseDto<Object>> handleFriendException(BusinessException e) { | ||
return ResponseEntity.status(e.getStatus()).body(ApiResponseDto.error(e.getStatus(), e.getMessage())); | ||
} | ||
|
||
} | ||
``` | ||
|
||
> [`ErrorCode`](../src/main/java/com/server/global/error/code) 및 [`Exception`](../src/main/java/com/server/global/error/exception) 정의 후 아래 예시와 같이 service layer에서 예외 생성 | ||
```java | ||
throw new AuthException(AuthErrorCode.OAUTH_PROCESS_ERROR); | ||
throw new BusinessException(FriendErrorCode.RECEIPT_ALREADY_EXISTS); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,11 @@ | ||
#!/bin/bash | ||
|
||
./gradlew build | ||
rm -r build | ||
|
||
if ./gradlew clean build; then | ||
echo "Build success!" | ||
else | ||
echo "Build failed..." | ||
exit 1 | ||
fi | ||
java -jar build/libs/*SNAPSHOT.jar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
src/main/java/com/server/domain/friend/controller/FriendController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package com.server.domain.friend.controller; | ||
|
||
import java.util.List; | ||
|
||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.PutMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.ResponseStatus; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import com.server.domain.friend.dto.GetFriendOutDto; | ||
import com.server.domain.friend.enums.FriendState; | ||
import com.server.domain.friend.service.FriendService; | ||
import com.server.global.dto.ApiResponseDto; | ||
import com.server.global.jwt.JwtService; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
@RequiredArgsConstructor | ||
@RestController | ||
@RequestMapping("/api/friends") | ||
public class FriendController { | ||
|
||
private final JwtService jwtService; | ||
private final FriendService friendService; | ||
|
||
@ResponseStatus(HttpStatus.CREATED) | ||
@PostMapping("/request") | ||
@Operation(summary = "친구 신청 생성", description = "친구 신청할 사용자의 이름을 입력하여 친구 신청 생성") | ||
public ApiResponseDto<String> createFriendRequest(HttpServletRequest request, | ||
@RequestParam String receiptUsername) { | ||
String requestUsername = jwtService.extractUsernameFromToken(request).get(); | ||
friendService.createFriendRequest(requestUsername, receiptUsername); | ||
return ApiResponseDto.success(HttpStatus.CREATED.value(), | ||
String.format("A friend request from User '%s' to User '%s' has been created.", | ||
requestUsername, receiptUsername)); | ||
} | ||
|
||
@ResponseStatus(HttpStatus.OK) | ||
@GetMapping("/request") | ||
@Operation(summary = "친구 내역 조회", description = "사용자 기준 신청 보낸 내역") | ||
public ApiResponseDto<List<GetFriendOutDto>> getFriendRequest( | ||
@RequestParam(required = false) FriendState state, | ||
HttpServletRequest request) { | ||
String username = jwtService.extractUsernameFromToken(request).get(); | ||
List<GetFriendOutDto> getUserOutDtos = friendService.getRequestUser(username, state); | ||
return ApiResponseDto.success(HttpStatus.OK.value(), getUserOutDtos); | ||
} | ||
|
||
@ResponseStatus(HttpStatus.OK) | ||
@DeleteMapping("/request") | ||
@Operation(summary = "친구 신청 취소", description = "친구 신청할 사용자의 이름을 입력하여 친구 신청 삭제") | ||
public ApiResponseDto<String> deleteFriendRequest(HttpServletRequest request, | ||
@RequestParam String receiptUsername) { | ||
String requestUsername = jwtService.extractUsernameFromToken(request).get(); | ||
friendService.deleteFriendRequest(requestUsername, receiptUsername); | ||
return ApiResponseDto.success(HttpStatus.OK.value(), String | ||
.format("The friend request from '%s' to '%s' has been deleted.", requestUsername, receiptUsername)); | ||
} | ||
|
||
@ResponseStatus(HttpStatus.OK) | ||
@GetMapping("/receipt") | ||
@Operation(summary = "친구 내역 조회", description = "사용자 기준 신청 받은 내역") | ||
public ApiResponseDto<List<GetFriendOutDto>> getFriendReceipt(HttpServletRequest request, | ||
@RequestParam(required = false) FriendState state) { | ||
String username = jwtService.extractUsernameFromToken(request).get(); | ||
List<GetFriendOutDto> getUserOutDtos = friendService.getReceiptUser(username, state); | ||
return ApiResponseDto.success(HttpStatus.OK.value(), getUserOutDtos); | ||
} | ||
|
||
@ResponseStatus(HttpStatus.CREATED) | ||
@PutMapping("/receipt") | ||
@Operation(summary = "친구 신청 승인", description = "친구 신청을 승인할 사용자의 이름을 입력하여 친구 신청 승인") | ||
public ApiResponseDto<String> approveFriendRequest(HttpServletRequest request, | ||
@RequestParam String requestUsername) { | ||
String receiptUsername = jwtService.extractUsernameFromToken(request).get(); | ||
friendService.acceptFriendRequest(requestUsername, receiptUsername); | ||
return ApiResponseDto.success(HttpStatus.CREATED.value(), String.format( | ||
"The friend request from User '%s' to User '%s' has been accepted.", requestUsername, receiptUsername)); | ||
} | ||
} |
10 changes: 4 additions & 6 deletions
10
...rver/domain/friend/dto/FriendListDto.java → ...er/domain/friend/dto/GetFriendOutDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,13 @@ | ||
package com.server.domain.friend.dto; | ||
|
||
import java.util.UUID; | ||
|
||
import com.server.domain.friend.enums.FriendState; | ||
import com.server.domain.user.dto.UserDto; | ||
|
||
import lombok.Getter; | ||
import lombok.Setter; | ||
|
||
@Getter | ||
public class FriendListDto { | ||
private UUID id; | ||
private UUID requestUserId; | ||
private UUID receiptUserId; | ||
@Setter | ||
public class GetFriendOutDto extends UserDto { | ||
private FriendState state; | ||
} |
Oops, something went wrong.