Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
99f5ced
feat: UUID를 8자리 짧은 코드로 압축하는 기능 추가
sudhdkso May 28, 2025
63ca094
feat: UUID를 발급받아 그룹코드를 생성하는 기능 추가
sudhdkso May 28, 2025
1ebcb43
feat: UUID를 발급받아 그룹코드를 생성하는 기능 추가
sudhdkso May 28, 2025
05f1ecb
feat: 그룹코드를 통해 그룹ID를 조회하는 기능 추가
sudhdkso May 28, 2025
e4805f3
refactor: 그룹 권한 AOP 검증 방식을 토큰 기반에서 코드 기반으로 변경
sudhdkso May 28, 2025
6eb7b01
fix: 토큰 기반 그룹 ID 찾기에서 코드 기반 그룹 ID 찾기로 변경
sudhdkso May 28, 2025
355577b
test: 그룹 테스트용 GroupTestFactory 클래스 생성
sudhdkso May 28, 2025
82f4429
refactor: 테스트에서 new Group() 대신 Factory 메서드 사용하도록 변경
sudhdkso May 28, 2025
f96f813
feat: group 생성시 토큰 -> 코드를 response 하도록 변경
sudhdkso May 28, 2025
e910222
feat: token기반 조회에서 code기반 조회로 변경
sudhdkso May 28, 2025
5b8dd68
chore: 불필요한 TestController삭제
sudhdkso May 28, 2025
352e08b
chore: 불필요한 내용 삭제 및 오류 수정
sudhdkso May 28, 2025
3df3596
refactor: group code not found일때 custom exception 반환하도록 수정
sudhdkso May 28, 2025
efdb0cd
chore: 불필요한 print 삭제
sudhdkso May 28, 2025
0660ff2
test: group code 생성에 대한 테스트 코드 작성
sudhdkso May 29, 2025
4ea03cb
test: 테스트 메서드명 BDD 스타일로 리팩터링
sudhdkso May 29, 2025
cf30b4d
refactor: code -> token (우선 원래대로 복구, 프론트/테스트 확인 후 재변경 예정)
sudhdkso Jun 1, 2025
71a6784
fix: 불필요한 부분 삭제
sudhdkso Jun 1, 2025
2d03ebf
refactor: token -> groupToken으로 변경
sudhdkso Jun 1, 2025
912b5be
feat: Spring cache + redis를 활용한 캐시 적용
sudhdkso Jun 6, 2025
d740205
test: cache 테스트 코드 추가
sudhdkso Jun 6, 2025
5132eb7
chore: 개발 환경의 redis 설정 및 db변경 사항 반영
sudhdkso Jun 6, 2025
33d5281
fix: 충돌 난 부분 해결
sudhdkso Jun 6, 2025
e12c759
fix: 충돌 난 부분 해결
sudhdkso Jun 6, 2025
6505917
test: token -> code로 변경함에 따라 테스트 코드 변경
sudhdkso Jun 6, 2025
7e70561
refactor(test): 패키지 이동에 따른 테스트 코드 위치 및 import 수정
sudhdkso Jun 6, 2025
38f3879
refactor: 충돌난 부분 수정
sudhdkso Jun 6, 2025
7cb17b6
fix: 불필요한 파일 삭제
sudhdkso Jun 6, 2025
5d35594
refactor: 패키지 이름 변경 및 관련 오류 수정
sudhdkso Jun 8, 2025
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
15 changes: 12 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,27 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.security:spring-security-core'
implementation 'org.springframework.boot:spring-boot-starter-cache'

implementation 'com.amazonaws:aws-java-sdk-s3:1.12.638'
// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

implementation 'com.amazonaws:aws-java-sdk-s3:1.12.638'
//jwt
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'

//db
implementation 'mysql:mysql-connector-java:8.0.30'

compileOnly 'org.projectlombok:lombok'
implementation 'mysql:mysql-connector-java:8.0.30'
annotationProcessor 'org.projectlombok:lombok'

//test
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:testcontainers'
testImplementation 'com.h2database:h2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

Expand All @@ -65,7 +75,6 @@ dependencies {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'

//monitoring
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-registry-prometheus'
Expand Down Expand Up @@ -118,6 +127,6 @@ build {
bootJar {
dependsOn asciidoctor
from("${asciidoctor.outputDir}") {
into 'static/docs'
into 'src/main/resources/static/docs'
}
}
10 changes: 10 additions & 0 deletions docker-compose.local.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# 로컬 개발용 도커 컴포즈 파일
# docker compose -f docker-compose.local.yml up -d
# docker compose -f docker-compose.local.yml down
services:
redis:
container_name: redis
image: redis:7-alpine
ports:
- "6379:6379"
restart: unless-stopped
15 changes: 13 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,18 @@ services:
- backend
volumes:
- ./logs:/logs # 로그 파일을 호스트 시스템의 ./logs 디렉토리로 매핑

redis:
image: redis:latest
container_name: redis
ports:
- "6379:6379"
volumes:
- ./redis.conf:/etc/redis/redis.conf
- redis-data:/data
command: redis-server /etc/redis/redis.conf
networks:
backend:
driver: bridge
driver: bridge

volumes:
redis-data:
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/main/java/com/dnd/moddo/ModdoApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;

@SpringBootApplication (exclude = SecurityAutoConfiguration.class)
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class ModdoApplication {

public static void main(String[] args) {
Expand Down
12 changes: 0 additions & 12 deletions src/main/java/com/dnd/moddo/TestController.java

This file was deleted.

47 changes: 25 additions & 22 deletions src/main/java/com/dnd/moddo/domain/auth/service/AuthService.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,43 @@
package com.dnd.moddo.domain.auth.service;

import java.time.LocalDateTime;
import java.util.UUID;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dnd.moddo.domain.user.entity.User;
import com.dnd.moddo.domain.user.entity.type.Authority;
import com.dnd.moddo.domain.user.repository.UserRepository;
import com.dnd.moddo.global.jwt.dto.TokenResponse;
import com.dnd.moddo.global.jwt.utill.JwtProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.UUID;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Service
public class AuthService {

private final UserRepository userRepository;
private final JwtProvider jwtProvider;
private final UserRepository userRepository;
private final JwtProvider jwtProvider;

@Transactional
public TokenResponse createGuestUser() {
String guestEmail = "guest-" + UUID.randomUUID() + "@guest.com";
@Transactional
public TokenResponse createGuestUser() {
String guestEmail = "guest-" + UUID.randomUUID() + "@guest.com";

User guestUser = User.builder()
.email(guestEmail)
.name("Guest")
.profile(null)
.createdAt(LocalDateTime.now())
.expiredAt(LocalDateTime.now().plusMonths(1))
.authority(Authority.USER)
.isMember(false)
.build();
User guestUser = User.builder()
.email(guestEmail)
.name("Guest")
.profile(null)
.createdAt(LocalDateTime.now())
.expiredAt(LocalDateTime.now().plusMonths(1))
.authority(Authority.USER)
.isMember(false)
.build();

userRepository.save(guestUser);
userRepository.save(guestUser);

return jwtProvider.generateToken(guestUser.getId(), guestUser.getEmail(), guestUser.getAuthority().toString(), guestUser.getIsMember());
}
return jwtProvider.generateToken(guestUser.getId(), guestUser.getEmail(), guestUser.getAuthority().toString(),
guestUser.getIsMember());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.web.bind.annotation.RestController;

import com.dnd.moddo.domain.character.service.QueryCharacterService;
import com.dnd.moddo.domain.group.service.QueryGroupService;
import com.dnd.moddo.domain.image.dto.CharacterResponse;
import com.dnd.moddo.global.jwt.service.JwtService;

Expand All @@ -19,12 +20,13 @@ public class CharacterController {

private final JwtService jwtService;
private final QueryCharacterService queryCharacterService;
private final QueryGroupService queryGroupService;

@GetMapping()
public ResponseEntity<CharacterResponse> getCharacter(
@RequestParam("groupToken") String groupToken
@RequestParam("groupToken") String code
) {
Long groupId = jwtService.getGroupId(groupToken);
Long groupId = queryGroupService.findIdByCode(code);

CharacterResponse response = queryCharacterService.findCharacterByGroupId(groupId);
return ResponseEntity.ok(response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.dnd.moddo.domain.expense.dto.response.ExpensesResponse;
import com.dnd.moddo.domain.expense.service.CommandExpenseService;
import com.dnd.moddo.domain.expense.service.QueryExpenseService;
import com.dnd.moddo.domain.group.service.QueryGroupService;
import com.dnd.moddo.global.common.annotation.VerifyManagerPermission;
import com.dnd.moddo.global.jwt.service.JwtService;

Expand All @@ -34,19 +35,20 @@ public class ExpenseController {
private final CommandExpenseService commandExpenseService;
private final QueryExpenseService queryExpenseService;
private final JwtService jwtService;
private final QueryGroupService queryGroupService;

@PostMapping
public ResponseEntity<ExpensesResponse> saveExpenses(
@RequestParam("groupToken") String groupToken,
@RequestParam("groupToken") String code,
@Valid @RequestBody ExpensesRequest request) {
Long groupId = jwtService.getGroupId(groupToken);
Long groupId = queryGroupService.findIdByCode(code);
ExpensesResponse response = commandExpenseService.createExpenses(groupId, request);
return ResponseEntity.ok(response);
}

@GetMapping
public ResponseEntity<ExpensesResponse> getAllByGroupId(@RequestParam("groupToken") String groupToken) {
Long groupId = jwtService.getGroupId(groupToken);
public ResponseEntity<ExpensesResponse> getAllByGroupId(@RequestParam("groupToken") String code) {
Long groupId = queryGroupService.findIdByCode(code);
ExpensesResponse response = queryExpenseService.findAllByGroupId(groupId);
return ResponseEntity.ok(response);
}
Expand All @@ -60,8 +62,8 @@ public ResponseEntity<ExpenseResponse> getByExpenseId(@PathVariable("expenseId")

@GetMapping("/details")
public ResponseEntity<ExpenseDetailsResponse> getExpenseDetailsByGroupId(
@RequestParam("groupToken") String groupToken) {
Long groupId = jwtService.getGroupId(groupToken);
@RequestParam("groupToken") String code) {
Long groupId = queryGroupService.findIdByCode(code);
ExpenseDetailsResponse response = queryExpenseService.findAllExpenseDetailsByGroupId(groupId);
return ResponseEntity.ok(response);
}
Expand All @@ -84,11 +86,11 @@ public ResponseEntity<Void> deleteByExpenseId(@PathVariable("expenseId") Long ex

@PutMapping("/img/{expenseId}")
public void updateImgUrl(HttpServletRequest request,
@RequestParam("groupToken") String groupToken,
@RequestParam("groupToken") String code,
@PathVariable("expenseId") Long expenseId,
@RequestBody ExpenseImageRequest expenseImageRequest) {
Long userId = jwtService.getUserId(request);
Long groupId = jwtService.getGroupId(groupToken);
Long groupId = queryGroupService.findIdByCode(code);
commandExpenseService.updateImgUrl(userId, groupId, expenseId, expenseImageRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ public ResponseEntity<GroupSaveResponse> saveGroup(HttpServletRequest request,
@PutMapping("/account")
public ResponseEntity<GroupResponse> updateAccount(
HttpServletRequest request,
@RequestParam("groupToken") String groupToken,
@RequestParam("groupToken") String code,
@RequestBody GroupAccountRequest groupAccountRequest) {
Long userId = jwtService.getUserId(request);
Long groupId = jwtService.getGroupId(groupToken);
Long groupId = queryGroupService.findIdByCode(code);

GroupResponse response = commandGroupService.updateAccount(groupAccountRequest, userId, groupId);
return ResponseEntity.ok(response);
Expand All @@ -55,9 +55,9 @@ public ResponseEntity<GroupResponse> updateAccount(
@GetMapping
public ResponseEntity<GroupDetailResponse> getGroup(
HttpServletRequest request,
@RequestParam("groupToken") String groupToken) {
@RequestParam("groupToken") String code) {
Long userId = jwtService.getUserId(request);
Long groupId = jwtService.getGroupId(groupToken);
Long groupId = queryGroupService.findIdByCode(code);

GroupDetailResponse response = queryGroupService.findOne(groupId, userId);
return ResponseEntity.ok(response);
Expand All @@ -66,21 +66,30 @@ public ResponseEntity<GroupDetailResponse> getGroup(
@PostMapping("/password")
public ResponseEntity<GroupPasswordResponse> isPasswordMatch(
HttpServletRequest request,
@RequestParam("groupToken") String groupToken,
@RequestParam("groupToken") String code,
@RequestBody GroupPasswordRequest groupPasswordRequest) {
Long userId = jwtService.getUserId(request);
Long groupId = jwtService.getGroupId(groupToken);
Long groupId = queryGroupService.findIdByCode(code);

GroupPasswordResponse response = commandGroupService.isPasswordMatch(groupId, userId, groupPasswordRequest);
return ResponseEntity.ok(response);
}

@GetMapping("/header")
public ResponseEntity<GroupHeaderResponse> getHeader(
@RequestParam("groupToken") String groupToken) {
Long groupId = jwtService.getGroupId(groupToken);

@RequestParam("groupToken") String code) {
Long groupId = queryGroupService.findIdByCode(code);

GroupHeaderResponse response = queryGroupService.findByGroupHeader(groupId);
return ResponseEntity.ok(response);
}

@GetMapping("/header/no-cache")
public ResponseEntity<GroupHeaderResponse> getHeaderNoCache(
@RequestParam("groupToken") String code) {
Long groupId = queryGroupService.findIdByCodeNoCache(code);

GroupHeaderResponse response = queryGroupService.findByGroupHeader(groupId);
return ResponseEntity.ok(response);
}
}
}
6 changes: 5 additions & 1 deletion src/main/java/com/dnd/moddo/domain/group/entity/Group.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,20 @@ public class Group {

private LocalDateTime deadline;

@Column(unique = true)
private String code;

@Builder
public Group(String name, Long writer, String password, LocalDateTime createdAt,
String bank, String accountNumber, LocalDateTime deadline) {
String bank, String accountNumber, String code, LocalDateTime deadline) {
this.name = name;
this.writer = writer;
this.password = password;
this.createdAt = createdAt;
this.expiredAt = LocalDateTime.now().plusMonths(1);
this.bank = bank;
this.accountNumber = accountNumber;
this.code = code;
this.deadline = deadline;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
package com.dnd.moddo.domain.group.exception;

import com.dnd.moddo.global.exception.ModdoException;
import org.springframework.http.HttpStatus;

import com.dnd.moddo.global.exception.ModdoException;

public class GroupNotFoundException extends ModdoException {
public GroupNotFoundException(Long groupId){
super(HttpStatus.NOT_FOUND, "아이디가 " + groupId + "인 모임을 찾을 수 없습니다.");
};
public GroupNotFoundException(Long groupId) {
super(HttpStatus.NOT_FOUND, "아이디가 " + groupId + "인 모임을 찾을 수 없습니다.");
}

;

public GroupNotFoundException(String code) {
super(HttpStatus.NOT_FOUND, "그룹 코드가 " + code + "인 모임을 찾을 수 없습니다.");
}

;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
package com.dnd.moddo.domain.group.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.dnd.moddo.domain.group.entity.Group;
import com.dnd.moddo.domain.group.exception.GroupNotFoundException;
import org.springframework.data.jpa.repository.JpaRepository;

public interface GroupRepository extends JpaRepository<Group, Long> {
default Group getById(Long groupId) {
return findById(groupId).orElseThrow(() -> new GroupNotFoundException(groupId));
}
default Group getById(Long groupId) {
return findById(groupId).orElseThrow(() -> new GroupNotFoundException(groupId));
}

boolean existsByCode(String code);

@Query("SELECT g.id FROM Group g WHERE g.code = :code")
Optional<Long> findIdByCode(@Param("code") String code);

default Long getIdByCode(String code) {
return findIdByCode(code).orElseThrow(() -> new GroupNotFoundException(code));
}

}
Loading
Loading