Skip to content

Commit

Permalink
Merge pull request #3 from mujik-tigers/feature/create-room-yeon
Browse files Browse the repository at this point in the history
merge
  • Loading branch information
yeonise authored Mar 11, 2024
2 parents 16c677c + 7c10c7b commit 27e93c6
Show file tree
Hide file tree
Showing 23 changed files with 558 additions and 15 deletions.
31 changes: 16 additions & 15 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.3'
id 'io.spring.dependency-management' version '1.1.4'
id 'java'
id 'org.springframework.boot' version '3.2.3'
id 'io.spring.dependency-management' version '1.1.4'
}

group = 'site'
version = '0.0.1-SNAPSHOT'

java {
sourceCompatibility = '17'
sourceCompatibility = '17'
}

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

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}

jar {
enabled = false
enabled = false
}
34 changes: 34 additions & 0 deletions src/main/java/site/youtogether/config/RedisConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package site.youtogether.config;

import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import lombok.RequiredArgsConstructor;

@Configuration
@RequiredArgsConstructor
public class RedisConfig {

private final RedisProperties redisProperties;

@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort());
}

@Bean
public RedisTemplate<String, String> redisStringTemplate() {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());

return redisTemplate;
}

}
23 changes: 23 additions & 0 deletions src/main/java/site/youtogether/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package site.youtogether.config;

import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import lombok.RequiredArgsConstructor;
import site.youtogether.resolver.AddressArgumentResolver;

@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {

private final AddressArgumentResolver addressArgumentResolver;

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(addressArgumentResolver);
}

}
17 changes: 17 additions & 0 deletions src/main/java/site/youtogether/exception/CustomException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package site.youtogether.exception;

import org.springframework.http.HttpStatus;

import lombok.Getter;

@Getter
public class CustomException extends RuntimeException {

private final HttpStatus status;

public CustomException(ErrorType errorType) {
super(errorType.getMessage());
this.status = errorType.getStatus();
}

}
21 changes: 21 additions & 0 deletions src/main/java/site/youtogether/exception/ErrorType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package site.youtogether.exception;

import org.springframework.http.HttpStatus;

import lombok.Getter;

@Getter
public enum ErrorType {

// Room
SINGLE_ROOM_PARTICIPATION_VIOLATION(HttpStatus.BAD_REQUEST, "하나의 방에만 참가할 수 있습니다");

private final HttpStatus status;
private final String message;

ErrorType(HttpStatus status, String message) {
this.status = status;
this.message = message;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package site.youtogether.exception;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import site.youtogether.util.api.ApiResponse;
import site.youtogether.util.api.ResponseResult;

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(BindException.class)
public ResponseEntity<ApiResponse<Object>> handleBindException(BindException exception) {
return ResponseEntity.badRequest()
.body(ApiResponse.of(HttpStatus.BAD_REQUEST, ResponseResult.EXCEPTION_OCCURRED,
exception.getBindingResult().getFieldErrors().stream()
.collect(Collectors.groupingBy(FieldError::getField))
.entrySet().stream()
.map(error -> {
Map<String, Object> fieldError = new LinkedHashMap<>();
fieldError.put("type", error.getKey());
fieldError.put("message", error.getValue().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.joining(", ")));
return fieldError;
})
)
);
}

@ExceptionHandler(CustomException.class)
public ResponseEntity<ApiResponse<Object>> handleCustomException(CustomException customException) {
Map<String, String> error = new LinkedHashMap<>(2);
error.put("type", customException.getClass().getSimpleName());
error.put("message", customException.getMessage());

return ResponseEntity.badRequest()
.body(ApiResponse.of(customException.getStatus(), ResponseResult.EXCEPTION_OCCURRED, List.of(error)));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package site.youtogether.exception.room;

import site.youtogether.exception.CustomException;
import site.youtogether.exception.ErrorType;

public class SingleRoomParticipationViolationException extends CustomException {

public SingleRoomParticipationViolationException() {
super(ErrorType.SINGLE_ROOM_PARTICIPATION_VIOLATION);
}

}
11 changes: 11 additions & 0 deletions src/main/java/site/youtogether/resolver/Address.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package site.youtogether.resolver;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Address {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package site.youtogether.resolver;

import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import jakarta.servlet.http.HttpServletRequest;

@Component
public class AddressArgumentResolver implements HandlerMethodArgumentResolver {

@Override
public boolean supportsParameter(MethodParameter parameter) {
boolean hasAddressAnnotation = parameter.hasParameterAnnotation(Address.class);
boolean isStringType = String.class.isAssignableFrom(parameter.getParameterType());

return hasAddressAnnotation && isStringType;
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);

assert request != null;
return request.getLocalAddr();
}

}
29 changes: 29 additions & 0 deletions src/main/java/site/youtogether/room/Room.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package site.youtogether.room;

import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;

import lombok.Builder;
import lombok.Getter;
import site.youtogether.util.RandomUtil;

@RedisHash(value = "room")
@Getter
public class Room {

@Id
private final String code;

private final String title;
private final int capacity;
private final String password;

@Builder
public Room(String title, int capacity, String password) {
this.code = RandomUtil.generateRoomCode();
this.title = title;
this.capacity = capacity;
this.password = password;
}

}
51 changes: 51 additions & 0 deletions src/main/java/site/youtogether/room/application/RoomService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package site.youtogether.room.application;

import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import site.youtogether.exception.room.SingleRoomParticipationViolationException;
import site.youtogether.room.Room;
import site.youtogether.room.dto.RoomCode;
import site.youtogether.room.dto.RoomSettings;
import site.youtogether.room.infrastructure.RedisStorage;
import site.youtogether.room.infrastructure.RoomStorage;
import site.youtogether.user.Role;
import site.youtogether.user.User;
import site.youtogether.user.infrastructure.UserStorage;
import site.youtogether.util.RandomUtil;

@Service
@RequiredArgsConstructor
public class RoomService {

private final RedisStorage redisStorage;
private final RoomStorage roomStorage;
private final UserStorage userStorage;

public RoomCode create(String address, RoomSettings roomSettings) {
if (redisStorage.existsInActiveAddress(address)) {
throw new SingleRoomParticipationViolationException();
}

Room room = Room.builder()
.title(roomSettings.getTitle())
.capacity(roomSettings.getCapacity())
.password(roomSettings.getPassword())
.build();

User host = User.builder()
.address(address)
.nickname(RandomUtil.generateUserNickname())
.role(Role.HOST)
.build();

roomStorage.save(room);
userStorage.save(host);

redisStorage.addActiveAddress(address);
redisStorage.addParticipant(room.getCode(), address);

return new RoomCode(room);
}

}
15 changes: 15 additions & 0 deletions src/main/java/site/youtogether/room/dto/RoomCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package site.youtogether.room.dto;

import lombok.Getter;
import site.youtogether.room.Room;

@Getter
public class RoomCode {

private final String roomCode;

public RoomCode(Room room) {
this.roomCode = room.getCode();
}

}
23 changes: 23 additions & 0 deletions src/main/java/site/youtogether/room/dto/RoomSettings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package site.youtogether.room.dto;

import org.hibernate.validator.constraints.Range;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.Getter;

@Getter
public class RoomSettings {

@NotBlank
@Size(min = 1, max = 30)
private String title;

@Range(min = 2, max = 10)
private int capacity;

@Pattern(regexp = "^[0-9a-zA-Z]{5,10}$")
private String password;

}
Loading

0 comments on commit 27e93c6

Please sign in to comment.