acbab68a12
1. 운영 console.log/warn 제거 (G15) — page.tsx 의 이모지 prefix 디버그 로그 (🔍 🔄 ✅ 🗑️ 📥 📊 📋) 일괄 제거. catch 블록의 console.error 는 추적용으로 유지. CreateTableModal 의 컬럼 조회 디버그 로그도 정리. 2. useLogTable dead code 정리 (G16) — CreateTableModal 의 useLogTable state, handleCreateTable 분기, 주석 처리된 체크박스 UI 모두 제거. 시그니처 안 맞는 createLogTable 호출 페이로드까지 같이 사라짐. Activity / Checkbox import 도 필요 없어졌으므로 제거. 3. 에러 메시지 일관화 (G17) — DdlController 와 TableManagementController 의 "최고 관리자 권한이 필요합니다." 메시지 모두 "최고 관리자(SUPER_ADMIN) 권한이 필요합니다." 로 통일. 일반 ADMIN 권한 메시지는 그대로 유지. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
712 lines
39 KiB
Java
712 lines
39 KiB
Java
package com.erp.controller;
|
|
|
|
import com.erp.dto.ApiResponse;
|
|
import com.erp.service.TableManagementService;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.http.ResponseEntity;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
@RestController
|
|
@RequestMapping("/api/table-management")
|
|
@RequiredArgsConstructor
|
|
@Slf4j
|
|
public class TableManagementController {
|
|
|
|
private final TableManagementService tableManagementService;
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 테이블 목록
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** GET /api/table-management/tables */
|
|
@GetMapping("/tables")
|
|
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableList() {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getTableList(), "테이블 목록을 성공적으로 조회했습니다."));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 엔티티 관계 (literal segment이 path variable보다 우선)
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** GET /api/table-management/tables/entity-relations */
|
|
@GetMapping("/tables/entity-relations")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableEntityRelations(
|
|
@RequestParam String leftTable,
|
|
@RequestParam String rightTable,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getTableEntityRelations(leftTable, rightTable, companyCode)));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 컬럼 목록
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** GET /api/table-management/tables/:tableName/columns */
|
|
@GetMapping("/tables/{tableName}/columns")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> getColumnList(
|
|
@PathVariable String tableName,
|
|
@RequestParam(defaultValue = "1") int page,
|
|
@RequestParam(defaultValue = "50") int size,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getColumnList(tableName, page, size, companyCode),
|
|
"컬럼 목록을 성공적으로 조회했습니다."));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 테이블 라벨
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** GET /api/table-management/tables/:tableName/labels */
|
|
@GetMapping("/tables/{tableName}/labels")
|
|
public ResponseEntity<ApiResponse<Object>> getTableLabels(@PathVariable String tableName) {
|
|
Map<String, Object> labels = tableManagementService.getTableLabels(tableName);
|
|
Object data = labels != null ? labels : Map.of();
|
|
return ResponseEntity.ok(ApiResponse.success(data, "테이블 라벨 정보를 조회했습니다."));
|
|
}
|
|
|
|
/** PUT /api/table-management/tables/:tableName/label */
|
|
@PutMapping("/tables/{tableName}/label")
|
|
public ResponseEntity<ApiResponse<Void>> updateTableLabel(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("role") String role) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
String displayName = (String) body.get("display_name");
|
|
String description = (String) body.get("description");
|
|
if (displayName == null || displayName.isBlank()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("표시명이 필요합니다."));
|
|
}
|
|
tableManagementService.updateTableLabel(tableName, displayName, description);
|
|
return ResponseEntity.ok(ApiResponse.success(null, "테이블 라벨이 성공적으로 설정되었습니다."));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 컬럼 설정
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** GET /api/table-management/tables/:tableName/columns/:columnName/labels */
|
|
@GetMapping("/tables/{tableName}/columns/{columnName}/labels")
|
|
public ResponseEntity<ApiResponse<Object>> getColumnLabels(
|
|
@PathVariable String tableName,
|
|
@PathVariable String columnName) {
|
|
Map<String, Object> labels = tableManagementService.getColumnLabels(tableName, columnName);
|
|
Object data = labels != null ? labels : Map.of();
|
|
return ResponseEntity.ok(ApiResponse.success(data, "컬럼 라벨 정보를 조회했습니다."));
|
|
}
|
|
|
|
/** POST /api/table-management/tables/:tableName/columns/:columnName/settings */
|
|
@PostMapping("/tables/{tableName}/columns/{columnName}/settings")
|
|
public ResponseEntity<ApiResponse<Void>> updateColumnSettingsPost(
|
|
@PathVariable String tableName,
|
|
@PathVariable String columnName,
|
|
@RequestBody Map<String, Object> settings,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
return doUpdateColumnSettings(tableName, columnName, settings, companyCode);
|
|
}
|
|
|
|
/** PUT /api/table-management/tables/:tableName/columns/:columnName */
|
|
@PutMapping("/tables/{tableName}/columns/{columnName}")
|
|
public ResponseEntity<ApiResponse<Void>> updateColumnSettingsPut(
|
|
@PathVariable String tableName,
|
|
@PathVariable String columnName,
|
|
@RequestBody Map<String, Object> settings,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
return doUpdateColumnSettings(tableName, columnName, settings, companyCode);
|
|
}
|
|
|
|
private ResponseEntity<ApiResponse<Void>> doUpdateColumnSettings(
|
|
String tableName, String columnName, Map<String, Object> settings, String companyCode) {
|
|
if (tableName == null || columnName == null) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("테이블명과 컬럼명이 필요합니다."));
|
|
}
|
|
if (settings == null) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("컬럼 설정 정보가 필요합니다."));
|
|
}
|
|
tableManagementService.updateColumnSettings(tableName, columnName, settings, companyCode);
|
|
return ResponseEntity.ok(ApiResponse.success(null, "컬럼 설정을 성공적으로 저장했습니다."));
|
|
}
|
|
|
|
/** POST /api/table-management/tables/:tableName/columns/settings (batch) */
|
|
@PostMapping("/tables/{tableName}/columns/settings")
|
|
public ResponseEntity<ApiResponse<Void>> updateAllColumnSettingsPost(
|
|
@PathVariable String tableName,
|
|
@RequestBody List<Map<String, Object>> columnSettings,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
return doUpdateAllColumnSettings(tableName, columnSettings, companyCode);
|
|
}
|
|
|
|
/** PUT /api/table-management/tables/:tableName/columns/batch */
|
|
@PutMapping("/tables/{tableName}/columns/batch")
|
|
public ResponseEntity<ApiResponse<Void>> updateAllColumnSettingsBatch(
|
|
@PathVariable String tableName,
|
|
@RequestBody List<Map<String, Object>> columnSettings,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
return doUpdateAllColumnSettings(tableName, columnSettings, companyCode);
|
|
}
|
|
|
|
private ResponseEntity<ApiResponse<Void>> doUpdateAllColumnSettings(
|
|
String tableName, List<Map<String, Object>> columnSettings, String companyCode) {
|
|
if (tableName == null) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("테이블명이 필요합니다."));
|
|
}
|
|
if (columnSettings == null || columnSettings.isEmpty()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("컬럼 설정 목록이 필요합니다."));
|
|
}
|
|
tableManagementService.updateAllColumnSettings(tableName, columnSettings, companyCode);
|
|
return ResponseEntity.ok(ApiResponse.success(null, "모든 컬럼 설정을 성공적으로 저장했습니다."));
|
|
}
|
|
|
|
/** PUT /api/table-management/tables/:tableName/columns/:columnName/web-type */
|
|
@PutMapping("/tables/{tableName}/columns/{columnName}/web-type")
|
|
public ResponseEntity<ApiResponse<Void>> updateColumnWebType(
|
|
@PathVariable String tableName,
|
|
@PathVariable String columnName,
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
String webType = (String) body.get("web_type");
|
|
if (webType == null || webType.isBlank()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("웹 타입이 필요합니다."));
|
|
}
|
|
@SuppressWarnings("unchecked")
|
|
Map<String, Object> detailSettings = (Map<String, Object>) body.get("detail_settings");
|
|
// 멀티테넌트 격리: SUPER_ADMIN(company_code='*') 가 아니면 자기 회사 코드로 저장
|
|
tableManagementService.updateColumnWebType(tableName, columnName, webType, detailSettings, companyCode);
|
|
return ResponseEntity.ok(ApiResponse.success(null, "컬럼 웹타입이 설정되었습니다."));
|
|
}
|
|
|
|
/** PUT /api/table-management/tables/:tableName/columns/:columnName/input-type */
|
|
@PutMapping("/tables/{tableName}/columns/{columnName}/input-type")
|
|
public ResponseEntity<ApiResponse<Void>> updateColumnInputType(
|
|
@PathVariable String tableName,
|
|
@PathVariable String columnName,
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
String inputType = (String) body.get("input_type");
|
|
if (tableName == null || columnName == null || inputType == null || inputType.isBlank()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("테이블명, 컬럼명, 입력 타입이 모두 필요합니다."));
|
|
}
|
|
@SuppressWarnings("unchecked")
|
|
Map<String, Object> detailSettings = (Map<String, Object>) body.get("detail_settings");
|
|
tableManagementService.updateColumnInputType(tableName, columnName, inputType, companyCode, detailSettings);
|
|
return ResponseEntity.ok(ApiResponse.success(null, "컬럼 입력 타입이 성공적으로 설정되었습니다."));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 테이블 스키마 / 존재 여부 / 웹타입
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** GET /api/table-management/tables/:tableName/schema */
|
|
@GetMapping("/tables/{tableName}/schema")
|
|
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableSchema(
|
|
@PathVariable String tableName) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getTableSchema(tableName),
|
|
"테이블 스키마 정보를 성공적으로 조회했습니다."));
|
|
}
|
|
|
|
/** GET /api/table-management/tables/:tableName/exists */
|
|
@GetMapping("/tables/{tableName}/exists")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> checkTableExists(
|
|
@PathVariable String tableName) {
|
|
boolean exists = tableManagementService.checkTableExists(tableName);
|
|
return ResponseEntity.ok(ApiResponse.success(Map.of("exists", exists), "테이블 존재 여부를 확인했습니다."));
|
|
}
|
|
|
|
/** GET /api/table-management/tables/:tableName/web-types */
|
|
@GetMapping("/tables/{tableName}/web-types")
|
|
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getColumnWebTypes(
|
|
@PathVariable String tableName,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getColumnInputTypes(tableName, companyCode),
|
|
"컬럼 입력타입 정보를 성공적으로 조회했습니다."));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 제약조건 관리
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** GET /api/table-management/tables/:tableName/constraints */
|
|
@GetMapping("/tables/{tableName}/constraints")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableConstraints(
|
|
@PathVariable String tableName) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getTableConstraints(tableName)));
|
|
}
|
|
|
|
/** PUT /api/table-management/tables/:tableName/primary-key */
|
|
@PutMapping("/tables/{tableName}/primary-key")
|
|
public ResponseEntity<ApiResponse<Void>> setTablePrimaryKey(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("role") String role) {
|
|
if (!isSuperAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자(SUPER_ADMIN) 권한이 필요합니다."));
|
|
}
|
|
@SuppressWarnings("unchecked")
|
|
List<String> columns = (List<String>) body.get("columns");
|
|
if (tableName == null || columns == null || columns.isEmpty()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("테이블명과 PK 컬럼 배열이 필요합니다."));
|
|
}
|
|
tableManagementService.setTablePrimaryKey(tableName, columns);
|
|
return ResponseEntity.ok(ApiResponse.success(null,
|
|
"PK가 설정되었습니다: " + String.join(", ", columns)));
|
|
}
|
|
|
|
/** POST /api/table-management/tables/:tableName/indexes */
|
|
@PostMapping("/tables/{tableName}/indexes")
|
|
public ResponseEntity<ApiResponse<Void>> toggleTableIndex(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("role") String role) {
|
|
if (!isSuperAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자(SUPER_ADMIN) 권한이 필요합니다."));
|
|
}
|
|
String columnName = (String) body.get("column_name");
|
|
String indexType = (String) body.get("index_type");
|
|
String action = (String) body.get("action");
|
|
if (tableName == null || columnName == null || indexType == null || action == null) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error(
|
|
"tableName, columnName, indexType(index|unique), action(create|drop)이 필요합니다."));
|
|
}
|
|
try {
|
|
tableManagementService.toggleTableIndex(tableName, columnName, indexType, action);
|
|
String msg = "create".equals(action)
|
|
? "인덱스가 생성되었습니다."
|
|
: "인덱스가 삭제되었습니다.";
|
|
return ResponseEntity.ok(ApiResponse.success(null, msg));
|
|
} catch (Exception e) {
|
|
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
|
}
|
|
}
|
|
|
|
/** PUT /api/table-management/tables/:tableName/columns/:columnName/nullable */
|
|
@PutMapping("/tables/{tableName}/columns/{columnName}/nullable")
|
|
public ResponseEntity<ApiResponse<Void>> toggleColumnNullable(
|
|
@PathVariable String tableName,
|
|
@PathVariable String columnName,
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isSuperAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자(SUPER_ADMIN) 권한이 필요합니다."));
|
|
}
|
|
Object nullableObj = body.get("nullable");
|
|
if (tableName == null || columnName == null || !(nullableObj instanceof Boolean)) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("tableName, columnName, nullable(boolean)이 필요합니다."));
|
|
}
|
|
boolean nullable = (Boolean) nullableObj;
|
|
tableManagementService.toggleColumnNullable(tableName, columnName, nullable, companyCode);
|
|
String msg = nullable ? columnName + " 컬럼의 NOT NULL 제약이 해제되었습니다."
|
|
: columnName + " 컬럼이 NOT NULL로 설정되었습니다.";
|
|
return ResponseEntity.ok(ApiResponse.success(null, msg));
|
|
}
|
|
|
|
/** PUT /api/table-management/tables/:tableName/columns/:columnName/unique */
|
|
@PutMapping("/tables/{tableName}/columns/{columnName}/unique")
|
|
public ResponseEntity<ApiResponse<Void>> toggleColumnUnique(
|
|
@PathVariable String tableName,
|
|
@PathVariable String columnName,
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isSuperAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자(SUPER_ADMIN) 권한이 필요합니다."));
|
|
}
|
|
Object uniqueObj = body.get("unique");
|
|
if (tableName == null || columnName == null || !(uniqueObj instanceof Boolean)) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("tableName, columnName, unique(boolean)이 필요합니다."));
|
|
}
|
|
boolean unique = (Boolean) uniqueObj;
|
|
tableManagementService.toggleColumnUnique(tableName, columnName, unique, companyCode);
|
|
String msg = unique ? columnName + " 컬럼이 UNIQUE로 설정되었습니다."
|
|
: columnName + " 컬럼의 UNIQUE 제약이 해제되었습니다.";
|
|
return ResponseEntity.ok(ApiResponse.success(null, msg));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 데이터 CRUD
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** POST /api/table-management/tables/:tableName/data */
|
|
@PostMapping("/tables/{tableName}/data")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableData(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> options) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getTableData(tableName, options),
|
|
"테이블 데이터를 성공적으로 조회했습니다."));
|
|
}
|
|
|
|
/** POST /api/table-management/tables/:tableName/aggregate
|
|
* body: { aggregation: "count"|"sum"|..., columnName?: string, filters?: [...] }
|
|
* → { value: number }
|
|
*/
|
|
@PostMapping("/tables/{tableName}/aggregate")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> aggregateTableData(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> options) {
|
|
try {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.aggregateTableData(tableName, options == null ? Map.of() : options),
|
|
"테이블 집계를 성공적으로 조회했습니다."));
|
|
} catch (IllegalArgumentException e) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
|
}
|
|
}
|
|
|
|
/** POST /api/table-management/tables/:tableName/aggregate-group
|
|
* body: { aggregation, groupBy, valueColumn?, filters?, limit?, orderDir? }
|
|
* → { rows: [{ group, value }, ...] }
|
|
*/
|
|
@PostMapping("/tables/{tableName}/aggregate-group")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> aggregateTableGroup(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> options) {
|
|
try {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.aggregateTableGroup(tableName, options == null ? Map.of() : options),
|
|
"테이블 그룹 집계를 성공적으로 조회했습니다."));
|
|
} catch (IllegalArgumentException e) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
|
}
|
|
}
|
|
|
|
/** POST /api/table-management/tables/:tableName/select-rows
|
|
* body: { columns?, filters?, orderBy?, limit?, offset? }
|
|
* → { rows: [{...}, ...] }
|
|
*/
|
|
@PostMapping("/tables/{tableName}/select-rows")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> selectTableRows(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> options) {
|
|
try {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.selectTableRows(tableName, options == null ? Map.of() : options),
|
|
"테이블 row 를 성공적으로 조회했습니다."));
|
|
} catch (IllegalArgumentException e) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
|
}
|
|
}
|
|
|
|
/** POST /api/table-management/tables/:tableName/record (단일 레코드) */
|
|
@PostMapping("/tables/{tableName}/record")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableRecord(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> body) {
|
|
String filterColumn = (String) body.get("filter_column");
|
|
Object filterValue = body.get("filter_value");
|
|
String displayColumn = (String) body.get("display_column");
|
|
|
|
if (filterColumn == null || filterValue == null) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error(
|
|
"tableName, filterColumn, filterValue가 필요합니다."));
|
|
}
|
|
|
|
Map<String, Object> options = new java.util.HashMap<>();
|
|
options.put("page", 1);
|
|
options.put("size", 1);
|
|
options.put("search", Map.of(filterColumn, filterValue.toString()));
|
|
|
|
Map<String, Object> result = tableManagementService.getTableData(tableName, options);
|
|
@SuppressWarnings("unchecked")
|
|
List<Map<String, Object>> data = (List<Map<String, Object>>) result.get("data");
|
|
|
|
if (data == null || data.isEmpty()) {
|
|
return ResponseEntity.status(404).body(ApiResponse.error("데이터를 찾을 수 없습니다."));
|
|
}
|
|
|
|
Map<String, Object> record = data.get(0);
|
|
Object displayValue = (displayColumn != null && !displayColumn.equals("*"))
|
|
? record.get(displayColumn) : record;
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
Map.of("value", displayValue != null ? displayValue : "", "record", record),
|
|
"레코드를 성공적으로 조회했습니다."));
|
|
}
|
|
|
|
/** POST /api/table-management/tables/:tableName/add */
|
|
@PostMapping("/tables/{tableName}/add")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> addTableData(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> data,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
if (data == null || data.isEmpty()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("추가할 데이터가 필요합니다."));
|
|
}
|
|
|
|
// 멀티테넌시: company_code 자동 추가
|
|
if (!data.containsKey("company_code") && tableManagementService.hasColumn(tableName, "company_code")) {
|
|
data.put("company_code", companyCode);
|
|
}
|
|
|
|
// 소프트 제약조건 검증
|
|
List<String> notNullViolations = tableManagementService.validateNotNullConstraints(tableName, data, companyCode);
|
|
if (!notNullViolations.isEmpty()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error(
|
|
"필수 항목이 비어있습니다: " + String.join(", ", notNullViolations)));
|
|
}
|
|
List<String> uniqueViolations = tableManagementService.validateUniqueConstraints(tableName, data, companyCode, null);
|
|
if (!uniqueViolations.isEmpty()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error(
|
|
"중복된 값이 존재합니다: " + String.join(", ", uniqueViolations)));
|
|
}
|
|
|
|
Map<String, Object> result = tableManagementService.addTableData(tableName, data);
|
|
return ResponseEntity.status(201).body(ApiResponse.success(
|
|
Map.of("id", result.getOrDefault("inserted_id", "")),
|
|
"테이블 데이터를 성공적으로 추가했습니다."));
|
|
}
|
|
|
|
/** PUT /api/table-management/tables/:tableName/edit */
|
|
@PutMapping("/tables/{tableName}/edit")
|
|
public ResponseEntity<ApiResponse<Void>> editTableData(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
@SuppressWarnings("unchecked")
|
|
Map<String, Object> originalData = (Map<String, Object>) body.get("original_data");
|
|
@SuppressWarnings("unchecked")
|
|
Map<String, Object> updatedData = (Map<String, Object>) body.get("updated_data");
|
|
|
|
if (originalData == null || updatedData == null) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("원본 데이터와 수정할 데이터가 모두 필요합니다."));
|
|
}
|
|
if (updatedData.isEmpty()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("수정할 데이터가 없습니다."));
|
|
}
|
|
|
|
// 소프트 제약조건 검증
|
|
List<String> notNullViolations = tableManagementService.validateNotNullConstraints(tableName, updatedData, companyCode);
|
|
if (!notNullViolations.isEmpty()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error(
|
|
"필수 항목이 비어있습니다: " + String.join(", ", notNullViolations)));
|
|
}
|
|
String excludeId = originalData.get("id") != null ? originalData.get("id").toString() : null;
|
|
List<String> uniqueViolations = tableManagementService.validateUniqueConstraints(tableName, updatedData, companyCode, excludeId);
|
|
if (!uniqueViolations.isEmpty()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error(
|
|
"중복된 값이 존재합니다: " + String.join(", ", uniqueViolations)));
|
|
}
|
|
|
|
tableManagementService.editTableData(tableName, originalData, updatedData);
|
|
return ResponseEntity.ok(ApiResponse.success(null, "테이블 데이터를 성공적으로 수정했습니다."));
|
|
}
|
|
|
|
/** DELETE /api/table-management/tables/:tableName/delete */
|
|
@DeleteMapping("/tables/{tableName}/delete")
|
|
public ResponseEntity<ApiResponse<Void>> deleteTableData(
|
|
@PathVariable String tableName,
|
|
@RequestBody Object body,
|
|
@RequestAttribute("role") String role) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
List<Map<String, Object>> dataList;
|
|
if (body instanceof List) {
|
|
@SuppressWarnings("unchecked")
|
|
List<Map<String, Object>> cast = (List<Map<String, Object>>) body;
|
|
dataList = cast;
|
|
} else {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("삭제할 데이터가 필요합니다."));
|
|
}
|
|
if (dataList.isEmpty()) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("삭제할 데이터가 필요합니다."));
|
|
}
|
|
tableManagementService.deleteTableData(tableName, dataList);
|
|
return ResponseEntity.ok(ApiResponse.success(null, "테이블 데이터를 성공적으로 삭제했습니다."));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 로그 관리
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** POST /api/table-management/tables/:tableName/log */
|
|
@PostMapping("/tables/{tableName}/log")
|
|
public ResponseEntity<ApiResponse<Void>> createLogTable(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("role") String role) {
|
|
if (!isSuperAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자(SUPER_ADMIN) 권한이 필요합니다."));
|
|
}
|
|
@SuppressWarnings("unchecked")
|
|
List<String> logColumns = (List<String>) body.get("log_columns");
|
|
boolean isActive = Boolean.TRUE.equals(body.get("is_active"));
|
|
tableManagementService.createLogTable(tableName, logColumns, isActive);
|
|
return ResponseEntity.ok(ApiResponse.success(null, "로그 테이블이 생성되었습니다."));
|
|
}
|
|
|
|
/** GET /api/table-management/tables/:tableName/log/config */
|
|
@GetMapping("/tables/{tableName}/log/config")
|
|
public ResponseEntity<ApiResponse<Object>> getLogConfig(@PathVariable String tableName) {
|
|
Map<String, Object> config = tableManagementService.getLogConfig(tableName);
|
|
Object data = config != null ? config : Map.of();
|
|
return ResponseEntity.ok(ApiResponse.success(data));
|
|
}
|
|
|
|
/** GET /api/table-management/tables/:tableName/log */
|
|
@GetMapping("/tables/{tableName}/log")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> getLogData(
|
|
@PathVariable String tableName,
|
|
@RequestParam(defaultValue = "1") int page,
|
|
@RequestParam(defaultValue = "50") int size) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getLogData(tableName, page, size)));
|
|
}
|
|
|
|
/** POST /api/table-management/tables/:tableName/log/toggle */
|
|
@PostMapping("/tables/{tableName}/log/toggle")
|
|
public ResponseEntity<ApiResponse<Void>> toggleLogTable(
|
|
@PathVariable String tableName,
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("role") String role) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
boolean isActive = Boolean.TRUE.equals(body.get("is_active"));
|
|
tableManagementService.toggleLogTable(tableName, isActive);
|
|
return ResponseEntity.ok(ApiResponse.success(null,
|
|
isActive ? "로그가 활성화되었습니다." : "로그가 비활성화되었습니다."));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 카테고리 / 채번 컬럼
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** GET /api/table-management/category-columns */
|
|
@GetMapping("/category-columns")
|
|
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryColumnsByCompany(
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getCategoryColumnsByCompany(companyCode)));
|
|
}
|
|
|
|
/** GET /api/table-management/numbering-columns */
|
|
@GetMapping("/numbering-columns")
|
|
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getNumberingColumnsByCompany(
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getNumberingColumnsByCompany(companyCode)));
|
|
}
|
|
|
|
/** GET /api/table-management/menu/:menuObjid/category-columns */
|
|
@GetMapping("/menu/{menuObjid}/category-columns")
|
|
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryColumnsByMenu(
|
|
@PathVariable String menuObjid,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getCategoryColumnsByMenu(companyCode, menuObjid)));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 현재 테이블을 참조하는 테이블
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** GET /api/table-management/columns/:tableName/referenced-by */
|
|
@GetMapping("/columns/{tableName}/referenced-by")
|
|
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getReferencedByTables(
|
|
@PathVariable String tableName,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.getReferencedByTables(tableName, companyCode)));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 다중 테이블 저장 / 엑셀 검증
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** POST /api/table-management/multi-table-save */
|
|
@PostMapping("/multi-table-save")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> multiTableSave(
|
|
@RequestBody Map<String, Object> payload,
|
|
@RequestAttribute("role") String role,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
if (!isAdmin(role)) {
|
|
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
|
}
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.multiTableSave(payload, companyCode),
|
|
"다중 테이블 저장이 완료되었습니다."));
|
|
}
|
|
|
|
/** POST /api/table-management/validate-excel */
|
|
@PostMapping("/validate-excel")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> validateExcelData(
|
|
@RequestBody Map<String, Object> body,
|
|
@RequestAttribute("company_code") String companyCode) {
|
|
String tableName = (String) body.get("table_name");
|
|
@SuppressWarnings("unchecked")
|
|
List<Map<String, Object>> rows = (List<Map<String, Object>>) body.get("rows");
|
|
if (tableName == null || rows == null) {
|
|
return ResponseEntity.status(400).body(ApiResponse.error("tableName과 rows가 필요합니다."));
|
|
}
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.validateExcelData(tableName, rows, companyCode)));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// DB 헬스체크
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
/** GET /api/table-management/health */
|
|
@GetMapping("/health")
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> checkDatabaseConnection() {
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
tableManagementService.checkDatabaseConnection(), "데이터베이스 연결 상태를 확인했습니다."));
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 권한 헬퍼
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
private boolean isAdmin(String role) {
|
|
return isSuperAdmin(role) || "COMPANY_ADMIN".equals(role);
|
|
}
|
|
|
|
private boolean isSuperAdmin(String roleOrCode) {
|
|
return "*".equals(roleOrCode) || "SUPER_ADMIN".equals(roleOrCode);
|
|
}
|
|
}
|