Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

제약 조건 추가 및 리팩토링 #249

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

@RestController
@RequestMapping("/categories")
public class CategoryController implements SpringDocCategoryController{
public class CategoryController implements SpringDocCategoryController {

private final CategoryService categoryService;

Expand All @@ -41,8 +41,10 @@ public ResponseEntity<FindAllCategoriesResponse> getCategories() {
}

@PutMapping("/{id}")
public ResponseEntity<Void> updateCategory(@PathVariable Long id,
@Valid @RequestBody UpdateCategoryRequest updateCategoryRequest) {
public ResponseEntity<Void> updateCategory(
@PathVariable Long id,
@Valid @RequestBody UpdateCategoryRequest updateCategoryRequest
) {
categoryService.update(id, updateCategoryRequest);
return ResponseEntity.ok().build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import codezap.global.validation.ValidationGroups.NotNullGroup;
import codezap.global.validation.ValidationGroups.SizeCheckGroup;
import io.swagger.v3.oas.annotations.media.Schema;

public record CreateCategoryRequest(
@Schema(description = "카테고리 이름", example = "Spring")
@NotNull(message = "카테고리 이름이 null 입니다.")
@Size(max = 255, message = "카테고리 이름은 최대 255자까지 입력 가능합니다.")
@NotNull(message = "카테고리 이름이 null 입니다.", groups = NotNullGroup.class)
@Size(max = 255, message = "카테고리 이름은 최대 255자까지 입력 가능합니다.", groups = SizeCheckGroup.class)
String name
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import codezap.global.validation.ValidationGroups.NotNullGroup;
import codezap.global.validation.ValidationGroups.SizeCheckGroup;
import io.swagger.v3.oas.annotations.media.Schema;

public record UpdateCategoryRequest(
@Schema(description = "카테고리 이름", example = "Spring")
@NotNull(message = "카테고리 이름이 null 입니다.")
@Size(max = 255, message = "카테고리 이름은 최대 255자까지 입력 가능합니다.")
@NotNull(message = "카테고리 이름이 null 입니다.", groups = NotNullGroup.class)
@Size(max = 255, message = "카테고리 이름은 최대 255자까지 입력 가능합니다.", groups = SizeCheckGroup.class)
String name
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ public void deleteById(Long id) {
if (templateRepository.existsByCategoryId(id)) {
throw new CodeZapException(HttpStatus.BAD_REQUEST, "템플릿이 존재하는 카테고리는 삭제할 수 없습니다.");
}
if (id == 1) {
throw new CodeZapException(HttpStatus.BAD_REQUEST, "1번 카테고리는 삭제할 수 없습니다.");
}
categoryRepository.deleteById(id);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class WebCorsConfiguration implements WebMvcConfigurer {
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*");
.allowedMethods("*")
.exposedHeaders("*");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package codezap.global.validation;

public class ValidationGroups {
public interface NotNullGroup {}
public interface ByteLengthGroup {}
public interface SizeCheckGroup {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package codezap.global.validation;

import jakarta.validation.GroupSequence;

import codezap.global.validation.ValidationGroups.ByteLengthGroup;
import codezap.global.validation.ValidationGroups.NotNullGroup;
import codezap.global.validation.ValidationGroups.SizeCheckGroup;

@GroupSequence({NotNullGroup.class, SizeCheckGroup.class, ByteLengthGroup.class})
public interface ValidationSequence {
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface SpringDocTemplateController {

@Operation(summary = "템플릿 생성", description = """
새로운 템플릿을 생성합니다. \n
템플릿의 제목, 썸네일 스니펫의 순서, 스니펫 목록이 필요합니다. \n
템플릿의 제목, 썸네일 스니펫의 순서, 스니펫 목록, 카테고리 ID, 태그 목록이 필요합니다. \n
스니펫 목록은 파일 이름, 소스 코드, 해당 스니펫의 순서가 필요합니다. \n
* 썸네일 스니펫은 1로 고정입니다. (2024.07.15 기준) \n
* 모든 스니펫 순서는 1부터 시작합니다. \n
Expand All @@ -31,7 +31,7 @@ public interface SpringDocTemplateController {
@Header(name = "생성된 템플릿의 API 경로", example = "/templates/1")})
@ApiErrorResponse(status = HttpStatus.BAD_REQUEST, instance = "/templates/1", errorCases = {
@ErrorCase(description = "모든 필드 중 null인 값이 있는 경우", exampleMessage = "템플릿 이름 null 입니다."),
@ErrorCase(description = "제목 또는 스니펫 파일명이 255자를 초과한 경우", exampleMessage = "제목은 최대 255자까지 입력 가능합니다."),
@ErrorCase(description = "제목 또는 스니펫 파일 또는 태그 이름이 255자를 초과한 경우", exampleMessage = "제목은 최대 255자까지 입력 가능합니다."),
@ErrorCase(description = "썸네일 스니펫의 순서가 1이 아닌 경우", exampleMessage = "썸네일 스니펫의 순서가 잘못되었습니다."),
@ErrorCase(description = "스니펫 순서가 잘못된 경우", exampleMessage = "스니펫 순서가 잘못되었습니다."),
@ErrorCase(description = "스니펫 내용 65,535 byte를 초과한 경우", exampleMessage = "파일 내용은 최대 65,535 byte까지 입력 가능합니다.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

import java.net.URI;

import jakarta.validation.Valid;

import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -13,6 +12,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import codezap.global.validation.ValidationSequence;
import codezap.template.dto.request.CreateTemplateRequest;
import codezap.template.dto.request.UpdateTemplateRequest;
import codezap.template.dto.response.FindAllTemplatesResponse;
Expand All @@ -30,7 +30,7 @@ public TemplateController(TemplateService templateService) {
}

@PostMapping
public ResponseEntity<Void> create(@Valid @RequestBody CreateTemplateRequest createTemplateRequest) {
public ResponseEntity<Void> create(@Validated(ValidationSequence.class) @RequestBody CreateTemplateRequest createTemplateRequest) {
return ResponseEntity.created(URI.create("/templates/" + templateService.create(createTemplateRequest)))
.build();
}
Expand All @@ -48,7 +48,7 @@ public ResponseEntity<FindTemplateByIdResponse> getTemplateById(@PathVariable Lo
@PostMapping("/{id}")
public ResponseEntity<Void> updateTemplate(
@PathVariable Long id,
@Valid @RequestBody UpdateTemplateRequest updateTemplateRequest
@Validated(ValidationSequence.class) @RequestBody UpdateTemplateRequest updateTemplateRequest
) {
templateService.update(id, updateTemplateRequest);
return ResponseEntity.ok().build();
Expand Down
6 changes: 4 additions & 2 deletions backend/src/main/java/codezap/template/domain/Template.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ public class Template extends BaseTimeEntity {
@ManyToOne(optional = false)
private Category category;

public Template(String title, Category category) {
public Template(String title, String description, Category category) {
this.title = title;
this.description = description;
this.category = category;
}

public void updateTitle(String title, Category category) {
public void updateTemplate(String title, String description, Category category) {
this.title = title;
this.description = description;
this.category = category;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@
import jakarta.validation.constraints.Size;

import codezap.global.validation.ByteLength;
import codezap.global.validation.ValidationGroups.ByteLengthGroup;
import codezap.global.validation.ValidationGroups.NotNullGroup;
import codezap.global.validation.ValidationGroups.SizeCheckGroup;
import io.swagger.v3.oas.annotations.media.Schema;

public record CreateSnippetRequest(
@Schema(description = "파일 이름", example = "Main.java")
@NotNull(message = "파일 이름이 null 입니다.")
@Size(max = 255, message = "파일 이름은 최대 255자까지 입력 가능합니다.")
@NotNull(message = "파일 이름이 null 입니다.", groups = NotNullGroup.class)
@Size(max = 255, message = "파일 이름은 최대 255자까지 입력 가능합니다.", groups = SizeCheckGroup.class)
String filename,

@Schema(description = "소스 코드", example = "public class Main { // ...")
@NotNull(message = "파일 내용이 null 입니다.")
@ByteLength(max = 65_535, message = "파일 내용은 최대 65,535 Byte까지 입력 가능합니다.")
@NotNull(message = "파일 내용이 null 입니다.", groups = NotNullGroup.class)
@ByteLength(max = 65_535, message = "파일 내용은 최대 65,535 Byte까지 입력 가능합니다.", groups = ByteLengthGroup.class)
String content,

@Schema(description = "스니펫 순서", example = "1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,35 @@
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import codezap.global.validation.ByteLength;
import codezap.global.validation.ValidationGroups.ByteLengthGroup;
import codezap.global.validation.ValidationGroups.NotNullGroup;
import codezap.global.validation.ValidationGroups.SizeCheckGroup;
import codezap.template.dto.request.validation.ValidatedSnippetsOrdinalRequest;
import io.swagger.v3.oas.annotations.media.Schema;

public record CreateTemplateRequest(
@Schema(description = "템플릿 이름", example = "스프링 로그인 구현")
@NotNull(message = "템플릿 이름이 null 입니다.")
@Size(max = 255, message = "템플릿 이름은 최대 255자까지 입력 가능합니다.")
@NotNull(message = "템플릿 이름이 null 입니다.", groups = NotNullGroup.class)
@Size(max = 255, message = "템플릿 이름은 최대 255자까지 입력 가능합니다.", groups = SizeCheckGroup.class)
String title,

@Schema(description = "템플릿 설명", example = "JWT를 사용하여 로그인 기능을 구현함")
@NotNull(message = "템플릿 설명이 null 입니다.", groups = NotNullGroup.class)
@ByteLength(max = 65_535, message = "템플릿 설명은 최대 65,535 Byte까지 입력 가능합니다.", groups = ByteLengthGroup.class)
String description,

@Schema(description = "템플릿의 스니펫 내역")
@NotNull(message = "스니펫 리스트가 null 입니다.")
@NotNull(message = "스니펫 리스트가 null 입니다.", groups = NotNullGroup.class)
@Valid
List<CreateSnippetRequest> snippets,

@Schema(description = "카테고리 ID", example = "1")
@NotNull(message = "카테고리 id가 null 입니다.")
Long categoryId,

@Schema(description = "태그 리스트")
@NotNull(message = "태그 리스트가 null 입니다.")
List<String> tags
) implements ValidatedSnippetsOrdinalRequest {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import jakarta.validation.constraints.Size;

import codezap.global.validation.ByteLength;
import codezap.global.validation.ValidationGroups.ByteLengthGroup;
import codezap.global.validation.ValidationGroups.NotNullGroup;
import codezap.global.validation.ValidationGroups.SizeCheckGroup;
import io.swagger.v3.oas.annotations.media.Schema;

public record UpdateSnippetRequest(
Expand All @@ -12,13 +15,13 @@ public record UpdateSnippetRequest(
Long id,

@Schema(description = "파일 이름", example = "Main.java")
@NotNull(message = "파일 이름이 null 입니다.")
@Size(max = 255, message = "파일 이름은 최대 255자까지 입력 가능합니다.")
@NotNull(message = "파일 이름이 null 입니다.", groups = NotNullGroup.class)
@Size(max = 255, message = "파일 이름은 최대 255자까지 입력 가능합니다.", groups = SizeCheckGroup.class)
String filename,

@Schema(description = "소스 코드", example = "public class Main { // ...")
@NotNull(message = "파일 내용이 null 입니다.")
@ByteLength(max = 65_535, message = "파일 내용은 최대 65,535 Byte까지 입력 가능합니다.")
@NotNull(message = "파일 내용이 null 입니다.", groups = NotNullGroup.class)
@ByteLength(max = 65_535, message = "파일 내용은 최대 65,535 Byte까지 입력 가능합니다.", groups = ByteLengthGroup.class)
String content,

@Schema(description = "스니펫 순서", example = "1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,48 @@
import java.util.List;
import java.util.stream.Stream;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import codezap.global.validation.ByteLength;
import codezap.global.validation.ValidationGroups.ByteLengthGroup;
import codezap.global.validation.ValidationGroups.NotNullGroup;
import codezap.global.validation.ValidationGroups.SizeCheckGroup;
import codezap.template.dto.request.validation.ValidatedSnippetsOrdinalRequest;
import io.swagger.v3.oas.annotations.media.Schema;

public record UpdateTemplateRequest(
@Schema(description = "템플릿 이름", example = "스프링 로그인 구현")
@NotNull(message = "템플릿 이름이 null 입니다.")
@NotNull(message = "템플릿 이름이 null 입니다.", groups = NotNullGroup.class)
@Size(max = 255, message = "템플릿 이름은 최대 255자까지 입력 가능합니다.", groups = SizeCheckGroup.class)
String title,

@Schema(description = "템플릿 설명", example = "JWT를 사용하여 로그인 기능을 구현함")
@NotNull(message = "템플릿 설명이 null 입니다.", groups = NotNullGroup.class)
@ByteLength(max = 65_535, message = "템플릿 설명은 최대 65,535 Byte까지 입력 가능합니다.", groups = ByteLengthGroup.class)
String description,

@Schema(description = "새로 추가한 스니펫 내역")
@NotNull(message = "createSnippets 리스트가 null 입니다.")
@NotNull(message = "createSnippets 리스트가 null 입니다.", groups = NotNullGroup.class)
@Valid
List<CreateSnippetRequest> createSnippets,

@Schema(description = "삭제, 생성 스니펫을 제외한 모든 스니펫 내역")
@NotNull(message = "updateSnippets 리스트가 null 입니다.")
@NotNull(message = "updateSnippets 리스트가 null 입니다.", groups = NotNullGroup.class)
@Valid
List<UpdateSnippetRequest> updateSnippets,

@Schema(description = "삭제한 스니펫 식별자")
@NotNull(message = "deleteSnippetIds 리스트가 null 입니다.")
List<Long> deleteSnippetIds,

@Schema(description = "카테고리 ID", example = "1")
@NotNull(message = "카테고리 id가 null 입니다.")
Long categoryId,

@Schema(description = "태그 리스트")
@NotNull(message = "태그 리스트가 null 입니다.")
List<String> tags
) implements ValidatedSnippetsOrdinalRequest {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
public record FindAllSnippetByTemplateResponse(
@Schema(description = "파일 식별자", example = "0")
Long id,

@Schema(description = "파일 이름", example = "Main.java")
String filename,

@Schema(description = "소스 코드", example = "public class Main { // ...")
String content,

@Schema(description = "스니펫의 순서", example = "1")
int ordinal
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package codezap.template.dto.response;

import codezap.template.domain.Tag;
import io.swagger.v3.oas.annotations.media.Schema;

public record FindTagByIdResponse(
@Schema(description = "태그 식별자", example = "1")
Long id,

@Schema(description = "태그 이름", example = "스프링")
String name
) {
public static FindTagByIdResponse from(Tag tag) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ public record FindTemplateByIdResponse(
@Schema(description = "템플릿 이름", example = "스프링 로그인 구현")
String title,

@Schema(description = "템플릿 설명", example = "JWT를 사용하여 로그인 기능을 구현함")
String description,

@Schema(description = "스니펫 목록")
List<FindAllSnippetByTemplateResponse> snippets,

@Schema(description = "카테고리 정보")
FindCategoryByIdResponse category,

@Schema(description = "태그 목록")
List<FindTagByIdResponse> tags,

@Schema(description = "템플릿 수정 시간", example = "2024-11-11 12:00", type = "string")
Expand All @@ -30,6 +35,7 @@ public static FindTemplateByIdResponse of(Template template, List<Snippet> snipp
return new FindTemplateByIdResponse(
template.getId(),
template.getTitle(),
template.getDescription(),
mapToFindAllSnippetByTemplateResponse(snippets),
FindCategoryByIdResponse.from(template.getCategory()),
mapToFindTagByTemplateResponse(tags),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
public record FindThumbnailSnippetResponse(
@Schema(description = "파일 이름", example = "Main.java")
String filename,

@Schema(description = "목록 조회 시 보여질 코드", example = "public class Main { // ...")
String thumbnailContent
) {
Expand Down
Loading