최초커밋

This commit is contained in:
kjs
2025-08-21 09:41:46 +09:00
commit a0e5b57a24
2454 changed files with 1476904 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,300 @@
package com.pms.controller;
import com.pms.service.AuthService;
import com.pms.service.SessionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import com.pms.common.bean.PersonBean;
import com.pms.common.utils.Constants;
@Slf4j
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthController {
private final AuthService authService;
private final SessionService sessionService;
/**
* 로그인 처리 (기존 JSP 방식과 동일)
*/
@PostMapping("/login")
public ResponseEntity<Map<String, Object>> login(
HttpServletRequest request,
HttpServletResponse response,
@RequestBody Map<String, Object> paramMap) {
setCorsHeaders(response, request);
try {
// 기존 LoginService.loginPwdCheck와 동일한 방식
Map<String, Object> loginResultMap = authService.loginPwdCheck(request, paramMap);
boolean loginResult = Boolean.parseBoolean(String.valueOf(loginResultMap.get("loginResult")));
if (loginResult) {
// 세션에 사용자 정보 저장 (기존 방식과 동일)
HttpSession session = request.getSession();
Map<String, Object> userInfoMap = authService.getUserInfo(paramMap);
// PersonBean 생성 및 세션 저장
PersonBean personBean = new PersonBean();
if (userInfoMap != null) {
personBean.setUserType((String) userInfoMap.get("USER_TYPE"));
personBean.setUserId((String) userInfoMap.get("USER_ID"));
personBean.setUserName((String) userInfoMap.get("USER_NAME"));
personBean.setEmail((String) userInfoMap.get("EMAIL"));
personBean.setDeptCode((String) userInfoMap.get("DEPT_CODE"));
personBean.setDeptName((String) userInfoMap.get("DEPT_NAME"));
personBean.setPositionCode((String) userInfoMap.get("POSITION_CODE"));
personBean.setPositionName((String) userInfoMap.get("POSITION_NAME"));
personBean.setLocale((String) userInfoMap.get("LOCALE"));
// photo 데이터 설정 (PostgreSQL bytea 타입)
Object photoObj = userInfoMap.get("PHOTO");
if (photoObj != null) {
if (photoObj instanceof byte[]) {
personBean.setPhoto((byte[]) photoObj);
}
}
}
// Constants.PERSON_BEAN 사용
session.setAttribute(Constants.PERSON_BEAN, personBean);
// 응답용 사용자 정보 생성
Map<String, Object> userInfo = new HashMap<>();
userInfo.put("USERTYPE", personBean.getUserType());
userInfo.put("USERID", personBean.getUserId());
userInfo.put("USERNAME", personBean.getUserName());
userInfo.put("EMAIL", personBean.getEmail());
userInfo.put("DEPTCODE", personBean.getDeptCode());
userInfo.put("DEPTNAME", personBean.getDeptName());
userInfo.put("POSITIONCODE", personBean.getPositionCode());
userInfo.put("POSITIONNAME", personBean.getPositionName());
userInfo.put("LOCALE", personBean.getLocale());
// photo 데이터 처리 (이미 완전한 data URL 형태로 저장되어 있음)
if (personBean.getPhoto() != null && personBean.getPhoto().length > 0) {
// 데이터베이스에서 가져온 데이터를 그대로 사용 (완전한 data URL)
String photoData = new String(personBean.getPhoto());
userInfo.put("PHOTO", photoData);
} else {
userInfo.put("PHOTO", null);
}
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", true);
response_map.put("message", "로그인 성공");
response_map.put("data", userInfo);
return ResponseEntity.ok(response_map);
} else {
String errorReason = String.valueOf(loginResultMap.get("errorReason"));
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", false);
response_map.put("message", "로그인 실패");
response_map.put("errorCode", "LOGIN_FAILED");
response_map.put("data", errorReason);
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response_map);
}
} catch (Exception e) {
log.error("로그인 처리 중 오류 발생", e);
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", false);
response_map.put("message", "서버 오류가 발생했습니다.");
response_map.put("errorCode", "SERVER_ERROR");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response_map);
}
}
/**
* 로그아웃 처리
*/
@PostMapping("/logout")
public ResponseEntity<Map<String, Object>> logout(HttpServletRequest request, HttpServletResponse response) {
setCorsHeaders(response, request);
try {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", true);
response_map.put("message", "로그아웃 되었습니다.");
return ResponseEntity.ok(response_map);
} catch (Exception e) {
log.error("로그아웃 처리 중 오류 발생", e);
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", false);
response_map.put("message", "로그아웃 처리 중 오류가 발생했습니다.");
response_map.put("errorCode", "LOGOUT_ERROR");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response_map);
}
}
/**
* 현재 사용자 정보 조회
*/
@GetMapping("/me")
public ResponseEntity<Map<String, Object>> getCurrentUser(HttpServletRequest request, HttpServletResponse response) {
setCorsHeaders(response, request);
try {
Map<String, Object> userInfo = sessionService.getCurrentUserInfo(request);
if (userInfo == null) {
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", false);
response_map.put("message", "인증되지 않은 사용자입니다.");
response_map.put("errorCode", "NOT_AUTHENTICATED");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response_map);
}
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", true);
response_map.put("message", "사용자 정보 조회 성공");
response_map.put("data", userInfo);
return ResponseEntity.ok(response_map);
} catch (Exception e) {
log.error("사용자 정보 조회 중 오류 발생", e);
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", false);
response_map.put("message", "사용자 정보 조회 중 오류가 발생했습니다.");
response_map.put("errorCode", "USER_INFO_ERROR");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response_map);
}
}
/**
* 로그인 상태 확인
*/
@GetMapping("/status")
public ResponseEntity<Map<String, Object>> checkAuthStatus(HttpServletRequest request, HttpServletResponse response) {
setCorsHeaders(response, request);
try {
boolean isLoggedIn = sessionService.isLoggedIn(request);
boolean isAdmin = isLoggedIn && sessionService.isAdmin(request);
Map<String, Object> statusInfo = new HashMap<>();
statusInfo.put("isLoggedIn", isLoggedIn);
statusInfo.put("isAdmin", isAdmin);
if (isLoggedIn) {
statusInfo.put("userId", sessionService.getCurrentUserId(request));
statusInfo.put("deptCode", sessionService.getCurrentUserDeptCode(request));
}
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", true);
response_map.put("message", "인증 상태 확인 완료");
response_map.put("data", statusInfo);
return ResponseEntity.ok(response_map);
} catch (Exception e) {
log.error("인증 상태 확인 중 오류 발생", e);
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", false);
response_map.put("message", "인증 상태 확인 중 오류가 발생했습니다.");
response_map.put("errorCode", "AUTH_STATUS_ERROR");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response_map);
}
}
/**
* 메뉴 접근 권한 확인
*/
@GetMapping("/menu-auth")
public ResponseEntity<Map<String, Object>> checkMenuAuth(
@RequestParam String menuUrl,
HttpServletRequest request,
HttpServletResponse response) {
setCorsHeaders(response, request);
try {
boolean hasAuth = sessionService.hasMenuAuth(request, menuUrl);
Map<String, Object> authInfo = new HashMap<>();
authInfo.put("menuUrl", menuUrl);
authInfo.put("hasAuth", hasAuth);
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", true);
response_map.put("message", "메뉴 권한 확인 완료");
response_map.put("data", authInfo);
return ResponseEntity.ok(response_map);
} catch (Exception e) {
log.error("메뉴 권한 확인 중 오류 발생 - menuUrl: {}", menuUrl, e);
Map<String, Object> response_map = new HashMap<>();
response_map.put("success", false);
response_map.put("message", "메뉴 권한 확인 중 오류가 발생했습니다.");
response_map.put("errorCode", "MENU_AUTH_ERROR");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response_map);
}
}
/**
* 연결 테스트
*/
@GetMapping("/test")
public ResponseEntity<String> test() {
return ResponseEntity.ok("Spring Boot Backend Connected!");
}
/**
* CORS 헤더 설정 (동적 origin 지원)
*/
private void setCorsHeaders(HttpServletResponse response, HttpServletRequest request) {
String origin = request.getHeader("Origin");
String[] allowedOrigins = {
"http://localhost:3000",
"http://localhost:9771",
"http://192.168.0.70:5555"
};
for (String allowedOrigin : allowedOrigins) {
if (allowedOrigin.equals(origin)) {
response.setHeader("Access-Control-Allow-Origin", origin);
break;
}
}
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Max-Age", "3600");
}
}

View File

@@ -0,0 +1,279 @@
package com.pms.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.pms.service.MultiLangService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/multilang")
@RequiredArgsConstructor
public class MultiLangController {
private final MultiLangService multiLangService;
// 성공 응답 생성
private Map<String, Object> createSuccessResponse(Object data) {
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("data", data);
return response;
}
// 오류 응답 생성
private Map<String, Object> createErrorResponse(String message, String detail) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
response.put("message", message);
response.put("detail", detail);
return response;
}
// 회사 목록 조회
@GetMapping("/companies")
public ResponseEntity<Map<String, Object>> getCompanies() {
try {
List<Map<String, Object>> companies = multiLangService.getCompanies();
return ResponseEntity.ok(createSuccessResponse(companies));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("회사 목록 조회 실패", e.getMessage()));
}
}
// 언어 마스터 조회
@GetMapping("/languages")
public ResponseEntity<Map<String, Object>> getLanguages() {
try {
List<Map<String, Object>> languages = multiLangService.getLanguages();
return ResponseEntity.ok(createSuccessResponse(languages));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("언어 목록 조회 실패", e.getMessage()));
}
}
// 언어 추가
@PostMapping("/languages")
public ResponseEntity<Map<String, Object>> createLanguage(@RequestBody Map<String, Object> languageData) {
try {
String langCode = multiLangService.createLanguage(languageData);
return ResponseEntity.ok(createSuccessResponse(langCode));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("언어 추가 실패", e.getMessage()));
}
}
// 언어 수정
@PutMapping("/languages/{langId}")
public ResponseEntity<Map<String, Object>> updateLanguage(
@PathVariable Integer langId,
@RequestBody Map<String, Object> languageData) {
try {
languageData.put("langId", langId);
multiLangService.updateLanguage(languageData);
return ResponseEntity.ok(createSuccessResponse("언어 수정 완료"));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("언어 수정 실패", e.getMessage()));
}
}
// 언어 삭제
@DeleteMapping("/languages/{langCode}")
public ResponseEntity<Map<String, Object>> deleteLanguage(@PathVariable String langCode) {
try {
multiLangService.deleteLanguage(langCode);
return ResponseEntity.ok(createSuccessResponse("언어 삭제 완료"));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("언어 삭제 실패", e.getMessage()));
}
}
// 언어 활성/비활성 토글
@PutMapping("/languages/{langCode}/toggle")
public ResponseEntity<Map<String, Object>> toggleLanguage(@PathVariable String langCode) {
try {
String result = multiLangService.toggleLanguage(langCode);
return ResponseEntity.ok(createSuccessResponse(result));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("언어 상태 변경 실패", e.getMessage()));
}
}
// 회사별 다국어 키 목록 조회
@GetMapping("/keys")
public ResponseEntity<Map<String, Object>> getLangKeys(
@RequestParam(required = false) String companyCode,
@RequestParam(required = false) String menuCode,
@RequestParam(required = false) String keyType,
@RequestParam(required = false) String searchText) {
try {
Map<String, Object> params = new HashMap<>();
params.put("companyCode", companyCode);
params.put("menuCode", menuCode);
params.put("keyType", keyType);
params.put("searchText", searchText);
log.info("다국어 키 조회 파라미터: companyCode={}, menuCode={}, keyType={}, searchText={}",
companyCode, menuCode, keyType, searchText);
List<Map<String, Object>> keys = multiLangService.getLangKeys(params);
return ResponseEntity.ok(createSuccessResponse(keys));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("다국어 키 목록 조회 실패", e.getMessage()));
}
}
// 특정 키의 다국어 텍스트 조회
@GetMapping("/keys/{keyId}/texts")
public ResponseEntity<Map<String, Object>> getLangTexts(@PathVariable Integer keyId) {
try {
List<Map<String, Object>> texts = multiLangService.getLangTexts(keyId);
return ResponseEntity.ok(createSuccessResponse(texts));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("다국어 텍스트 조회 실패", e.getMessage()));
}
}
// 사용자별 다국어 텍스트 조회 (프론트엔드용)
@GetMapping("/user-text/{companyCode}/{menuCode}/{langKey}")
public ResponseEntity<Map<String, Object>> getUserText(
@PathVariable String companyCode,
@PathVariable String menuCode,
@PathVariable String langKey,
@RequestParam String userLang) {
System.out.println("🌐 다국어 API 호출: " + companyCode + "/" + menuCode + "/" + langKey + " (lang: " + userLang + ")");
try {
String text = multiLangService.getUserText(companyCode, menuCode, langKey, userLang);
System.out.println("🌐 다국어 API 응답: " + text);
return ResponseEntity.ok(createSuccessResponse(text));
} catch (Exception e) {
System.err.println("❌ 다국어 API 오류: " + e.getMessage());
e.printStackTrace();
return ResponseEntity.badRequest().body(createErrorResponse("사용자 텍스트 조회 실패", e.getMessage()));
}
}
// 다국어 키 생성
@PostMapping("/keys")
public ResponseEntity<Map<String, Object>> createLangKey(@RequestBody Map<String, Object> keyData) {
try {
Integer keyId = multiLangService.createLangKey(keyData);
return ResponseEntity.ok(createSuccessResponse(keyId));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("중복된 키 입니다.", e.getMessage()));
}
}
// 다국어 키 수정
@PutMapping("/keys/{keyId}")
public ResponseEntity<Map<String, Object>> updateLangKey(
@PathVariable Integer keyId,
@RequestBody Map<String, Object> keyData) {
try {
keyData.put("keyId", keyId);
multiLangService.updateLangKey(keyData);
return ResponseEntity.ok(createSuccessResponse("수정 완료"));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("다국어 키 수정 실패", e.getMessage()));
}
}
// 다국어 키 삭제
@DeleteMapping("/keys/{keyId}")
public ResponseEntity<Map<String, Object>> deleteLangKey(@PathVariable Integer keyId) {
try {
multiLangService.deleteLangKey(keyId);
return ResponseEntity.ok(createSuccessResponse("삭제 완료"));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("다국어 키 삭제 실패", e.getMessage()));
}
}
// 다국어 키 활성/비활성 토글
@PutMapping("/keys/{keyId}/toggle")
public ResponseEntity<Map<String, Object>> toggleLangKey(@PathVariable Integer keyId) {
try {
String result = multiLangService.toggleLangKey(keyId);
return ResponseEntity.ok(createSuccessResponse(result));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("다국어 키 상태 변경 실패", e.getMessage()));
}
}
// 다국어 텍스트 저장/수정
@PostMapping("/keys/{keyId}/texts")
public ResponseEntity<Map<String, Object>> saveLangTexts(
@PathVariable Integer keyId,
@RequestBody List<Map<String, Object>> textData) {
try {
multiLangService.saveLangTexts(keyId, textData);
return ResponseEntity.ok(createSuccessResponse("저장 완료"));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("다국어 텍스트 저장 실패", e.getMessage()));
}
}
// 특정 키의 다국어 텍스트 조회 (회사, 키, 언어별)
@GetMapping("/text/{companyCode}/{langKey}/{langCode}")
public ResponseEntity<Map<String, Object>> getLangText(
@PathVariable String companyCode,
@PathVariable String langKey,
@PathVariable String langCode) {
try {
String text = multiLangService.getLangText(companyCode, langKey, langCode);
return ResponseEntity.ok(createSuccessResponse(text));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("다국어 텍스트 조회 실패", e.getMessage()));
}
}
// 사용자 언어별 다국어 텍스트 조회
@GetMapping("/user-text/{companyCode}/{langKey}")
public ResponseEntity<Map<String, Object>> getUserLangText(
@PathVariable String companyCode,
@PathVariable String langKey,
@RequestParam(defaultValue = "ko") String userLang) {
try {
String text = multiLangService.getLangText(companyCode, langKey, userLang);
return ResponseEntity.ok(createSuccessResponse(text));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("사용자 다국어 텍스트 조회 실패", e.getMessage()));
}
}
// 테스트 엔드포인트
@GetMapping("/test")
public ResponseEntity<Map<String, Object>> test() {
return ResponseEntity.ok(createSuccessResponse("MultiLangController is working!"));
}
// 데이터베이스 연결 테스트
@GetMapping("/test-db")
public ResponseEntity<Map<String, Object>> testDb() {
try {
String result = multiLangService.testConnection();
return ResponseEntity.ok(createSuccessResponse("DB 연결 성공: " + result));
} catch (Exception e) {
return ResponseEntity.badRequest().body(createErrorResponse("DB 연결 실패", e.getMessage()));
}
}
}

View File

@@ -0,0 +1,114 @@
package com.pms.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.pms.service.TableManagementService;
/**
* 테이블 관리 API 컨트롤러
*/
@RestController
@RequestMapping("/table-management")
public class TableManagementController {
@Autowired
private TableManagementService tableManagementService;
/**
* 테이블 목록 조회
*/
@GetMapping("/tables")
public ResponseEntity<Map<String, Object>> getTableList(HttpServletRequest request) {
try {
List<Map<String, Object>> tableList = tableManagementService.getTableList();
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("data", tableList);
response.put("message", "테이블 목록을 성공적으로 조회했습니다.");
return ResponseEntity.ok(response);
} catch (Exception e) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
response.put("message", "테이블 목록 조회 중 오류가 발생했습니다: " + e.getMessage());
return ResponseEntity.badRequest().body(response);
}
}
/**
* 테이블 컬럼 정보 조회
*/
@GetMapping("/tables/{tableName}/columns")
public ResponseEntity<Map<String, Object>> getColumnList(
HttpServletRequest request,
@PathVariable String tableName) {
try {
List<Map<String, Object>> columns = tableManagementService.getColumnList(tableName);
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("data", columns);
response.put("message", "컬럼 목록을 성공적으로 조회했습니다.");
return ResponseEntity.ok(response);
} catch (Exception e) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
response.put("message", "컬럼 목록 조회 중 오류가 발생했습니다: " + e.getMessage());
return ResponseEntity.badRequest().body(response);
}
}
@PostMapping("/tables/{tableName}/columns/{columnName}/settings")
public ResponseEntity<Map<String, Object>> updateColumnSettings(
HttpServletRequest request,
@PathVariable String tableName,
@PathVariable String columnName,
@RequestBody Map<String, Object> settings) {
try {
tableManagementService.updateColumnSettings(tableName, columnName, settings);
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("message", "컬럼 설정을 성공적으로 저장했습니다.");
return ResponseEntity.ok(response);
} catch (Exception e) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
response.put("message", "컬럼 설정 저장 중 오류가 발생했습니다: " + e.getMessage());
return ResponseEntity.badRequest().body(response);
}
}
@PostMapping("/tables/{tableName}/columns/settings")
public ResponseEntity<Map<String, Object>> updateAllColumnSettings(
HttpServletRequest request,
@PathVariable String tableName,
@RequestBody List<Map<String, Object>> columnSettings) {
try {
tableManagementService.updateAllColumnSettings(tableName, columnSettings);
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("message", "모든 컬럼 설정을 성공적으로 저장했습니다.");
return ResponseEntity.ok(response);
} catch (Exception e) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
response.put("message", "컬럼 설정 저장 중 오류가 발생했습니다: " + e.getMessage());
return ResponseEntity.badRequest().body(response);
}
}
}