iflex 1.8.0과 Firo 통합 가이드
개요
이 가이드는 iflex 1.8.0 프로젝트에 Firo 파일 관리 라이브러리를 안전하게 통합하는 방법을 설명합니다.
통합 전 체크리스트
1. 버전 호환성 확인
- iflex 버전: 1.8.0+
- Firo 버전: 1.3.1-SNAPSHOT+
- Spring Boot: 3.4.4+
- Java: 17+
2. 의존성 호환성 확인
- MyBatis: iflex와 Firo 모두 지원
- Spring Data JPA: 선택사항 (Firo에서만 사용 가능)
단계별 통합 가이드
1단계: 의존성 추가
Gradle 설정 (build.gradle)
gradle
dependencies {
// 기존 iflex 의존성들...
// Firo 의존성 추가 (iflex 의존성 이후에 추가)
implementation 'com.unvus.firo:firo-core:1.3.1-SNAPSHOT'
implementation 'com.unvus.firo:firo-mybatis:1.3.1-SNAPSHOT' // iflex는 MyBatis 사용
}
Maven 설정 (pom.xml)
xml
<dependencies>
<!-- 기존 iflex 의존성들... -->
<!-- Firo 의존성 추가 -->
<dependency>
<groupId>com.unvus.firo</groupId>
<artifactId>firo-core</artifactId>
<version>1.3.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.unvus.firo</groupId>
<artifactId>firo-mybatis</artifactId>
<version>1.3.1-SNAPSHOT</version>
</dependency>
</dependencies>
2단계: 설정 파일 구성
application.properties
properties
# === Firo 설정 ===
# Firo 활성화
firo.enabled=true
# MyBatis 사용 (iflex와 동일)
firo.db.type=mybatis
# 파일 업로드 기본 설정
firo.directory.base-dir=/var/uploads/
firo.directory.tmp-dir=/var/uploads/temp/
firo.cdn-url=https://cdn.yourdomain.com/
# 최대 파일 크기 설정
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB
# === iflex 기존 설정은 그대로 유지 ===
# iflex.xxx=...
application.yml
yaml
# Firo 설정
firo:
enabled: true
db:
type: mybatis # iflex와 동일
directory:
base-dir: /var/uploads/
tmp-dir: /var/uploads/temp/
cdn-url: https://cdn.yourdomain.com/
api-prefix: /api/firo
# Spring Boot 설정
spring:
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
# iflex 기존 설정은 그대로 유지
# iflex:
# xxx: ...
application-dev.properties (개발 환경)
properties
# Firo 개발 환경 설정
firo.enabled=true
firo.db.type=mybatis
firo.directory.base-dir=./uploads/
firo.directory.tmp-dir=./uploads/temp/
# 디버깅 로깅
logging.level.com.unvus.firo=DEBUG
logging.level.com.unvus.firo.mybatis.mapper=DEBUG
application-dev.yml (개발 환경)
yaml
# Firo 개발 환경 설정
firo:
enabled: true
db:
type: mybatis
directory:
base-dir: ./uploads/
tmp-dir: ./uploads/temp/
logging:
level:
com.unvus.firo: DEBUG
com.unvus.firo.mybatis.mapper: DEBUG
3단계: 데이터베이스 테이블 생성
MySQL DDL
sql
-- Firo 파일 관리 테이블 (iflex 테이블 프리픽스에 맞춰 조정)
CREATE TABLE attach (
attach_id BIGINT AUTO_INCREMENT PRIMARY KEY,
attach_ref_domain VARCHAR(50) NOT NULL,
attach_ref_key BIGINT NOT NULL,
attach_ref_category VARCHAR(50) NOT NULL DEFAULT 'default',
attach_display_name VARCHAR(255) NOT NULL,
attach_saved_name VARCHAR(255) NOT NULL,
attach_saved_dir VARCHAR(500) NOT NULL,
attach_file_type VARCHAR(100),
attach_file_size BIGINT,
attach_deleted BOOLEAN DEFAULT FALSE,
attach_ext VARCHAR(100),
attach_created_by BIGINT,
attach_created_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_attach_ref (attach_ref_domain, attach_ref_key, attach_ref_category),
INDEX idx_attach_deleted (attach_deleted)
);
프리픽스가 있는 경우
properties
# iflex 테이블 프리픽스 설정 (예: ha_attach)
firo.database.table-prefix=ha_
4단계: Spring Configuration 설정
FiroIflex통합Configuration.java
java
package com.yourproject.config;
import com.unvus.firo.core.module.service.FiroRegistry;
import com.unvus.firo.core.module.service.domain.FiroDomain;
import com.unvus.firo.core.module.service.domain.FiroCategory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Slf4j
@Configuration
public class FiroIflexIntegrationConfiguration {
@PostConstruct
public void setupFiroDomains() {
// iflex 프로젝트에 맞는 도메인 설정
// 사용자 프로필 이미지
FiroDomain userDomain = FiroDomain.builder("user")
.build();
userDomain.addCategory("profile"); // 프로필 사진
userDomain.addCategory("avatar"); // 아바타
FiroRegistry.add(userDomain);
// 게시판 첨부파일
FiroDomain boardDomain = FiroDomain.builder("board")
.build();
boardDomain.addCategory("attachment"); // 일반 첨부파일
boardDomain.addCategory("image"); // 이미지 첨부파일
FiroRegistry.add(boardDomain);
// 공통 파일
FiroDomain commonDomain = FiroDomain.builder("common")
.build();
commonDomain.addCategory("temp"); // 임시 파일
commonDomain.addCategory("document"); // 문서 파일
FiroRegistry.add(commonDomain);
log.info("Firo domains configured for iflex integration");
}
}
5단계: 통합 테스트
기본 연동 테스트
java
package com.yourproject.service;
import com.unvus.firo.core.module.service.FiroService;
import com.unvus.firo.core.module.service.domain.FiroFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@Service
public class FileUploadService {
@Autowired
private FiroService firoService;
public String uploadUserProfile(Long userId, MultipartFile file) {
try {
// 임시 업로드
String tempUuid = firoService.uploadTemp(file, "user", "profile");
// 실제 저장 (사용자 ID를 refKey로 사용)
String savedPath = firoService.save(userId, tempUuid, "user", "profile");
return savedPath;
} catch (Exception e) {
throw new RuntimeException("파일 업로드 실패", e);
}
}
public List<FiroFile> getUserProfileImages(Long userId) {
return firoService.listAttachByRef("user", userId, "profile");
}
}
6단계: API 엔드포인트 사용
Firo REST API 사용 예시
java
package com.yourproject.service;
import com.unvus.firo.core.module.service.FiroService;
import com.unvus.firo.core.module.service.domain.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@Service
public class UserFileService {
@Autowired
private FiroService firoService;
public String uploadUserProfile(Long userId, MultipartFile file) {
try {
// 1. 임시 업로드
FiroCategory category = FiroRegistry.get("user", "profile");
String tempUuid = firoService.uploadTemp(file, category, null, true);
// 2. AttachBag 생성 및 저장
AttachBag bag = new AttachBag("user");
FiroFile firoFile = new FiroFile();
firoFile.setDisplayName(file.getOriginalFilename());
firoFile.setSavedName(tempUuid);
firoFile.setFileType(file.getContentType());
firoFile.setFileSize(file.getSize());
bag.add("profile", firoFile);
List<FiroFile> savedFiles = firoService.save(
userId, bag, LocalDateTime.now(), false, false
);
return savedFiles.get(0).getSavedDir() + savedFiles.get(0).getSavedName();
} catch (Exception e) {
throw new RuntimeException("파일 업로드 실패", e);
}
}
public AttachBag getUserFiles(Long userId) {
return firoService.getAttachBagByRef("user", userId, null);
}
}
또는 Firo의 내장 REST API 직접 사용
bash
# 임시 파일 업로드
curl -X POST \
http://localhost:8080/api/firo/attach/tmp \
-F 'file=@profile.jpg' \
-F 'refDomain=user' \
-F 'refCategory=profile'
# AttachBag 저장
curl -X POST \
http://localhost:8080/api/firo/attach/user/123 \
-H 'Content-Type: application/json' \
-d '{
"categories": {
"profile": [{
"displayName": "profile.jpg",
"savedName": "temp-uuid-123.jpg",
"fileType": "image/jpeg",
"fileSize": 102400
}]
},
"cleanDomain": false,
"keepTemp": false
}'
# AttachBag 조회
curl -X GET http://localhost:8080/api/firo/attach/user/123
## 주의사항 및 베스트 프랙티스
### 1. SqlSessionFactory 통합
- **동일한 SqlSessionFactory 사용**: iflex와 Firo가 같은 SqlSessionFactory를 공유해야 함
- **Mapper 스캔 설정**: `@MapperScans`를 사용하여 모든 Mapper를 등록
- **Type Alias 관리**: 사용자가 직접 Type Alias를 등록해야 함
### 2. MyBatis Type Alias 관리
- **수동 등록 필요**: Firo Type Alias를 수동으로 등록해야 함
- **충돌 방지**: 서로 다른 패키지의 동명 클래스 주의
- **테스트**: 기존 iflex MyBatis 쿼리가 정상 동작하는지 확인
### 3. 테이블 네이밍 통일
```properties
# iflex 테이블 명명 규칙에 맞춤
firo.database.table-prefix=ha_ # ha_attach 테이블 사용
4. 파일 저장소 설정
properties
# 프로덕션에서는 클라우드 스토리지 사용 권장
firo.s3.access-key=${AWS_ACCESS_KEY_ID}
firo.s3.secret-key=${AWS_SECRET_ACCESS_KEY}
firo.s3.bucket=iflex-files
firo.s3.region=ap-northeast-2
5. 성능 최적화
properties
# 파일 업로드 성능 최적화
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB
firo.directory.tmp-dir=/var/tmp/firo/ # 충분한 디스크 공간 확보
6. 보안 설정
java
@Configuration
public class FiroSecurityConfiguration {
@Bean
public SecureAccessFunc secureAccessFunc() {
return (request, firoFile) -> {
// iflex 보안 정책에 맞는 접근 제어 구현
// 예: 사용자 권한 확인, 파일 소유권 검증 등
return true; // 또는 실제 보안 로직
};
}
}
트러블슈팅
자주 발생하는 문제들
Mapper 인식 실패:
@MapperScan
에 Firo Mapper 패키지가 올바르게 등록되어 있는지 확인basePackages = "com.unvus.firo.mybatis.mapper"
Type Alias 오류:
- Firo Type Alias가 올바르게 등록되어 있는지 확인
"Result Maps collection does not contain value"
오류 시 Type Alias 등록 상태 확인
SqlSessionFactory 충돌:
- 모든 Mapper가 동일한
sqlSessionFactoryRef
를 사용하는지 확인
- 모든 Mapper가 동일한
테이블 없음: DDL 실행 및 테이블 프리픽스 확인
파일 업로드 실패: 디렉터리 권한 및 크기 제한 확인
디버깅 로깅
properties
# Firo 관련 로깅
logging.level.com.unvus.firo=DEBUG
logging.level.com.unvus.firo.mybatis.mapper=DEBUG
# iflex 관련 로깅 (기존 설정 유지)
logging.level.com.yourproject=DEBUG
지원 및 문의
추가 지원이 필요한 경우:
- 문서 참고: 트러블슈팅 가이드
- 로그 분석: DEBUG 레벨 로그로 상세 정보 확인
- 설정 검증: 모든 필수 설정이 올바른지 확인
- GitHub Issues: 구체적인 오류 정보와 함께 문의
마이그레이션 체크리스트
- [ ] 의존성 추가 완료
- [ ] application.properties 설정 완료
- [ ] 데이터베이스 테이블 생성 완료
- [ ] Spring Configuration 설정 완료
- [ ] 기본 파일 업로드 테스트 완료
- [ ] 기존 iflex 기능 정상 동작 확인
- [ ] MyBatis 쿼리 정상 실행 확인
- [ ] 프로덕션 환경 설정 완료