mirror of
https://github.com/hwanny1128/HGZero.git
synced 2026-06-13 05:59:11 +00:00
템플릿 목록 조회 API 개발
This commit is contained in:
@@ -50,6 +50,7 @@ public class SecurityConfig {
|
||||
// Meeting API endpoints (for testing)
|
||||
.requestMatchers("/api/meetings/**").permitAll()
|
||||
// All other requests require authentication
|
||||
.requestMatchers("/api/templates/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
|
||||
|
||||
+104
-127
@@ -1,13 +1,8 @@
|
||||
package com.unicorn.hgzero.meeting.infra.controller;
|
||||
|
||||
import com.unicorn.hgzero.common.dto.ApiResponse;
|
||||
import com.unicorn.hgzero.meeting.biz.dto.TemplateDTO;
|
||||
import com.unicorn.hgzero.meeting.biz.service.TemplateService;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.response.TemplateListResponse;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.response.TemplateDetailResponse;
|
||||
import com.unicorn.hgzero.meeting.infra.cache.CacheService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -15,12 +10,14 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 템플릿 관리 API Controller
|
||||
* 템플릿 목록 조회, 상세 조회 기능
|
||||
* 템플릿 관리API Controller
|
||||
* 고정된 템플릿 목록을 제공합니다
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/templates")
|
||||
@@ -29,11 +26,8 @@ import java.util.stream.Collectors;
|
||||
@Tag(name = "Template", description = "템플릿 관리 API")
|
||||
public class TemplateController {
|
||||
|
||||
private final TemplateService templateService;
|
||||
private final CacheService cacheService;
|
||||
|
||||
/**
|
||||
* 템플릿 목록 조회
|
||||
* 템플릿 목록 조회 (고정 데이터 반환)
|
||||
* GET /api/templates
|
||||
*/
|
||||
@GetMapping
|
||||
@@ -45,40 +39,19 @@ public class TemplateController {
|
||||
})
|
||||
public ResponseEntity<ApiResponse<TemplateListResponse>> getTemplateList(
|
||||
@RequestHeader("X-User-Id") String userId,
|
||||
@RequestHeader("X-User-Name") String userName,
|
||||
@Parameter(description = "템플릿 카테고리") @RequestParam(required = false) String category,
|
||||
@Parameter(description = "활성 상태 (true: 활성, false: 비활성)") @RequestParam(required = false) Boolean isActive) {
|
||||
@RequestHeader("X-User-Name") String userName) {
|
||||
|
||||
log.info("템플릿 목록 조회 요청 - userId: {}, category: {}, isActive: {}",
|
||||
userId, category, isActive);
|
||||
log.info("템플릿 목록 조회 요청 - userId: {}", userId);
|
||||
|
||||
try {
|
||||
// 캐시 확인
|
||||
String cacheKey = String.format("templates:list:%s:%s",
|
||||
(category != null ? category : "all"),
|
||||
(isActive != null ? isActive.toString() : "all"));
|
||||
TemplateListResponse cachedResponse = cacheService.getCachedTemplateList(cacheKey);
|
||||
if (cachedResponse != null) {
|
||||
log.debug("캐시된 템플릿 목록 반환");
|
||||
return ResponseEntity.ok(ApiResponse.success(cachedResponse));
|
||||
}
|
||||
|
||||
// 템플릿 목록 조회
|
||||
List<TemplateDTO> templates = templateService.getTemplateList(category, isActive);
|
||||
|
||||
// 응답 DTO 생성
|
||||
List<TemplateListResponse.TemplateItem> templateItems = templates.stream()
|
||||
.map(this::convertToTemplateItem)
|
||||
.collect(Collectors.toList());
|
||||
// 고정된 템플릿 데이터 생성
|
||||
List<TemplateListResponse.TemplateItem> templateItems = createFixedTemplates();
|
||||
|
||||
TemplateListResponse response = TemplateListResponse.builder()
|
||||
.templateList(templateItems)
|
||||
.totalCount(templateItems.size())
|
||||
.build();
|
||||
|
||||
// 캐시 저장
|
||||
cacheService.cacheTemplateList(cacheKey, response);
|
||||
|
||||
log.info("템플릿 목록 조회 성공 - count: {}", templateItems.size());
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
|
||||
@@ -90,99 +63,103 @@ public class TemplateController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 상세 조회
|
||||
* GET /api/templates/{templateId}
|
||||
* 고정된 템플릿 데이터 생성
|
||||
*/
|
||||
@GetMapping("/{templateId}")
|
||||
@Operation(summary = "템플릿 상세 조회", description = "템플릿 상세 정보를 조회합니다")
|
||||
public ResponseEntity<ApiResponse<TemplateDetailResponse>> getTemplateDetail(
|
||||
@RequestHeader("X-User-Id") String userId,
|
||||
@RequestHeader("X-User-Name") String userName,
|
||||
@Parameter(description = "템플릿 ID") @PathVariable String templateId) {
|
||||
|
||||
log.info("템플릿 상세 조회 요청 - userId: {}, templateId: {}", userId, templateId);
|
||||
|
||||
try {
|
||||
// 캐시 확인
|
||||
TemplateDetailResponse cachedResponse = cacheService.getCachedTemplateDetail(templateId);
|
||||
if (cachedResponse != null) {
|
||||
log.debug("캐시된 템플릿 상세 반환 - templateId: {}", templateId);
|
||||
return ResponseEntity.ok(ApiResponse.success(cachedResponse));
|
||||
}
|
||||
|
||||
// 템플릿 조회
|
||||
TemplateDTO templateDTO = templateService.getTemplateById(templateId);
|
||||
|
||||
// 응답 DTO 생성
|
||||
TemplateDetailResponse response = convertToTemplateDetailResponse(templateDTO);
|
||||
|
||||
// 캐시 저장
|
||||
cacheService.cacheTemplateDetail(templateId, response);
|
||||
|
||||
log.info("템플릿 상세 조회 성공 - templateId: {}", templateId);
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("템플릿 상세 조회 실패 - templateId: {}", templateId, e);
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.errorWithType("템플릿 상세 조회에 실패했습니다"));
|
||||
}
|
||||
private List<TemplateListResponse.TemplateItem> createFixedTemplates() {
|
||||
List<TemplateListResponse.TemplateItem> templates = new ArrayList<>();
|
||||
|
||||
// 일반 회의 템플릿
|
||||
templates.add(TemplateListResponse.TemplateItem.builder()
|
||||
.templateId("general")
|
||||
.name("일반 회의")
|
||||
.description("기본 회의록 형식")
|
||||
.category("meeting")
|
||||
.icon("📋")
|
||||
.isActive(true)
|
||||
.usageCount(0)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.lastUsedAt(null)
|
||||
.createdBy("system")
|
||||
.sections(Arrays.asList(
|
||||
createSectionInfo("회의 개요", "회의 기본 정보", 1, true),
|
||||
createSectionInfo("논의 사항", "주요 논의 내용", 2, true),
|
||||
createSectionInfo("결정 사항", "회의에서 결정된 사항", 3, true),
|
||||
createSectionInfo("액션 아이템", "향후 진행할 작업", 4, true)
|
||||
))
|
||||
.build());
|
||||
|
||||
// 스크럼 회의 템플릿
|
||||
templates.add(TemplateListResponse.TemplateItem.builder()
|
||||
.templateId("scrum")
|
||||
.name("스크럼 회의")
|
||||
.description("데일리 스탠드업 형식")
|
||||
.category("agile")
|
||||
.icon("🏃")
|
||||
.isActive(true)
|
||||
.usageCount(0)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.lastUsedAt(null)
|
||||
.createdBy("system")
|
||||
.sections(Arrays.asList(
|
||||
createSectionInfo("어제 한 일", "지난 작업일에 완료한 작업", 1, true),
|
||||
createSectionInfo("오늘 할 일", "오늘 진행할 예정 작업", 2, true),
|
||||
createSectionInfo("블로커/이슈", "진행을 방해하는 요소", 3, false)
|
||||
))
|
||||
.build());
|
||||
|
||||
// 킥오프 회의 템플릿
|
||||
templates.add(TemplateListResponse.TemplateItem.builder()
|
||||
.templateId("kickoff")
|
||||
.name("킥오프 회의")
|
||||
.description("프로젝트 시작 회의")
|
||||
.category("project")
|
||||
.icon("🚀")
|
||||
.isActive(true)
|
||||
.usageCount(0)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.lastUsedAt(null)
|
||||
.createdBy("system")
|
||||
.sections(Arrays.asList(
|
||||
createSectionInfo("프로젝트 개요", "프로젝트 기본 정보", 1, true),
|
||||
createSectionInfo("목표 및 범위", "프로젝트 목표와 범위", 2, true),
|
||||
createSectionInfo("역할 및 책임", "팀원별 역할과 책임", 3, true),
|
||||
createSectionInfo("일정 및 마일스톤", "프로젝트 일정", 4, true)
|
||||
))
|
||||
.build());
|
||||
|
||||
// 주간 회의 템플릿
|
||||
templates.add(TemplateListResponse.TemplateItem.builder()
|
||||
.templateId("weekly")
|
||||
.name("주간 회의")
|
||||
.description("주간 리뷰 및 계획")
|
||||
.category("review")
|
||||
.icon("📅")
|
||||
.isActive(true)
|
||||
.usageCount(0)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.lastUsedAt(null)
|
||||
.createdBy("system")
|
||||
.sections(Arrays.asList(
|
||||
createSectionInfo("지난주 성과", "지난주 달성한 성과", 1, true),
|
||||
createSectionInfo("이번주 계획", "이번주 진행할 계획", 2, true),
|
||||
createSectionInfo("주요 이슈", "해결이 필요한 이슈", 3, false),
|
||||
createSectionInfo("다음 액션", "다음 주 액션 아이템", 4, true)
|
||||
))
|
||||
.build());
|
||||
|
||||
return templates;
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
private TemplateListResponse.TemplateItem convertToTemplateItem(TemplateDTO templateDTO) {
|
||||
// 섹션 정보 변환
|
||||
List<TemplateListResponse.TemplateSectionInfo> sections = templateDTO.getSections().stream()
|
||||
.map(section -> TemplateListResponse.TemplateSectionInfo.builder()
|
||||
.title(section.getTitle())
|
||||
.description(section.getDescription())
|
||||
.orderIndex(section.getOrderIndex())
|
||||
.isRequired(section.isRequired())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return TemplateListResponse.TemplateItem.builder()
|
||||
.templateId(templateDTO.getTemplateId())
|
||||
.name(templateDTO.getName())
|
||||
.description(templateDTO.getDescription())
|
||||
.category(templateDTO.getCategory())
|
||||
.isActive(templateDTO.isActive())
|
||||
.usageCount(templateDTO.getUsageCount())
|
||||
.createdAt(templateDTO.getCreatedAt())
|
||||
.lastUsedAt(templateDTO.getLastUsedAt())
|
||||
.createdBy(templateDTO.getCreatedBy())
|
||||
.sections(sections)
|
||||
.build();
|
||||
}
|
||||
|
||||
private TemplateDetailResponse convertToTemplateDetailResponse(TemplateDTO templateDTO) {
|
||||
// 섹션 상세 정보 변환
|
||||
List<TemplateDetailResponse.SectionDetail> sections = templateDTO.getSections().stream()
|
||||
.map(section -> TemplateDetailResponse.SectionDetail.builder()
|
||||
.sectionId(section.getSectionId())
|
||||
.title(section.getTitle())
|
||||
.description(section.getDescription())
|
||||
.content(section.getContent())
|
||||
.orderIndex(section.getOrderIndex())
|
||||
.isRequired(section.isRequired())
|
||||
.inputType(section.getInputType())
|
||||
.placeholder(section.getPlaceholder())
|
||||
.maxLength(section.getMaxLength())
|
||||
.isEditable(section.isEditable())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return TemplateDetailResponse.builder()
|
||||
.templateId(templateDTO.getTemplateId())
|
||||
.name(templateDTO.getName())
|
||||
.description(templateDTO.getDescription())
|
||||
.category(templateDTO.getCategory())
|
||||
.isActive(templateDTO.isActive())
|
||||
.usageCount(templateDTO.getUsageCount())
|
||||
.createdAt(templateDTO.getCreatedAt())
|
||||
.lastUsedAt(templateDTO.getLastUsedAt())
|
||||
.createdBy(templateDTO.getCreatedBy())
|
||||
.sections(sections)
|
||||
/**
|
||||
* 템플릿 섹션 정보 생성 헬퍼 메서드
|
||||
*/
|
||||
private TemplateListResponse.TemplateSectionInfo createSectionInfo(
|
||||
String title, String description, int orderIndex, boolean isRequired) {
|
||||
return TemplateListResponse.TemplateSectionInfo.builder()
|
||||
.title(title)
|
||||
.description(description)
|
||||
.orderIndex(orderIndex)
|
||||
.isRequired(isRequired)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
+1
@@ -29,6 +29,7 @@ public class TemplateListResponse {
|
||||
private String name;
|
||||
private String description;
|
||||
private String category;
|
||||
private String icon; // 아이콘 추가
|
||||
private boolean isActive;
|
||||
private int usageCount;
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
Reference in New Issue
Block a user