Files
goldenChart/backend/src/main/java/com/goldenchart/controller/ChartSettingsController.java
T
2026-05-23 15:11:48 +09:00

147 lines
5.6 KiB
Java

package com.goldenchart.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.goldenchart.entity.GcChartSlot;
import com.goldenchart.entity.GcChartWorkspace;
import com.goldenchart.service.ChartSettingsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 차트 워크스페이스 설정 REST API.
*
* GET /api/chart/workspace - 전체 설정 로드 (프론트 시작 시 호출)
* POST /api/chart/workspace - 전체 설정 저장
* PUT /api/chart/workspace/layout - 레이아웃만 변경
* PUT /api/chart/slot/{index} - 특정 슬롯 저장
*/
@RestController
@RequestMapping("/chart")
@RequiredArgsConstructor
@Slf4j
public class ChartSettingsController {
private final ChartSettingsService settingsService;
private final ObjectMapper objectMapper;
/** 헤더에서 userId 또는 deviceId 추출 */
private Long userId(Map<String, String> headers) {
String v = headers.get("x-user-id");
return v != null ? Long.parseLong(v) : null;
}
private String deviceId(Map<String, String> headers) {
return headers.getOrDefault("x-device-id", "anonymous");
}
/**
* 프론트엔드 시작 시 전체 워크스페이스 로드.
* DB에 저장된 설정이 없으면 204 반환 → 프론트는 기본값 사용.
*/
@GetMapping("/workspace")
public ResponseEntity<?> getWorkspace(
@RequestHeader Map<String, String> headers) {
GcChartWorkspace ws = settingsService.getWorkspaceWithSlots(
userId(headers), deviceId(headers));
if (ws == null) return ResponseEntity.noContent().build();
return ResponseEntity.ok(toDto(ws));
}
/**
* 전체 워크스페이스 저장 (자동 저장 / 명시 저장).
*/
@PostMapping("/workspace")
public ResponseEntity<?> saveWorkspace(
@RequestHeader Map<String, String> headers,
@RequestBody Map<String, Object> body) {
Long uid = userId(headers);
String did = deviceId(headers);
String layoutId = (String) body.getOrDefault("layoutId", "1");
String syncJson = body.containsKey("syncOptions")
? toJson(body.get("syncOptions")) : null;
@SuppressWarnings("unchecked")
List<Map<String, Object>> slotsData = (List<Map<String, Object>>) body.get("slots");
GcChartWorkspace ws = settingsService.saveAll(uid, did, layoutId, syncJson,
slotsData != null ? slotsData : List.of());
return ResponseEntity.ok(toDto(ws));
}
/**
* 레이아웃만 변경.
*/
@PutMapping("/workspace/layout")
public ResponseEntity<?> updateLayout(
@RequestHeader Map<String, String> headers,
@RequestBody Map<String, Object> body) {
String layoutId = (String) body.get("layoutId");
String syncJson = body.containsKey("syncOptions") ? toJson(body.get("syncOptions")) : null;
GcChartWorkspace ws = settingsService.saveWorkspace(
userId(headers), deviceId(headers), layoutId, syncJson);
return ResponseEntity.ok(Map.of("layoutId", ws.getLayoutId()));
}
/**
* 특정 슬롯 설정 저장.
*/
@PutMapping("/slot/{slotIndex}")
public ResponseEntity<?> saveSlot(
@RequestHeader Map<String, String> headers,
@PathVariable int slotIndex,
@RequestBody Map<String, Object> body) {
GcChartSlot slot = settingsService.saveSlot(
userId(headers), deviceId(headers), slotIndex, body);
return ResponseEntity.ok(slotToDto(slot));
}
// ── DTO 변환 ────────────────────────────────────────────────────────────────
private Map<String, Object> toDto(GcChartWorkspace ws) {
Map<String, Object> dto = new HashMap<>();
dto.put("id", ws.getId());
dto.put("layoutId", ws.getLayoutId());
dto.put("syncOptions", parseJson(ws.getSyncOptionsJson()));
dto.put("slots", ws.getSlots().stream()
.map(this::slotToDto)
.collect(Collectors.toList()));
return dto;
}
private Map<String, Object> slotToDto(GcChartSlot s) {
Map<String, Object> dto = new HashMap<>();
dto.put("slotIndex", s.getSlotIndex());
dto.put("symbol", s.getSymbol());
dto.put("timeframe", s.getTimeframe());
dto.put("chartType", s.getChartType());
dto.put("theme", s.getTheme());
dto.put("mode", s.getMode());
dto.put("logScale", s.getLogScale());
dto.put("drawingsLocked", s.getDrawingsLocked());
dto.put("drawingsVisible", s.getDrawingsVisible());
dto.put("indicators", parseJson(s.getIndicatorsJson()));
dto.put("drawings", parseJson(s.getDrawingsJson()));
dto.put("paneLayout", parseJson(s.getPaneLayoutJson()));
dto.put("mainChartStyle", parseJson(s.getMainChartStyleJson()));
return dto;
}
private Object parseJson(String json) {
if (json == null) return null;
try { return objectMapper.readValue(json, Object.class); }
catch (Exception e) { return null; }
}
private String toJson(Object obj) {
try { return objectMapper.writeValueAsString(obj); }
catch (Exception e) { return null; }
}
}