Merge branch 'jenkins_with_weblogic' into master
This commit is contained in:
+10
-1
@@ -14,6 +14,15 @@ idea {
|
||||
|
||||
def nexusUrl = "https://nexus.eactive.synology.me:8090"
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven {
|
||||
url "${nexusUrl}/repository/maven-public/"
|
||||
allowInsecureProtocol = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def springVersion = "5.3.27"
|
||||
//def quartzVersion = "2.2.1"
|
||||
def queryDslVersion = "5.0.0"
|
||||
@@ -72,7 +81,7 @@ tasks.withType(JavaCompile) {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':kjb-safedb')
|
||||
// api project(':kjb-safedb')
|
||||
|
||||
api "com.querydsl:querydsl-jpa:${queryDslVersion}"
|
||||
api "com.querydsl:querydsl-apt:${queryDslVersion}"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
-- 1. Add fields to ptl_app_request table
|
||||
ALTER TABLE ptl_app_request ADD app_description VARCHAR2(500);
|
||||
COMMENT ON COLUMN ptl_app_request.app_description IS '앱 설명';
|
||||
|
||||
ALTER TABLE ptl_app_request ADD callback_url VARCHAR2(255);
|
||||
COMMENT ON COLUMN ptl_app_request.callback_url IS '콜백 URL';
|
||||
|
||||
ALTER TABLE ptl_app_request ADD ip_whitelist VARCHAR2(1000);
|
||||
COMMENT ON COLUMN ptl_app_request.ip_whitelist IS 'IP 화이트리스트 (comma-separated)';
|
||||
|
||||
ALTER TABLE ptl_app_request ADD app_icon_file_id VARCHAR2(38);
|
||||
COMMENT ON COLUMN ptl_app_request.app_icon_file_id IS '앱 아이콘 파일 ID (ptl_file 참조)';
|
||||
|
||||
-- 2. Add fields to ptl_credential table
|
||||
ALTER TABLE ptl_credential ADD app_description VARCHAR2(500);
|
||||
COMMENT ON COLUMN ptl_credential.app_description IS '앱 설명';
|
||||
|
||||
ALTER TABLE ptl_credential ADD app_icon_file_id VARCHAR2(38);
|
||||
COMMENT ON COLUMN ptl_credential.app_icon_file_id IS '앱 아이콘 파일 ID (ptl_file 참조)';
|
||||
@@ -61,4 +61,8 @@ public class Agreements extends Auditable {
|
||||
@Column(name = "SCHEDULED_ON")
|
||||
@Convert(converter = LocalDateTimeToStringConverter14.class)
|
||||
private LocalDateTime scheduledOn;
|
||||
|
||||
@Column(name = "ATTACHED_FILE_ID", length = 36)
|
||||
@Comment("첨부파일 ID (PTL_FILE.FILE_ID)")
|
||||
private String attachedFileId;
|
||||
}
|
||||
@@ -111,6 +111,14 @@ public class Credential extends AbstractEntity<String> implements Serializable {
|
||||
@Comment("기관이름")
|
||||
private String orgname;
|
||||
|
||||
@Column(name = "app_description", length = 500)
|
||||
@Comment("앱 설명")
|
||||
private String appDescription;
|
||||
|
||||
@Column(name = "app_icon_file_id", length = 38)
|
||||
@Comment("앱 아이콘 파일 ID")
|
||||
private String appIconFileId;
|
||||
|
||||
@Comment("일별 토큰 제한 수 (0:무제한)")
|
||||
private int dailytokenlimit;
|
||||
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
package com.eactive.apim.portal.app.entity;
|
||||
|
||||
import com.eactive.apim.portal.apispec.entity.ApiSpecInfo;
|
||||
import com.eactive.eai.data.converter.LocalDateTimeToStringConverter14;
|
||||
import com.eactive.eai.data.entity.AbstractEntity;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@Table(name = "ptl_prod_client")
|
||||
@org.hibernate.annotations.Table(appliesTo = "ptl_prod_client", comment = "사용자 정보")
|
||||
public class ProdClient extends AbstractEntity<String> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@Column(unique = true, nullable = false, length = 256)
|
||||
@Comment("client id")
|
||||
private String clientid;
|
||||
|
||||
@Column(length = 11)
|
||||
@Comment("Access Token 유효 기간(초)")
|
||||
private String accesstokenvalidityseconds;
|
||||
|
||||
@Column(length = 256)
|
||||
@Comment("허용된 IP")
|
||||
private String allowedips;
|
||||
|
||||
@Column(length = 256)
|
||||
@Comment("권한")
|
||||
private String authorities;
|
||||
|
||||
@Column(length = 256)
|
||||
@Comment("자동 승인 스코프")
|
||||
private String autoapprove;
|
||||
|
||||
@Column(length = 40)
|
||||
@Comment("client명")
|
||||
private String clientname;
|
||||
|
||||
@Column(length = 512)
|
||||
@Comment("Client 비밀번호")
|
||||
private String clientsecret;
|
||||
|
||||
@Column(length = 256)
|
||||
@Comment("권한타입")
|
||||
private String granttypes;
|
||||
|
||||
@Column(length = 8)
|
||||
@Comment("수정인")
|
||||
@LastModifiedBy
|
||||
private String modifiedby;
|
||||
|
||||
@Column(length = 14)
|
||||
@Comment("수정일")
|
||||
@Convert(converter = LocalDateTimeToStringConverter14.class)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime modifiedon;
|
||||
|
||||
@Column(length = 256)
|
||||
@Comment("Redirect URI")
|
||||
private String redirecturi;
|
||||
|
||||
@Column(length = 11)
|
||||
@Comment("Refresh Token 유효 기간(초)")
|
||||
private String refreshtokenvalidityseconds;
|
||||
|
||||
@Column(length = 4000)
|
||||
@Comment("리소스 id")
|
||||
private String resourceids;
|
||||
|
||||
@Column(length = 1024)
|
||||
@Comment("scope")
|
||||
private String scope;
|
||||
|
||||
@Column(length = 4000)
|
||||
@Comment("암호key")
|
||||
private String securitykey;
|
||||
|
||||
@Column(length = 38)
|
||||
@Comment("기관ID")
|
||||
private String orgid;
|
||||
|
||||
@Comment("APP 상태")
|
||||
private String appstatus; //0: 차단, 1: 정상
|
||||
|
||||
@Column(length = 255)
|
||||
@Comment("기관이름")
|
||||
private String orgname;
|
||||
|
||||
@Comment("일별 토큰 제한 수 (0:무제한)")
|
||||
private int dailytokenlimit;
|
||||
|
||||
@Override
|
||||
public @NonNull String getId() {
|
||||
return clientid;
|
||||
}
|
||||
|
||||
@ManyToMany
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
@JoinTable(name = "ptl_prod_client_api", joinColumns = @JoinColumn(name = "client_id"), inverseJoinColumns = @JoinColumn(name = "eaisvcname"))
|
||||
private List<ApiSpecInfo> apiList = new ArrayList<>();
|
||||
}
|
||||
@@ -7,15 +7,39 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
@EMSDataSource
|
||||
public interface CredentialRepository extends BaseRepository<Credential, String> {
|
||||
|
||||
Page<Credential> findAllByOrgidAndServer(Pageable pageable, String id, String server);
|
||||
Page<Credential> findAllByOrgid(Pageable pageable, String id);
|
||||
|
||||
int countAllByOrgidAndServer(String orgid, String server);
|
||||
int countAllByOrgid(String orgid);
|
||||
|
||||
List<Credential> findAllByOrgidAndServer(String orgid, String server);
|
||||
List<Credential> findAllByOrgid(String orgid);
|
||||
|
||||
Optional<Credential> findByClientidAndOrgidAndServer(String clientid, String orgid, String server);
|
||||
Optional<Credential> findByClientidAndOrgid(String clientid, String orgid);
|
||||
|
||||
/**
|
||||
* 특정 기관 ID 목록에 속하고 이용 가능 상태(appstatus='1')인 앱의 수를 조회
|
||||
*/
|
||||
@Query("SELECT COUNT(c) FROM Credential c WHERE c.appstatus = '1' AND c.orgid IN :orgIds")
|
||||
long countActiveAppsByOrgIds(@Param("orgIds") List<String> orgIds);
|
||||
|
||||
/**
|
||||
* 특정 기관 ID 목록에 속하고 이용 가능 상태(appstatus='1')인 앱 목록 조회
|
||||
*/
|
||||
@Query("SELECT c FROM Credential c WHERE c.appstatus = '1' AND c.orgid IN :orgIds")
|
||||
List<Credential> findActiveAppsByOrgIds(@Param("orgIds") List<String> orgIds);
|
||||
|
||||
/**
|
||||
* 이용 가능 상태인 모든 앱의 수를 조회
|
||||
*/
|
||||
long countByAppstatus(String appstatus);
|
||||
|
||||
/**
|
||||
* 이용 가능 상태인 모든 앱 목록 조회
|
||||
*/
|
||||
List<Credential> findByAppstatus(String appstatus);
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.eactive.apim.portal.app.repository;
|
||||
|
||||
import com.eactive.apim.portal.app.entity.ProdClient;
|
||||
import com.eactive.apim.portal.approval.entity.Approval;
|
||||
import com.eactive.apim.portal.approval.entity.ApprovalType;
|
||||
import com.eactive.eai.data.jpa.BaseRepository;
|
||||
import com.eactive.eai.rms.data.EMSDataSource;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
@EMSDataSource
|
||||
public interface ProdClientRepository extends BaseRepository<ProdClient, String> {
|
||||
|
||||
Page<ProdClient> findAllByOrgid(Pageable pageable, String id);
|
||||
|
||||
Optional<ProdClient> findByClientidAndOrgid(String clientid, String orgid);
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode
|
||||
@@ -27,7 +29,8 @@ public class AppRequest implements com.eactive.eai.data.Data {
|
||||
private String id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "org_id")
|
||||
@JoinColumn(name = "org_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
private PortalOrg org;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@@ -37,7 +40,8 @@ public class AppRequest implements com.eactive.eai.data.Data {
|
||||
private AppRequestType type;
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "approval_id")
|
||||
@JoinColumn(name = "approval_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
private Approval approval;
|
||||
|
||||
@Column(name = "api_list")
|
||||
@@ -64,6 +68,18 @@ public class AppRequest implements com.eactive.eai.data.Data {
|
||||
@Column(name = "reason")
|
||||
private String reason;
|
||||
|
||||
@Column(name = "app_description", length = 500)
|
||||
private String appDescription;
|
||||
|
||||
@Column(name = "callback_url", length = 255)
|
||||
private String callbackUrl;
|
||||
|
||||
@Column(name = "ip_whitelist", length = 1000)
|
||||
private String ipWhitelist;
|
||||
|
||||
@Column(name = "app_icon_file_id", length = 38)
|
||||
private String appIconFileId;
|
||||
|
||||
@Column(length = 17, name = "created_date")
|
||||
@Convert(converter = LocalDateTimeToStringConverter17.class)
|
||||
@CreationTimestamp
|
||||
|
||||
@@ -3,10 +3,7 @@ package com.eactive.apim.portal.apprequest.entity;
|
||||
public enum AppRequestType {
|
||||
NEW("API키 신규"),
|
||||
MODIFY("API 변경"),
|
||||
DELETE("API키 삭제"),
|
||||
PROD_NEW("운영 API키 신규"),
|
||||
PROD_MODIFY("운영 API 변경"),
|
||||
PROD_DELETE("운영 API키 삭제");
|
||||
DELETE("API키 삭제");
|
||||
|
||||
private final String description;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.eactive.apim.portal.approval.statemachine.ApprovalState;
|
||||
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
|
||||
import com.eactive.eai.data.jpa.BaseRepository;
|
||||
import com.eactive.eai.rms.data.EMSDataSource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -20,6 +21,8 @@ public interface AppRequestRepository extends BaseRepository<AppRequest, String>
|
||||
|
||||
Optional<AppRequest> findAppRequestByApproval(Approval approval);
|
||||
|
||||
List<AppRequest> findAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(PortalOrg org, List<AppRequestType> types, List<ApprovalState> approvalStates);
|
||||
|
||||
int countAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(PortalOrg org, List<AppRequestType> types, List<ApprovalState> approvalStates);
|
||||
|
||||
Optional<AppRequest> findByIdAndOrg(String id, PortalOrg org);
|
||||
@@ -29,4 +32,12 @@ public interface AppRequestRepository extends BaseRepository<AppRequest, String>
|
||||
List<AppRequest> findAllByClientIdsContainsAndTypeIsIn(String clientId, List<AppRequestType> types);
|
||||
|
||||
List<AppRequest> findAllByOrgAndStatus(PortalOrg org, ApprovalStatus status);
|
||||
|
||||
/**
|
||||
* org.id 목록으로 AppRequest 조회 (ObpGwMetric 집계용)
|
||||
*
|
||||
* @param orgIds 기관 ID 목록
|
||||
* @return AppRequest 목록
|
||||
*/
|
||||
List<AppRequest> findByOrg_IdIn(Collection<String> orgIds);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.hibernate.annotations.*;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
@@ -50,9 +51,9 @@ public class Approval implements Serializable, com.eactive.eai.data.Data {
|
||||
@Column(name = "target_id", nullable = false)
|
||||
private String targetId; //승인하는 대상 객체의 ID
|
||||
|
||||
@NotNull
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "REQUESTER_ID", nullable = false)
|
||||
@JoinColumn(name = "REQUESTER_ID", nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
private PortalUser requester;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "approval")
|
||||
|
||||
@@ -29,6 +29,30 @@ public class FileService {
|
||||
private final BinaryStorageService binaryStorageService;
|
||||
private final FileTypeDetector fileTypeDetector;
|
||||
|
||||
private static final ThreadLocal<Boolean> internalUserContext = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 현재 스레드에 내부 사용자 컨텍스트 설정
|
||||
*/
|
||||
public static void setInternalUserContext(boolean isInternal) {
|
||||
internalUserContext.set(isInternal);
|
||||
}
|
||||
|
||||
/**
|
||||
* 내부 사용자 컨텍스트 조회
|
||||
*/
|
||||
public static boolean isInternalUserContext() {
|
||||
Boolean isInternal = internalUserContext.get();
|
||||
return isInternal != null && isInternal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 내부 사용자 컨텍스트 정리
|
||||
*/
|
||||
public static void clearInternalUserContext() {
|
||||
internalUserContext.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 파일 ID를 기반으로 파일 정보를 검색합니다.
|
||||
*
|
||||
@@ -71,8 +95,15 @@ public class FileService {
|
||||
String type = fileTypeDetector.detectFileType(file.getBytes());
|
||||
log.debug("upload file type:{}", type);
|
||||
|
||||
if(type.equalsIgnoreCase("unknown")) {
|
||||
throw new InvalidFileException("허용된 파일 형식이 아닙니다. <br>문서파일과 이미지 파일만 등록 가능합니다. <br>(pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)");
|
||||
boolean isValidType = !type.equalsIgnoreCase("unknown");
|
||||
|
||||
if (!isValidType) {
|
||||
if (isInternalUserContext()) {
|
||||
log.warn("Internal user bypassed file validation - File: {}, Type: {}",
|
||||
file.getOriginalFilename(), type);
|
||||
} else {
|
||||
throw new InvalidFileException("허용된 파일 형식이 아닙니다. <br>문서파일과 이미지 파일만 등록 가능합니다. <br>(pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)");
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(file.getOriginalFilename()) && file.getSize() > 0) {
|
||||
@@ -82,7 +113,13 @@ public class FileService {
|
||||
fileDetail.setFileSn(fileSn);
|
||||
fileDetail.setFileSize((int) file.getSize());
|
||||
fileDetail.setOriginalFileName(FilenameUtils.getBaseName(file.getOriginalFilename()));
|
||||
fileDetail.setFileExtension(type);
|
||||
|
||||
if (isValidType) {
|
||||
fileDetail.setFileExtension(type);
|
||||
} else {
|
||||
fileDetail.setFileExtension(FilenameUtils.getExtension(file.getOriginalFilename()));
|
||||
}
|
||||
|
||||
String contentReference = binaryStorageService.store(file.getBytes());
|
||||
fileDetail.setFileContents(contentReference);
|
||||
fileInfo.getFileDetails().add(fileDetail);
|
||||
@@ -232,12 +269,17 @@ public class FileService {
|
||||
String type = fileTypeDetector.detectFileType(file.getBytes());
|
||||
log.debug("upload file type:{}", type);
|
||||
|
||||
if (isCheckMime) {
|
||||
if(type.equalsIgnoreCase("unknown")) {
|
||||
throw new InvalidFileException("허용된 파일 형식이 아닙니다. <br>문서파일과 이미지 파일만 등록 가능합니다. <br>(pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)");
|
||||
}
|
||||
} else {
|
||||
log.debug("파일 체크 옵션 해제 - FileType : {}", type);
|
||||
boolean isValidType = !type.equalsIgnoreCase("unknown");
|
||||
|
||||
if (isCheckMime && !isValidType) {
|
||||
if (isInternalUserContext()) {
|
||||
log.warn("Internal user bypassed file validation - File: {}, Type: {}",
|
||||
fileName, type);
|
||||
} else {
|
||||
throw new InvalidFileException("허용된 파일 형식이 아닙니다. <br>문서파일과 이미지 파일만 등록 가능합니다. <br>(pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)");
|
||||
}
|
||||
} else if (!isCheckMime) {
|
||||
log.debug("파일 체크 옵션 해제 - FileType : {}", type);
|
||||
}
|
||||
|
||||
FileDetail fileDetail = new FileDetail();
|
||||
@@ -252,6 +294,100 @@ public class FileService {
|
||||
|
||||
return fileDetail;
|
||||
}
|
||||
|
||||
/**
|
||||
* byte[] 데이터로 단일 파일을 생성합니다.
|
||||
*
|
||||
* @param fileName 파일 이름 (확장자 포함)
|
||||
* @param contentType 파일 MIME 타입
|
||||
* @param fileData 파일 바이트 데이터
|
||||
* @return 파일 정보
|
||||
* @throws IOException 파일 처리 중 오류 발생 시
|
||||
*/
|
||||
public FileInfo createSingleFileFromBytes(String fileName, String contentType, byte[] fileData) throws IOException {
|
||||
// 파일 타입 검증
|
||||
String type = fileTypeDetector.detectFileType(fileData);
|
||||
log.debug("upload file type from bytes: {}", type);
|
||||
|
||||
if (type.equalsIgnoreCase("unknown")) {
|
||||
throw new InvalidFileException("허용된 파일 형식이 아닙니다. <br>문서파일과 이미지 파일만 등록 가능합니다. <br>(pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)");
|
||||
}
|
||||
|
||||
// FileInfo 생성
|
||||
FileInfo fileInfo = new FileInfo();
|
||||
String fileId = UUID.randomUUID().toString();
|
||||
fileInfo.setFileId(fileId);
|
||||
fileInfo.setCreatedDate(LocalDateTime.now());
|
||||
fileInfo.setUseYn("Y");
|
||||
|
||||
// FileDetail 생성
|
||||
FileDetail fileDetail = new FileDetail();
|
||||
fileDetail.setFileId(fileId);
|
||||
fileDetail.setFileSn(1);
|
||||
fileDetail.setFileSize(fileData.length);
|
||||
fileDetail.setOriginalFileName(FilenameUtils.getBaseName(fileName));
|
||||
fileDetail.setFileExtension(FilenameUtils.getExtension(fileName));
|
||||
|
||||
// 파일 내용 저장
|
||||
String contentReference = binaryStorageService.store(fileData);
|
||||
fileDetail.setFileContents(contentReference);
|
||||
|
||||
// FileInfo에 FileDetail 추가
|
||||
fileInfo.getFileDetails().add(fileDetail);
|
||||
|
||||
// 저장 및 반환
|
||||
return fileRepository.save(fileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* byte[] 데이터로 기존 파일을 업데이트하거나 새로 생성합니다.
|
||||
*
|
||||
* @param existingFileId 기존 파일 ID (null이면 새로 생성)
|
||||
* @param fileName 파일 이름 (확장자 포함)
|
||||
* @param contentType 파일 MIME 타입
|
||||
* @param fileData 파일 바이트 데이터
|
||||
* @return 파일 정보
|
||||
* @throws IOException 파일 처리 중 오류 발생 시
|
||||
*/
|
||||
public FileInfo createOrUpdateSingleFileFromBytes(String existingFileId, String fileName, String contentType, byte[] fileData) throws IOException {
|
||||
// 신규 등록 또는 기존 파일 정보 조회
|
||||
FileInfo fileInfo = Optional.ofNullable(existingFileId)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.map(this::findById)
|
||||
.orElseGet(() -> {
|
||||
FileInfo newFile = new FileInfo();
|
||||
newFile.setFileId(UUID.randomUUID().toString());
|
||||
newFile.setCreatedDate(LocalDateTime.now());
|
||||
newFile.setUseYn("Y");
|
||||
return newFile;
|
||||
});
|
||||
|
||||
// 파일 타입 검증
|
||||
String type = fileTypeDetector.detectFileType(fileData);
|
||||
log.debug("upload file type from bytes: {}", type);
|
||||
|
||||
if (type.equalsIgnoreCase("unknown")) {
|
||||
throw new InvalidFileException("허용된 파일 형식이 아닙니다. <br>문서파일과 이미지 파일만 등록 가능합니다. <br>(pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)");
|
||||
}
|
||||
|
||||
// FileDetail 생성
|
||||
FileDetail fileDetail = new FileDetail();
|
||||
fileDetail.setFileId(fileInfo.getFileId());
|
||||
fileDetail.setFileSn(1);
|
||||
fileDetail.setFileSize(fileData.length);
|
||||
fileDetail.setOriginalFileName(FilenameUtils.getBaseName(fileName));
|
||||
fileDetail.setFileExtension(FilenameUtils.getExtension(fileName));
|
||||
|
||||
// 파일 내용 저장
|
||||
String contentReference = binaryStorageService.store(fileData);
|
||||
fileDetail.setFileContents(contentReference);
|
||||
|
||||
// 기존 파일 상세 정보 제거 후 새로운 정보 추가
|
||||
fileInfo.getFileDetails().clear();
|
||||
fileInfo.getFileDetails().add(fileDetail);
|
||||
|
||||
return fileRepository.save(fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,10 +21,11 @@ public class UserInvitationEvent implements MessageEventHandler {
|
||||
@Override
|
||||
public MessageSendEvent createEvent(Object source, MessageRecipient recipient, Map<String, Object> params) {
|
||||
Map<String, String> requestParams = new HashMap<>();
|
||||
requestParams.put("company", params.get("company").toString());
|
||||
requestParams.put("manager", params.get("manager").toString());
|
||||
requestParams.put("corpName", params.get("corpName").toString());
|
||||
requestParams.put("managerName", params.get("managerName").toString());
|
||||
requestParams.put("url", params.get("url").toString());
|
||||
requestParams.put("userName",params.get("company").toString() + " 이용자");
|
||||
requestParams.put("loginId",params.get("corpName").toString() + " 이용자");
|
||||
requestParams.put("authNumber", params.get("authNumber").toString());
|
||||
return new MessageSendEvent(source, KEY, recipient, requestParams);
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -18,4 +18,8 @@ public interface UserInvitationRepository extends JpaRepository<UserInvitation,
|
||||
List<UserInvitation> findByStatus(InvitationStatus status);
|
||||
|
||||
Optional<UserInvitation> findFirstByInvitationEmailAndStatus(String email, InvitationStatus status);
|
||||
|
||||
Optional<UserInvitation> findFirstByInvitationEmailAndOrgIdAndStatus(String email, String orgId, InvitationStatus status);
|
||||
|
||||
Optional<UserInvitation> findFirstByInvitationEmailAndOrgId(String email, String orgId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.eactive.apim.portal.obp.entity;
|
||||
|
||||
import com.eactive.eai.data.converter.LocalDateTimeToStringConverter17;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Entity
|
||||
@Table(name = "ptl_obp_gw_metric")
|
||||
public class ObpGwMetric {
|
||||
@Id
|
||||
@GeneratedValue(generator = "uuid-v1")
|
||||
@GenericGenerator(
|
||||
name = "uuid-v1",
|
||||
strategy = "org.hibernate.id.UUIDGenerator",
|
||||
parameters = {
|
||||
@Parameter(
|
||||
name = "uuid_gen_strategy_class",
|
||||
value = "org.hibernate.id.uuid.CustomVersionOneStrategy"
|
||||
)
|
||||
}
|
||||
)
|
||||
@Column(length = 36)
|
||||
@Comment("id")
|
||||
private String id;
|
||||
|
||||
|
||||
// json : appKey
|
||||
@Column(length = 256, name = "client_id")
|
||||
@Comment("클라이언트 ID")
|
||||
private String clientId;
|
||||
|
||||
// json : clusterHostname
|
||||
@Column(length = 50, name = "hostname")
|
||||
@Comment("호스트 이름")
|
||||
private String hostname;
|
||||
|
||||
// json : timeslice
|
||||
@Column(length = 17, name = "timeslice")
|
||||
@Convert(converter = LocalDateTimeToStringConverter17.class)
|
||||
@Comment("타임슬라이스 (yyyyMMddHHmmssSSS)")
|
||||
private LocalDateTime timeslice;
|
||||
|
||||
// json : apiName
|
||||
@Column(name = "api_name", length = 255)
|
||||
@Comment("API 이름")
|
||||
private String apiName;
|
||||
|
||||
// json : apiRoutingUri
|
||||
@Column(length = 255, name = "uri")
|
||||
@Comment("URI")
|
||||
private String uri;
|
||||
|
||||
// HTTP 메서드 (GET, POST, PUT, DELETE 등)
|
||||
@Column(length = 10, name = "method")
|
||||
@Comment("HTTP 메서드 (GET, POST, PUT, DELETE 등)")
|
||||
private String method;
|
||||
|
||||
// json : attemptedCount
|
||||
@Column(name = "attempted_count")
|
||||
@Comment("시도 횟수")
|
||||
private Long attemptedCount;
|
||||
|
||||
// json : completedCount
|
||||
@Column(name = "completed_count")
|
||||
@Comment("완료 횟수")
|
||||
private Long completedCount;
|
||||
|
||||
// registeredOn
|
||||
@Column(name = "created_at", nullable = false)
|
||||
@Comment("생성 날짜와 시간. 레코드가 생성된 시간")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
// registeredBy
|
||||
@Column(name = "created_by", nullable = false, length = 50)
|
||||
@Comment("생성한 사용자")
|
||||
private String createdBy = "GwMetricHourJob";
|
||||
|
||||
// modifiedOn
|
||||
@Column(name = "updated_at")
|
||||
@Comment("최종 업데이트 날짜와 시간. 레코드가 마지막으로 업데이트된 시간")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
// modifiedBy
|
||||
@Column(name = "updated_by", length = 50)
|
||||
@Comment("최종 업데이트한 사용자")
|
||||
private String updatedBy;
|
||||
|
||||
|
||||
|
||||
// eapim ID
|
||||
// json : apiIdByEapim
|
||||
@Column(length = 40, name = "api_id")
|
||||
@Comment("API ID(EAPIM) - EAISVCNAME 최대 40자")
|
||||
private String apiId;
|
||||
|
||||
// json : appIdByEapim
|
||||
@Column(length = 36, name = "app_id")
|
||||
private String appId;
|
||||
|
||||
// json : orgIdByEapim
|
||||
@Column(length = 36, name = "org_id")
|
||||
private String orgId;
|
||||
|
||||
|
||||
// AS-IS 호환용 필드
|
||||
|
||||
// json : appId
|
||||
@Column(length = 50, name = "app_id_by_ca_portal")
|
||||
@Comment("애플리케이션 ID(CA 포탈)")
|
||||
private String appIdByCaPortal;
|
||||
|
||||
// json : portalOrgId
|
||||
@Column(length = 50, name = "org_id_by_ca_portal")
|
||||
@Comment("기관 ID(CA 포탈)")
|
||||
private String orgIdByCaPortal;
|
||||
|
||||
// json : portalApiId
|
||||
@Column(length = 50, name = "api_id_by_ca_portal")
|
||||
@Comment("API ID(CA 포탈)")
|
||||
private String apiIdByCaPortal;
|
||||
|
||||
// json : partnerCode
|
||||
@Column(length = 20, name = "partner_code")
|
||||
@Comment("파트너 코드(OBP)")
|
||||
private String partnerCode;
|
||||
|
||||
// json : apiId
|
||||
@Column(name = "app_id_by_ca", length = 36)
|
||||
@Comment("API ID(CA)")
|
||||
private String apiIdByCa;
|
||||
|
||||
|
||||
@Column(name = "update_count")
|
||||
@Comment("업데이트(보정) 횟수")
|
||||
private int updateCount;
|
||||
|
||||
|
||||
// 더미
|
||||
|
||||
// requestUri
|
||||
@Transient
|
||||
private String requestUri = "-1";
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.eactive.apim.portal.obp.repository;
|
||||
|
||||
import com.eactive.apim.portal.obp.entity.ObpGwMetric;
|
||||
import com.eactive.eai.data.jpa.BaseRepository;
|
||||
import com.eactive.eai.rms.data.EMSDataSource;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* ObpGwMetric Repository
|
||||
* API Gateway 시간별 거래량 지표 조회/저장
|
||||
*/
|
||||
@EMSDataSource
|
||||
public interface ObpGwMetricRepository extends BaseRepository<ObpGwMetric, String> {
|
||||
|
||||
/**
|
||||
* UPSERT 판단을 위한 기존 데이터 조회 (NULL 안전)
|
||||
* Unique Key: (timeslice, api_id, client_id, hostname, org_id)
|
||||
*
|
||||
* <p>Spring Data JPA의 메서드 이름 기반 쿼리는 NULL 비교를 제대로 처리하지 못함.
|
||||
* SQL에서 {@code column = NULL}은 항상 false이므로, NULL 값이 있는 레코드를 찾지 못함.
|
||||
* 이 쿼리는 {@code (column = :param OR (column IS NULL AND :param IS NULL))} 패턴으로 NULL을 안전하게 처리함.</p>
|
||||
*/
|
||||
@Query("SELECT m FROM ObpGwMetric m WHERE m.timeslice = :timeslice " +
|
||||
"AND (m.apiId = :apiId OR (m.apiId IS NULL AND :apiId IS NULL)) " +
|
||||
"AND (m.clientId = :clientId OR (m.clientId IS NULL AND :clientId IS NULL)) " +
|
||||
"AND (m.hostname = :hostname OR (m.hostname IS NULL AND :hostname IS NULL)) " +
|
||||
"AND (m.orgId = :orgId OR (m.orgId IS NULL AND :orgId IS NULL))")
|
||||
Optional<ObpGwMetric> findByUniqueKeyNullSafe(
|
||||
@Param("timeslice") LocalDateTime timeslice,
|
||||
@Param("apiId") String apiId,
|
||||
@Param("clientId") String clientId,
|
||||
@Param("hostname") String hostname,
|
||||
@Param("orgId") String orgId
|
||||
);
|
||||
|
||||
/**
|
||||
* @deprecated NULL 비교 문제로 {@link #findByUniqueKeyNullSafe} 사용 권장
|
||||
*/
|
||||
@Deprecated
|
||||
Optional<ObpGwMetric> findByTimesliceAndApiIdAndClientIdAndHostnameAndOrgId(
|
||||
LocalDateTime timeslice,
|
||||
String apiId,
|
||||
String clientId,
|
||||
String hostname,
|
||||
String orgId
|
||||
);
|
||||
|
||||
/**
|
||||
* 특정 시간대의 모든 지표 조회 (REST API 용)
|
||||
*/
|
||||
List<ObpGwMetric> findByTimeslice(LocalDateTime timeslice);
|
||||
|
||||
/**
|
||||
* 특정 시간대 범위의 지표 조회
|
||||
*/
|
||||
List<ObpGwMetric> findByTimesliceBetween(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
/**
|
||||
* API ID로 지표 조회
|
||||
*/
|
||||
List<ObpGwMetric> findByApiIdAndTimeslice(String apiId, LocalDateTime timeslice);
|
||||
|
||||
/**
|
||||
* 특정 시간대 이후의 모든 지표 조회 (REST API 용)
|
||||
*/
|
||||
List<ObpGwMetric> findByTimesliceGreaterThanEqual(LocalDateTime timeslice);
|
||||
|
||||
/**
|
||||
* 특정 시간대 이후의 지표 조회 (페이징 지원)
|
||||
*
|
||||
* @param timeslice 조회 시작 시간대
|
||||
* @param pageable 페이징 및 정렬 정보
|
||||
* @return 조회된 지표 목록
|
||||
*/
|
||||
List<ObpGwMetric> findByTimesliceGreaterThanEqual(LocalDateTime timeslice, Pageable pageable);
|
||||
}
|
||||
-1
@@ -26,7 +26,6 @@ public class PartnershipApplication extends Auditable {
|
||||
@Comment("비즈니스제목")
|
||||
private String bizSubject;
|
||||
|
||||
@Lob
|
||||
@Column(name = "biz_detail", nullable = false)
|
||||
@Comment("비즈니스내용")
|
||||
private String bizDetail;
|
||||
|
||||
@@ -12,6 +12,10 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
/**
|
||||
* 25.11.26 - 광주은행에서는 기관코드를 OBP 파트너코드와 매칭 시킴. 즉, 자동 생성 사용안함
|
||||
*/
|
||||
@Deprecated
|
||||
@Slf4j
|
||||
public class OrgCodeGenerator implements ValueGenerator<String> {
|
||||
private static final String TABLE_NAME = "PTL_ID";
|
||||
|
||||
@@ -3,18 +3,12 @@ package com.eactive.apim.portal.portalorg.entity;
|
||||
import com.eactive.apim.portal.common.entity.Auditable;
|
||||
import com.eactive.apim.portal.portalorg.entity.PortalOrgEnums.ApprovalStatus;
|
||||
import com.eactive.apim.portal.portalorg.entity.PortalOrgEnums.OrgStatus;
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.GenerationTime;
|
||||
import org.hibernate.annotations.GeneratorType;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true)
|
||||
@@ -40,8 +34,8 @@ public class PortalOrg extends Auditable implements Serializable, com.eactive.ea
|
||||
private String orgName;
|
||||
|
||||
@Column(name = "org_code")
|
||||
@Comment("제휴기관코드")
|
||||
@GeneratorType(type = OrgCodeGenerator.class, when = GenerationTime.INSERT)
|
||||
@Comment("제휴기관코드 - OBP 파트너코드")
|
||||
// @GeneratorType(type = OrgCodeGenerator.class, when = GenerationTime.INSERT)
|
||||
private String orgCode;
|
||||
|
||||
@Column(name = "org_desc", length = 255)
|
||||
|
||||
+55
@@ -2,21 +2,27 @@ package com.eactive.apim.portal.portalproperty.service;
|
||||
|
||||
import com.eactive.apim.portal.portalproperty.entity.PortalProperty;
|
||||
import com.eactive.apim.portal.portalproperty.entity.PortalPropertyGroup;
|
||||
import com.eactive.apim.portal.portalproperty.entity.PortalPropertyId;
|
||||
import com.eactive.apim.portal.portalproperty.repository.PortalPropertyGroupRepository;
|
||||
import com.eactive.apim.portal.portalproperty.repository.PortalPropertyRepository;
|
||||
import com.eactive.eai.data.jpa.AbstractDataService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional
|
||||
public class PortalPropertyService extends AbstractDataService<PortalPropertyGroup, String, PortalPropertyGroupRepository> {
|
||||
|
||||
private final PortalPropertyGroupRepository portalPropertyGroupRepository;
|
||||
private final PortalPropertyRepository portalPropertyRepository;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Map<String, String> getPortalPropertiesAsMap(String propertyGroupName) {
|
||||
@@ -31,5 +37,54 @@ public class PortalPropertyService extends AbstractDataService<PortalPropertyGro
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 프로퍼티 값을 조회하고, 없으면 기본값을 DB에 저장 후 반환
|
||||
*
|
||||
* @param groupName 프로퍼티 그룹명
|
||||
* @param propertyName 프로퍼티명
|
||||
* @param defaultValue 기본값
|
||||
* @param description 프로퍼티 설명 (신규 생성 시 사용)
|
||||
* @return 프로퍼티 값
|
||||
*/
|
||||
public String getOrCreateProperty(String groupName, String propertyName, String defaultValue, String description) {
|
||||
PortalPropertyId propertyId = new PortalPropertyId(groupName, propertyName);
|
||||
Optional<PortalProperty> existingProperty = portalPropertyRepository.findById(propertyId);
|
||||
|
||||
if (existingProperty.isPresent()) {
|
||||
return existingProperty.get().getPropertyValue();
|
||||
}
|
||||
|
||||
// 프로퍼티가 없으면 기본값으로 생성
|
||||
return createDefaultProperty(groupName, propertyName, defaultValue, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 프로퍼티를 DB에 생성
|
||||
*/
|
||||
private String createDefaultProperty(String groupName, String propertyName, String defaultValue, String description) {
|
||||
try {
|
||||
// 그룹이 존재하는지 확인
|
||||
PortalPropertyGroup group = portalPropertyGroupRepository.findById(groupName)
|
||||
.orElse(null);
|
||||
|
||||
if (group == null) {
|
||||
log.warn("프로퍼티 그룹 '{}'이 존재하지 않아 기본값 저장을 건너뜁니다.", groupName);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// 새 프로퍼티 생성
|
||||
PortalProperty newProperty = new PortalProperty();
|
||||
newProperty.setId(new PortalPropertyId(groupName, propertyName));
|
||||
newProperty.setPropertyValue(defaultValue);
|
||||
newProperty.setPropertyDesc(description);
|
||||
|
||||
portalPropertyRepository.save(newProperty);
|
||||
log.info("기본 프로퍼티 생성 완료 - 그룹: {}, 키: {}, 값: {}", groupName, propertyName, defaultValue);
|
||||
|
||||
return defaultValue;
|
||||
} catch (Exception e) {
|
||||
log.error("기본 프로퍼티 생성 실패 - 그룹: {}, 키: {}", groupName, propertyName, e);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -60,6 +62,7 @@ public class PortalUser extends Auditable implements Serializable, com.eactive.e
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "org_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
private PortalOrg portalOrg;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.eactive.apim.portal.portaluser.entity;
|
||||
public class PortalUserEnums {
|
||||
|
||||
public enum UserStatus {
|
||||
PENDING("대기"),
|
||||
READY("준비"),
|
||||
ACTIVE("정상"),
|
||||
PW_FAIL("비밀번호 5회 실패"),
|
||||
|
||||
+4
-1
@@ -10,17 +10,20 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@EMSDataSource
|
||||
public interface PortalUserRepository extends BaseRepository<PortalUser, String> {
|
||||
|
||||
Optional<PortalUser> findByLoginId(String userName);
|
||||
Optional<PortalUser> findByLoginId(String String);
|
||||
|
||||
Optional<PortalUser> findPortalUserByEmailAddr(String loginId);
|
||||
|
||||
PortalUser findByUserNameAndMobileNumber(String userName, String mobileNumber);
|
||||
|
||||
List<PortalUser> findAllByUserNameAndMobileNumber(String userName, String mobileNumber);
|
||||
|
||||
Optional<PortalUser> findByLoginIdAndUserNameAndMobileNumber(String loginId, String userName, String mobileNumber);
|
||||
|
||||
boolean existsByLoginId(String loginId);
|
||||
|
||||
@@ -8,6 +8,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -55,7 +57,8 @@ public class Inquiry extends Auditable {
|
||||
* 문의자
|
||||
*/
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "INQUIRER_ID")
|
||||
@JoinColumn(name = "INQUIRER_ID", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
private PortalUser inquirer;
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,8 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
@@ -59,6 +61,7 @@ public class MessageRequest implements Serializable {
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "user_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
@Comment("발송 대상 사용자")
|
||||
private PortalUser user;
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.springframework.data.annotation.LastModifiedDate;
|
||||
import com.eactive.eai.data.converter.LocalDateTimeToStringConverter14;
|
||||
import com.eactive.eai.data.converter.StringTrimConverter;
|
||||
import com.eactive.eai.data.entity.AbstractEntity;
|
||||
import kjb.safedb.KjbNotRnnoJpaAttributeConverter;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -53,6 +54,7 @@ public class UserInfo extends AbstractEntity<String> implements Serializable {
|
||||
|
||||
@Column(length = 40)
|
||||
@Comment("휴대폰 번호")
|
||||
@Convert(converter = KjbNotRnnoJpaAttributeConverter.class)
|
||||
private String cphnno;
|
||||
|
||||
@Column(length = 40)
|
||||
@@ -61,6 +63,7 @@ public class UserInfo extends AbstractEntity<String> implements Serializable {
|
||||
|
||||
@Column(length = 100)
|
||||
@Comment("이메일 주소")
|
||||
@Convert(converter = KjbNotRnnoJpaAttributeConverter.class)
|
||||
private String emad;
|
||||
|
||||
@Column(length = 3)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package kjb.safedb;
|
||||
|
||||
import com.eactive.ext.kjb.safedb.KjbSafedbWrapper;
|
||||
import com.eactive.ext.kjb.safedb.SafeDBColumns;
|
||||
import com.eactive.ext.kjb.safedb.Utils;
|
||||
//import com.eactive.ext.kjb.safedb.KjbSafedbWrapper;
|
||||
//import com.eactive.ext.kjb.safedb.SafeDBColumns;
|
||||
//import com.eactive.ext.kjb.safedb.Utils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -25,26 +25,26 @@ public class KjbNotRnnoJpaAttributeConverter implements AttributeConverter<Strin
|
||||
public String convertToDatabaseColumn(String attribute) {
|
||||
// log.debug("DB 암호화 #1 - {} / {}", attribute, SafeDBColumns.NOT_RNNO);
|
||||
|
||||
String originalAttribute = attribute;
|
||||
if (StringUtils.isNotEmpty(attribute)) {
|
||||
KjbSafedbWrapper wrapper = KjbSafedbWrapper.getInstance();
|
||||
attribute = wrapper.encryptNotRnnoString(attribute);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
// originalAttribute 홀수 글자 마스킹
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < originalAttribute.length(); i++) {
|
||||
if (i % 2 == 0) {
|
||||
sb.append(originalAttribute.charAt(i));
|
||||
} else {
|
||||
sb.append("*");
|
||||
}
|
||||
}
|
||||
|
||||
originalAttribute = sb.toString();
|
||||
log.debug("DB 암호화 #2 : {} -> {}", originalAttribute, attribute);
|
||||
}
|
||||
}
|
||||
// String originalAttribute = attribute;
|
||||
// if (StringUtils.isNotEmpty(attribute)) {
|
||||
// KjbSafedbWrapper wrapper = KjbSafedbWrapper.getInstance();
|
||||
// attribute = wrapper.encryptNotRnnoString(attribute);
|
||||
//
|
||||
// if (log.isDebugEnabled()) {
|
||||
// // originalAttribute 홀수 글자 마스킹
|
||||
// StringBuilder sb = new StringBuilder();
|
||||
// for (int i = 0; i < originalAttribute.length(); i++) {
|
||||
// if (i % 2 == 0) {
|
||||
// sb.append(originalAttribute.charAt(i));
|
||||
// } else {
|
||||
// sb.append("*");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// originalAttribute = sb.toString();
|
||||
// log.debug("DB 암호화 #2 : {} -> {}", originalAttribute, attribute);
|
||||
// }
|
||||
// }
|
||||
|
||||
return attribute;
|
||||
}
|
||||
@@ -59,23 +59,23 @@ public class KjbNotRnnoJpaAttributeConverter implements AttributeConverter<Strin
|
||||
public String convertToEntityAttribute(String dbData) {
|
||||
// log.debug("DB 복호화 #1 - {} / {}", dbData, SafeDBColumns.NOT_RNNO);
|
||||
|
||||
String dbDataOriginal = dbData;
|
||||
if (StringUtils.isNotEmpty(dbData)) {
|
||||
if (this.isEncrypted(dbData)) {
|
||||
KjbSafedbWrapper safeDBWrapper = KjbSafedbWrapper.getInstance();
|
||||
try {
|
||||
dbData = safeDBWrapper.decryptNotRnno(dbData);
|
||||
} catch (Exception e) {
|
||||
// 복호화 실패시 원본 반환
|
||||
String logData = dbData.length() <= 3 ? dbData : dbData.substring(0, 3) + "...";
|
||||
log.warn("DB 복호화 실패: 복호화하지 않고 원본 반환. dbData={} (Length : {})", logData, dbData.length());
|
||||
needFixLogger.warn("DB 복호화 실패: 복호화하지 않고 원본 반환. dbData={} (Length : {})", logData, dbData.length(), e);
|
||||
return dbData;
|
||||
}
|
||||
} else {
|
||||
log.debug("DB 복호화 경고: Base64 형식이 아님. 복호화하지 않고 원본 반환. dbData={}", dbData);
|
||||
}
|
||||
}
|
||||
// String dbDataOriginal = dbData;
|
||||
// if (StringUtils.isNotEmpty(dbData)) {
|
||||
// if (this.isEncrypted(dbData)) {
|
||||
// KjbSafedbWrapper safeDBWrapper = KjbSafedbWrapper.getInstance();
|
||||
// try {
|
||||
// dbData = safeDBWrapper.decryptNotRnno(dbData);
|
||||
// } catch (Exception e) {
|
||||
// // 복호화 실패시 원본 반환
|
||||
// String logData = dbData.length() <= 3 ? dbData : dbData.substring(0, 3) + "...";
|
||||
// log.warn("DB 복호화 실패: 복호화하지 않고 원본 반환. dbData={} (Length : {})", logData, dbData.length());
|
||||
// needFixLogger.warn("DB 복호화 실패: 복호화하지 않고 원본 반환. dbData={} (Length : {})", logData, dbData.length(), e);
|
||||
// return dbData;
|
||||
// }
|
||||
// } else {
|
||||
// log.debug("DB 복호화 경고: Base64 형식이 아님. 복호화하지 않고 원본 반환. dbData={}", dbData);
|
||||
// }
|
||||
// }
|
||||
|
||||
// log.debug("DB 복호화 #2 : {} -> {}", dbDataOriginal, dbData);
|
||||
|
||||
@@ -88,28 +88,29 @@ public class KjbNotRnnoJpaAttributeConverter implements AttributeConverter<Strin
|
||||
* @return
|
||||
*/
|
||||
private boolean isEncrypted(String data) {
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 숫자, - 로만 구성된 경우 암호화 되지 않은 걸로 판단 (ex: 연락처)
|
||||
if (data.matches("^[0-9-]+$")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data = data.trim();
|
||||
|
||||
// Base64 형식 체크
|
||||
if (!Utils.isBase64(data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Base64 길이 체크 (4의 배수)
|
||||
if (data.length() % 4 != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
// if (StringUtils.isEmpty(data)) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// // 숫자, - 로만 구성된 경우 암호화 되지 않은 걸로 판단 (ex: 연락처)
|
||||
// if (data.matches("^[0-9-]+$")) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// data = data.trim();
|
||||
//
|
||||
// // Base64 형식 체크
|
||||
// if (!Utils.isBase64(data)) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// // Base64 길이 체크 (4의 배수)
|
||||
// if (data.length() % 4 != 0) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user