Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ jobs:
shell: bash

- name: build
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: |
chmod +x gradlew
./gradlew build -x test
Expand Down
108 changes: 58 additions & 50 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,69 +1,77 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.1'
id 'io.spring.dependency-management' version '1.1.5'
id 'java'
id 'org.springframework.boot' version '3.3.1'
id 'io.spring.dependency-management' version '1.1.5'
id "io.sentry.jvm.gradle" version "5.1.0"
}

group = 'com.tiki'
version = '0.0.1-SNAPSHOT'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
mavenCentral()
}

sentry {
includeSourceContext = true
org = "ti-ki"
projectName = "java-spring-boot"
authToken = System.getenv("SENTRY_AUTH_TOKEN")
}

dependencies {

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

//jwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'

// slack logback
implementation 'com.github.maricn:logback-slack-appender:1.4.0'

// s3
implementation("software.amazon.awssdk:bom:2.21.0")
implementation("software.amazon.awssdk:s3:2.21.0")
// s3
implementation("software.amazon.awssdk:bom:2.21.0")
implementation("software.amazon.awssdk:s3:2.21.0")

// swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'

// mail
implementation 'org.springframework.boot:spring-boot-starter-mail'

//Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'io.lettuce:lettuce-core:6.2.1.RELEASE'

//thymeleaf
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

//jwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'

// slack logback
implementation 'com.github.maricn:logback-slack-appender:1.4.0'

// s3
implementation("software.amazon.awssdk:bom:2.21.0")
implementation("software.amazon.awssdk:s3:2.21.0")

// s3
implementation("software.amazon.awssdk:bom:2.21.0")
implementation("software.amazon.awssdk:s3:2.21.0")

// swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'

// mail
implementation 'org.springframework.boot:spring-boot-starter-mail'

//Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'io.lettuce:lettuce-core:6.2.1.RELEASE'

//thymeleaf
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

//Validation
implementation 'commons-validator:commons-validator:1.7'
Expand All @@ -73,5 +81,5 @@ dependencies {
}

tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}
15 changes: 15 additions & 0 deletions src/main/java/com/tiki/server/common/handler/ErrorHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.tiki.server.email.verification.exception.EmailVerificationException;
import com.tiki.server.folder.exception.FolderException;
import com.tiki.server.note.exception.NoteException;
import io.sentry.Sentry;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
Expand Down Expand Up @@ -36,90 +37,103 @@ public class ErrorHandler {
public ResponseEntity<BaseResponse> memberException(MemberException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(TeamException.class)
public ResponseEntity<BaseResponse> teamException(TeamException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(MemberTeamManagerException.class)
public ResponseEntity<BaseResponse> memberTeamManagerException(MemberTeamManagerException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(TimeBlockException.class)
public ResponseEntity<BaseResponse> timeBlockException(TimeBlockException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(DocumentException.class)
public ResponseEntity<BaseResponse> documentException(DocumentException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(NoteException.class)
public ResponseEntity<BaseResponse> noteException(NoteException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(ExternalException.class)
public ResponseEntity<BaseResponse> externalException(ExternalException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(EmailVerificationException.class)
public ResponseEntity<BaseResponse> mailVerificationException(EmailVerificationException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(EmailSenderException.class)
public ResponseEntity<BaseResponse> mailSenderException(EmailSenderException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(TeamInvitationException.class)
public ResponseEntity<BaseResponse> teamInvitationException(TeamInvitationException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(FolderException.class)
public ResponseEntity<BaseResponse> folderException(FolderException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}

@ExceptionHandler(AuthException.class)
public ResponseEntity<BaseResponse> authException(AuthException exception) {
log.error(exception.getMessage());
val errorCode = exception.getErrorCode();
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(
ErrorCodeResponse.of(errorCode.getCode(), errorCode.getMessage()));
}

@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<BaseResponse> httpMessageNotReadableException(HttpMessageNotReadableException exception) {
log.error(exception.getMessage());
Sentry.captureException(exception);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(
ErrorResponse.of(WRONG_INPUT));
}
Expand All @@ -128,6 +142,7 @@ public ResponseEntity<BaseResponse> httpMessageNotReadableException(HttpMessageN
public ResponseEntity<BaseResponse> exception(Exception exception) {
log.error(exception.getMessage());
val errorCode = UNCAUGHT_SERVER_EXCEPTION;
Sentry.captureException(exception);
return ResponseEntity.status(errorCode.getHttpStatus()).body(ErrorResponse.of(errorCode.getMessage()));
}
}
4 changes: 4 additions & 0 deletions src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,7 @@ aws-property:
bucket: ${AWS_PROPERTY.BUCKET.dev}
aws-region: ap-northeast-2
s3-url: ${AWS_PROPERTY.S3_URL.dev}

sentry:
dsn: ${SENTRY_PROPERTY.dsn}
traces-sample-rate: 1.0