Files
operationSystem-back/src/main/java/com/caliverse/admin/domain/service/MenuService.java
2025-08-06 14:39:05 +09:00

375 lines
15 KiB
Java

package com.caliverse.admin.domain.service;
import com.caliverse.admin.domain.RabbitMq.MessageHandlerService;
import com.caliverse.admin.domain.dao.admin.MenuMapper;
import com.caliverse.admin.domain.entity.*;
import com.caliverse.admin.domain.entity.log.LogAction;
import com.caliverse.admin.domain.entity.log.LogStatus;
import com.caliverse.admin.domain.request.MenuRequest;
import com.caliverse.admin.domain.response.MenuResponse;
import com.caliverse.admin.dynamodb.service.DynamodbMenuService;
import com.caliverse.admin.global.common.annotation.BusinessProcess;
import com.caliverse.admin.global.common.annotation.RequestLog;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.code.ErrorCode;
import com.caliverse.admin.global.common.code.SuccessCode;
import com.caliverse.admin.global.common.constants.CommonConstants;
import com.caliverse.admin.global.common.constants.MysqlConstants;
import com.caliverse.admin.global.common.exception.RestApiException;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.common.utils.FileUtils;
import com.caliverse.admin.global.component.manager.BusinessProcessIdManager;
import com.caliverse.admin.mongodb.service.MysqlHistoryLogService;
import com.caliverse.admin.redis.service.RedisUserInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.services.s3.model.S3Exception;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
@RequiredArgsConstructor
public class MenuService {
@Value("${excel.file-path}")
private String filePath;
@Value("${caliverse.file}")
private String samplePath;
private final FileUtils fileUtils;
private final MenuMapper menuMapper;
private final ResourceLoader resourceLoader;
private final MysqlHistoryLogService mysqlHistoryLogService;
private final S3Service s3Service;
private final DynamodbMenuService dynamodbMenuService;
private final MessageHandlerService messageHandlerService;
private final RedisUserInfoService redisUserInfoService;
private final BusinessProcessIdManager processIdManager;
@RequestLog
public MenuResponse getList(Map requestParam){
//페이징 처리
requestParam = CommonUtils.pageSetting(requestParam);
List<MenuBanner> list = menuMapper.getBannerList(requestParam);
return MenuResponse.builder()
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.resultData(MenuResponse.ResultData.builder()
.bannerList(list)
.total(menuMapper.getTotal())
.totalAll(list.size())
.pageNo(requestParam.get("page_no")!=null?
Integer.valueOf(requestParam.get("page_no").toString()):1)
.build()
)
.build();
}
@RequestLog
public MenuResponse getdetail(Long id){
MenuBanner banner = menuMapper.getBannerDetail(id);
banner.setImageList(menuMapper.getMessage(id));
return MenuResponse.builder()
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.resultData(MenuResponse.ResultData.builder()
.banner(banner)
.build())
.build();
}
public MenuResponse imageUpload(MultipartFile file){
if (file.isEmpty()) {
log.error("File is empty");
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_EXIT_FILE.toString());
}
// 파일을 서버에 저장
String fileName = fileUtils.saveFile(file);
return MenuResponse.builder()
.resultData(MenuResponse.ResultData.builder()
.message(SuccessCode.EXCEL_UPLOAD.getMessage())
.fileName(fileName)
.build())
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.build();
}
public MenuResponse imageDelete(String fileName){
if (fileName.isEmpty()) {
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_EXIT_FILE.getMessage() );
}
// 서버 파일 삭제
boolean is_delete = fileUtils.deleteFile(fileName);
if(is_delete){
return MenuResponse.builder()
.resultData(MenuResponse.ResultData.builder()
.message(SuccessCode.FILE_DELETE.getMessage())
.build())
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.build();
}else{
return MenuResponse.builder()
.resultData(MenuResponse.ResultData.builder()
.message(ErrorCode.ERROR_FILE_DELETE.getMessage())
.build())
.status(CommonCode.ERROR.getHttpStatus())
.result(CommonCode.ERROR.getResult())
.build();
}
}
public Resource fileDown(String fileName) {
Path fileFullPath = Path.of(filePath+fileName);
try {
if(fileName.contains("sample")){
return resourceLoader.getResource(samplePath + fileName);
}
Resource resource = new UrlResource(fileFullPath.toUri());
if (resource.exists() && resource.isReadable()) {
return resource;
} else {
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_EXIT_EXCEL.getMessage());
}
}catch (MalformedURLException e){
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_EXIT_EXCEL.getMessage());
}
}
@BusinessProcess(action = LogAction.BANNER)
@Transactional(transactionManager = "transactionManager")
@RequestLog
public MenuResponse postBanner(MenuRequest menuRequest){
menuRequest.setCreateBy(CommonUtils.getAdmin().getId());
int maxOrderId = menuMapper.getMaxOrderId();
menuRequest.setOrderId(maxOrderId+1);
menuMapper.insertBanner(menuRequest);
long banner_id = menuRequest.getId();
HashMap<String,String> map = new HashMap<>();
map.put("id",String.valueOf(banner_id));
//메시지 저장(title=이미지명, content=이미지 링크)
if(menuRequest.getImageList()!= null && !menuRequest.getImageList().isEmpty()){
menuRequest.getImageList().forEach(image -> {
String temp_file = image.getContent();
String contentType = fileUtils.getContentType(temp_file);
File file = fileUtils.loadFileObject(temp_file);
String fileUri = "";
try{
String directory = String.format("%s/%s-%d", CommonConstants.S3_MENU_BANNER_DIRECTORY, CommonConstants.S3_MENU_BANNER_DIRECTORY, banner_id);
fileUri = s3Service.uploadFile(file, directory, contentType);
}catch (S3Exception e) {
log.error("S3 오류: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_FILE_S3_UPLOAD.getMessage());
} catch (IOException e) {
log.error("파일 읽기 오류: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_FILE_S3_UPLOAD.getMessage());
} catch (Exception e) {
log.error("파일 업로드 중 예상치 못한 오류: {}", e.getMessage(), e);
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_FILE_S3_UPLOAD.getMessage());
}
if(fileUri.isEmpty()){
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_FILE_S3_UPLOAD.getMessage());
}
map.put("title", fileUri);
map.put("language", image.getLanguage());
if(menuRequest.isLink() && (menuRequest.getLinkList() != null && !menuRequest.getLinkList().isEmpty())){
String link = menuRequest.getLinkList().stream().filter(data -> data.getLanguage().equals(image.getLanguage())).findFirst().get().getContent();
map.put("content", link);
}else{
map.put("content", "");
}
menuMapper.insertMessage(map);
fileUtils.deleteFile(temp_file);
});
}
log.info("postBanner Insert MenuBanner id: {}", menuRequest.getId());
MenuBanner banner = menuMapper.getBannerDetail(menuRequest.getId());
banner.setImageList(menuMapper.getMessage(menuRequest.getId()));
String prodId = processIdManager.getCurrentProcessId();
LogAction action = processIdManager.getCurrentAction();
//message 정보까지 저장해야해서 수동 로그
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
try {
mysqlHistoryLogService.insertHistoryLog(
prodId,
action,
LogStatus.SUCCESS,
MysqlConstants.TABLE_NAME_MENU_BANNER,
"",
banner
);
} catch (Exception e) {
log.warn("Failed to log banner creation: {}", e.getMessage());
}
}
});
if(redisUserInfoService.getAllServerList().isEmpty()){
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_FOUND_SERVER.getMessage());
}
dynamodbMenuService.insertBanner(banner);
//운영DB 데이터 추가됐다고 게임서버 알림
notifyGameServers("postBanner", null);
return MenuResponse.builder()
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.resultData(MenuResponse.ResultData.builder()
.message(SuccessCode.SAVE.getMessage())
.build())
.build();
}
@BusinessProcess(action = LogAction.BANNER)
@Transactional(transactionManager = "transactionManager")
@RequestLog
public MenuResponse updateBanner(Long id, MenuRequest menuRequest) {
menuRequest.setId(id);
menuRequest.setUpdateBy(CommonUtils.getAdmin().getId());
menuRequest.setUpdateDt(LocalDateTime.now());
Long banner_id = menuRequest.getId();
MenuBanner before_info = menuMapper.getBannerDetail(banner_id);
List<Message> before_msg = menuMapper.getMessage(banner_id);
before_info.setImageList(before_msg);
menuMapper.updateBanner(menuRequest);
log.info("updateBanner Update Banner Complete: {}", menuRequest.getId());
MenuBanner after_info = menuMapper.getBannerDetail(banner_id);
after_info.setImageList(menuMapper.getMessage(banner_id));
if(redisUserInfoService.getAllServerList().isEmpty()){
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_FOUND_SERVER.getMessage());
}
dynamodbMenuService.updateBanner(after_info);
//운영DB 데이터 추가됐다고 게임서버 알림
notifyGameServers("updateBanner", null);
return MenuResponse.builder()
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.resultData(MenuResponse.ResultData.builder()
.message(SuccessCode.UPDATE.getMessage())
.build())
.build();
}
@BusinessProcess(action = LogAction.BANNER)
@Transactional(transactionManager = "transactionManager")
@RequestLog
public MenuResponse deleteBanner(Long id){
Map<String,Object> map = new HashMap<>();
map.put("id",id);
MenuBanner banner = menuMapper.getBannerDetail(id);
banner.setImageList(menuMapper.getMessage(id));
if(banner.getStartDt().isBefore(LocalDateTime.now())){
return MenuResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(CommonCode.ERROR.getResult())
.resultData(MenuResponse.ResultData.builder()
.message(ErrorCode.START_DATE_OVER.getMessage())
.build())
.build();
}
menuMapper.deleteBanner(map);
menuMapper.deleteMessage(map);
log.info("deleteBanner Delete Banner Complete id: {}", id);
if(redisUserInfoService.getAllServerList().isEmpty()){
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_FOUND_SERVER.getMessage());
}
dynamodbMenuService.deleteBanner(banner.getId().intValue());
//게임서버 알림
notifyGameServers("deleteBanner", null);
return MenuResponse.builder()
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.resultData(MenuResponse.ResultData.builder()
.message(SuccessCode.DELETE.getMessage())
.build())
.build();
}
public List<Message> getMessageList(Long id){
return menuMapper.getMessage(id);
}
private void notifyGameServers(String methodName, Runnable rollbackFunction) {
// 운영DB 데이터 추가됐다고 게임서버 알림
List<String> serverList = redisUserInfoService.getAllServerList();
if(serverList.isEmpty()){
log.error("{} serverList is empty", methodName);
if (rollbackFunction != null) {
rollbackFunction.run();
}
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_FOUND_SERVER.getMessage());
}
try{
serverList.forEach(messageHandlerService::sendBannerMessage);
} catch (Exception e) {
log.error("{} messageHandlerService error: {}", methodName, e.getMessage(), e);
if (rollbackFunction != null) {
rollbackFunction.run();
}
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.MESSAGE_SEND_FAIL.getMessage());
}
}
}