Skip to content

Firo 설정 가이드

기본 설정

application.properties 기본 설정

properties
# Firo 활성화 설정 (기본값: true)
firo.enabled=true

# 데이터베이스 구현체 선택 (기본값: jpa)
firo.db.type=jpa  # jpa 또는 mybatis

# API 라우팅 설정
firo.api-prefix=/api/firo

# 파일 업로드 기본 설정
firo.cdn-url=https://cdn.example.com/
firo.directory.base-dir=./uploads/
firo.directory.tmp-dir=./uploads/temp/
firo.directory.separator=/
firo.direct-upload-path=direct

# 최대 파일 크기 설정
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB

# 프로파일 설정
spring.profiles.active=local

application.yml 기본 설정

yaml
# Firo 기본 설정
firo:
  enabled: true
  db:
    type: jpa  # jpa 또는 mybatis
  cdn-url: https://cdn.example.com/
  directory:
    base-dir: /var/uploads/
    tmp-dir: /var/uploads/temp/
    separator: /
  direct-upload-path: direct

# Spring Boot 파일 업로드 설정
spring:
  servlet:
    multipart:
      max-file-size: 100MB
      max-request-size: 100MB

⚠️ 조건부 Bean 로딩:

  • firo.db.type 설정에 따라 JPA 또는 MyBatis 구현체만 로드됩니다
  • Azure/S3 어댑터는 해당 설정이 있을 때만 활성화됩니다
  • 필요하지 않은 어댑터 설정은 생략할 수 있습니다

데이터베이스 설정

테이블 프리픽스 설정 (선택사항)

Firo는 테이블명 앞에 프리픽스를 추가할 수 있습니다. 기본적으로는 attach 테이블을 사용하지만, 프리픽스를 설정하면 {prefix}attach 형태로 테이블명이 변경됩니다.

properties
# 테이블 프리픽스 설정 (선택사항)
firo.database.table-prefix=nv_        # nv_attach 테이블 사용
# firo.database.table-prefix=ha_      # ha_attach 테이블 사용  
# firo.database.table-prefix=         # attach 테이블 사용 (기본값)

사용 예시:

  • 프리픽스 없음 (기본): attach 테이블
  • firo.database.table-prefix=nv_: nv_attach 테이블
  • firo.database.table-prefix=company_: company_attach 테이블

JPA 설정

Properties 방식

properties
firo.db.type=jpa

# JPA/Hibernate 설정
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true

# 데이터베이스 연결
spring.datasource.url=jdbc:mysql://localhost:3306/firo_db
spring.datasource.username=firo_user
spring.datasource.password=firo_password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

YAML 방식

yaml
firo:
  db:
    type: jpa

spring:
  jpa:
    hibernate:
      ddl-auto: validate
    show-sql: false
    properties:
      hibernate:
        format_sql: true
        use_sql_comments: true
  datasource:
    url: jdbc:mysql://localhost:3306/firo_db
    username: firo_user
    password: firo_password
    driver-class-name: com.mysql.cj.jdbc.Driver

MyBatis 설정

중요: Firo MyBatis 모듈은 외부 프로젝트에서 제공하는 SqlSessionFactory를 사용합니다. 별도의 SqlSessionFactory를 생성하지 않으므로 기존 MyBatis 설정과 충돌하지 않습니다.

기본 설정

Properties 방식

properties
# Firo MyBatis 모듈 활성화
firo.db.type=mybatis

# 기존 MyBatis 설정은 그대로 유지
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true

# 데이터베이스 연결
spring.datasource.url=jdbc:mysql://localhost:3306/your_db
spring.datasource.username=your_user
spring.datasource.password=your_password

YAML 방식

yaml
firo:
  db:
    type: mybatis

# 기존 MyBatis 설정은 그대로 유지
mybatis:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true
    use-generated-keys: true

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/your_db
    username: your_user
    password: your_password

외부 프로젝트와 통합 시 필수 설정

Firo Mapper들을 외부 SqlSessionFactory에 등록하기 위해 다음과 같이 설정해야 합니다:

java
@Configuration
@MapperScans({
    @MapperScan(
        basePackages = "com.yourproject.mapper",
        annotationClass = DefaultMapper.class, // 또는 기존 마커 어노테이션
        sqlSessionFactoryRef = "defaultSqlSessionFactory"
    ),
    @MapperScan(
        basePackages = "com.unvus.firo.mybatis.mapper", // Firo Mapper 패키지
        annotationClass = Mapper.class,
        sqlSessionFactoryRef = "defaultSqlSessionFactory" // 동일한 SqlSessionFactory 사용
    )
})
public class MyBatisConfiguration {
    
    @Primary
    @Bean("defaultSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(
        @Qualifier("defaultDataSource") DataSource dataSource) throws Exception {
        
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        
        // Mapper XML 위치 설정
        Resource[] mapperResources = new PathMatchingResourcePatternResolver()
            .getResources("classpath*:mapper/*.xml");
        sessionFactory.setMapperLocations(mapperResources);
        
        // MyBatis Configuration
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setUseGeneratedKeys(true);
        
        // Firo Type Alias 등록 (선택사항)
        configuration.getTypeAliasRegistry().registerAlias("FiroFile", com.unvus.firo.core.module.service.domain.FiroFile.class);
        configuration.getTypeAliasRegistry().registerAlias("FiroAttachBag", com.unvus.firo.core.module.service.domain.AttachBag.class);
        
        sessionFactory.setConfiguration(configuration);
        
        return sessionFactory.getObject();
    }
}

⚠️ Type Alias 관리: Firo는 외부 SqlSessionFactory를 사용하믰로 Type Alias는 사용자가 직접 등록해야 합니다. 위 예시에서처럼 configuration.getTypeAliasRegistry().registerAlias()를 사용하거나, 패키지 스캔을 이용할 수 있습니다.

가능한 Type Alias 목록:

  • FiroFilecom.unvus.firo.core.module.service.domain.FiroFile
  • FiroDomaincom.unvus.firo.core.module.service.domain.FiroDomain
  • FiroCategorycom.unvus.firo.core.module.service.domain.FiroCategory
  • AttachBagcom.unvus.firo.core.module.service.domain.AttachBag
  • AttachContainercom.unvus.firo.core.module.service.domain.AttachContainer
  • SecureAccessFunccom.unvus.firo.core.module.service.domain.SecureAccessFunc

패키지 스캔 방식 (추천):

java
// Configuration에서 패키지 스캔으로 등록
configuration.getTypeAliasRegistry().registerAliases("com.unvus.firo.core.module.service.domain");

저장소 어댑터 설정

1. Local 어댑터 (기본값)

Properties 방식

properties
# Local 파일 시스템 사용
firo.adapters.local.directory.base-dir=/var/uploads/
firo.adapters.local.directory.tmp-dir=/var/uploads/temp/
firo.adapters.local.directory.separator=/

YAML 방식

yaml
firo:
  adapters:
    local:
      directory:
        base-dir: /var/uploads/
        tmp-dir: /var/uploads/temp/
        separator: /

2. Amazon S3 어댑터

Properties 방식

properties
# S3 설정
firo.s3.access-key=AKIA...
firo.s3.secret-key=your-secret-key
firo.s3.bucket=your-bucket-name
firo.s3.region=us-west-2

# CDN 설정 (선택사항)
firo.s3.cdn-url=https://d1234567890.cloudfront.net/

YAML 방식

yaml
firo:
  s3:
    access-key: AKIA...
    secret-key: your-secret-key
    bucket: your-bucket-name
    region: us-west-2
    cdn-url: https://d1234567890.cloudfront.net/

⚠️ 중요사항:

  • access-key 속성이 설정되어야 S3 Adapter가 활성화됩니다.
  • 설정이 누락되면 firo는 S3 없이 정상적으로 초기화됩니다.

S3 IAM 정책 예시

json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::your-bucket-name",
                "arn:aws:s3:::your-bucket-name/*"
            ]
        }
    ]
}

3. Azure Blob Storage 어댑터

Properties 방식

properties
# Azure Blob Storage 설정 (모든 속성이 필수)
firo.azure.connection-string=DefaultEndpointsProtocol=https;AccountName=yourstorageaccount;AccountKey=your-key;EndpointSuffix=core.windows.net
firo.azure.container=files
firo.azure.cdn-url=https://yourstorageaccount.blob.core.windows.net/

YAML 방식

yaml
firo:
  azure:
    connection-string: >
      DefaultEndpointsProtocol=https;
      AccountName=yourstorageaccount;
      AccountKey=your-key;
      EndpointSuffix=core.windows.net
    container: files
    cdn-url: https://yourstorageaccount.blob.core.windows.net/

⚠️ 중요사항:

  • connection-stringcontainer 속성이 모두 설정되어야 Azure Adapter가 활성화됩니다.
  • 설정이 누락되면 firo는 Azure 없이 정상적으로 초기화됩니다.
  • 잘못된 connection-string을 제공하면 명확한 오류 메시지가 표시됩니다.

4. FTP 어댑터

Properties 방식

properties
# FTP 서버 설정
firo.adapters.ftp.host=ftp.example.com
firo.adapters.ftp.port=21
firo.adapters.ftp.username=ftpuser
firo.adapters.ftp.password=ftppassword
firo.adapters.ftp.passive-mode=true
firo.adapters.ftp.directory.base-dir=/uploads/
firo.adapters.ftp.directory.tmp-dir=/uploads/temp/
firo.adapters.ftp.directory.separator=/

YAML 방식

yaml
firo:
  adapters:
    ftp:
      host: ftp.example.com
      port: 21
      username: ftpuser
      password: ftppassword
      passive-mode: true
      directory:
        base-dir: /uploads/
        tmp-dir: /uploads/temp/
        separator: /

5. SFTP 어댑터

Properties 방식

properties
# SFTP 서버 설정
firo.adapters.sftp.host=sftp.example.com
firo.adapters.sftp.port=22
firo.adapters.sftp.username=sftpuser
firo.adapters.sftp.password=sftppassword
firo.adapters.sftp.private-key=/path/to/private/key
firo.adapters.sftp.known-hosts=/path/to/known_hosts
firo.adapters.sftp.directory.base-dir=/uploads/
firo.adapters.sftp.directory.tmp-dir=/uploads/temp/

YAML 방식

yaml
firo:
  adapters:
    sftp:
      host: sftp.example.com
      port: 22
      username: sftpuser
      password: sftppassword
      private-key: /path/to/private/key
      known-hosts: /path/to/known_hosts
      directory:
        base-dir: /uploads/
        tmp-dir: /uploads/temp/

이미지 필터 설정

전역 필터 설정

properties
# EXIF 정보를 읽어 이미지 자동 회전
firo.filters.auto-fix-orientation.enabled=true

# 이미지 리사이징 설정
firo.filters.resize.enabled=true
firo.filters.resize.max-width=1920
firo.filters.resize.max-height=1080
firo.filters.resize.quality=0.8

# 최대 파일 크기 제한 (바이트)
firo.filters.max-size.enabled=true
firo.filters.max-size.image-max-size=10485760  # 10MB
firo.filters.max-size.document-max-size=52428800  # 50MB

# 확장자 제한
firo.filters.extension.enabled=true
firo.filters.extension.allowed-extensions=jpg,jpeg,png,gif,pdf,doc,docx,xls,xlsx

# 고정 차원 검증
firo.filters.fixed-dimension.enabled=false
firo.filters.fixed-dimension.width=200
firo.filters.fixed-dimension.height=200

Java Configuration으로 필터 설정

java
@Configuration
public class FiroFilterConfiguration {
    
    @Bean
    public FiroFilterRegistry firoFilterRegistry() {
        FiroFilterRegistry registry = new FiroFilterRegistry();
        
        // 이미지 필터 체인
        FiroFilterChain imageFilterChain = FiroFilterChain.builder()
            .add(new FileSizeExceptionFilter(10 * 1024 * 1024))  // 10MB
            .add(new FileExtensionExceptionFilter(Set.of("jpg", "jpeg", "png", "gif")))
            .add(new AutoFixOrientationImageFilter())
            .add(new ResizeImageFilter(1920, 1080))
            .build();
            
        // 문서 필터 체인  
        FiroFilterChain documentFilterChain = FiroFilterChain.builder()
            .add(new FileSizeExceptionFilter(50 * 1024 * 1024))  // 50MB
            .add(new FileExtensionExceptionFilter(Set.of("pdf", "doc", "docx", "xls", "xlsx")))
            .build();
            
        registry.register("image", imageFilterChain);
        registry.register("document", documentFilterChain);
        
        return registry;
    }
}

도메인/카테고리별 설정

Java Configuration 예시

java
@Configuration
public class FiroConfigurationExample {
    
    @PostConstruct
    public void configureFiroDomains() {
        // 사용자 프로필 이미지 도메인
        FiroDomain userProfileDomain = FiroDomain.builder("user-profile")
            .adapter(FiroRegistry.getAdapter(AdapterType.S3))
            .directoryPathPolicy(new DateDirectoryPathPolicy(
                DateDirectoryPathPolicy.DATE_SUBDIR_TYPE.YYYY_MM,
                "/user-profiles/",
                "/temp/"
            ))
            .build();
            
        // 프로필 이미지 카테고리 (리사이즈 필터 적용)
        FiroCategory avatarCategory = FiroCategory.builder(userProfileDomain, "avatar")
            .filterChain(FiroFilterChain.builder()
                .add(new AutoFixOrientationImageFilter())
                .add(new ResizeImageFilter(200, 200))
                .build())
            .keepExt(true)
            .build();
            
        userProfileDomain.addCategory(avatarCategory);
        FiroRegistry.add(userProfileDomain);
        
        // 게시글 첨부파일 도메인
        FiroDomain postAttachmentDomain = FiroDomain.builder("post-attachment")
            .adapter(FiroRegistry.getAdapter(AdapterType.LOCAL))
            .build();
            
        FiroCategory documentCategory = FiroCategory.builder(postAttachmentDomain, "document")
            .filterChain(FiroFilterChain.builder()
                .add(new MaxSizeExceptionFilter(50 * 1024 * 1024)) // 50MB
                .build())
            .build();
            
        postAttachmentDomain.addCategory(documentCategory);
        FiroRegistry.add(postAttachmentDomain);
    }
}

환경별 설정

개발 환경 (application-dev.properties)

Properties 방식

properties
# Firo 기본 설정
firo.enabled=true
firo.db.type=jpa

# 개발 환경에서는 Local 어댑터 사용
firo.directory.base-dir=./uploads/
firo.directory.tmp-dir=./uploads/temp/
firo.api-prefix=/api/firo

# 디버깅을 위한 로깅
logging.level.com.unvus.firo=DEBUG
logging.level.org.springframework.web.multipart=DEBUG

YAML 방식 (application-dev.yml)

yaml
firo:
  enabled: true
  db:
    type: jpa
  directory:
    base-dir: ./uploads/
    tmp-dir: ./uploads/temp/

logging:
  level:
    com.unvus.firo: DEBUG
    org.springframework.web.multipart: DEBUG

테스트 환경 (application-test.properties)

properties
# Firo 테스트 설정
firo.enabled=true
firo.db.type=jpa

# 테스트용 H2 인메모리 DB
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.hibernate.ddl-auto=create-drop

# 테스트용 임시 디렉토리
firo.directory.base-dir=/tmp/test-uploads/
firo.directory.tmp-dir=/tmp/test-uploads/temp/

프로덕션 환경 (application-prod.properties)

properties
# Firo 프로덕션 설정
firo.enabled=true
firo.db.type=mybatis

# 프로덕션에서는 S3 사용
firo.s3.access-key=${AWS_ACCESS_KEY_ID}
firo.s3.secret-key=${AWS_SECRET_ACCESS_KEY}
firo.s3.bucket=${S3_BUCKET_NAME}
firo.s3.region=${AWS_REGION}

# 보안을 위한 로깅 레벨 조정
logging.level.com.unvus.firo=INFO
logging.level.org.springframework.web.multipart=WARN

iflex 통합 환경 (application-iflex.properties)

properties
# iflex와 함께 사용 시 권장 설정
firo.enabled=true
firo.db.type=mybatis  # iflex는 MyBatis 사용

# iflex 테이블 프리픽스와 맞춤
firo.database.table-prefix=

# MyBatis Type Alias 충돌 방지 (자동 처리됨)
# MyBatis 로깅 (필요시)
logging.level.com.unvus.firo.mybatis.mapper=DEBUG

# 필터 체인 전역 설정
firo.filters.auto-fix-orientation.enabled=true
firo.filters.resize.enabled=true
firo.filters.max-size.enabled=true

보안 설정

CORS 설정 (파일 업로드 API용)

java
@Configuration
public class CorsConfiguration {
    
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOriginPatterns(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/api/firo/**", configuration);
        return source;
    }
}

파일 타입 제한

java
@Component
public class FileTypeValidator {
    
    private static final Set<String> ALLOWED_IMAGE_TYPES = Set.of(
        "image/jpeg", "image/png", "image/gif", "image/webp"
    );
    
    private static final Set<String> ALLOWED_DOCUMENT_TYPES = Set.of(
        "application/pdf", "text/plain", 
        "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
    );
    
    public boolean isValidFileType(String contentType, String category) {
        if ("image".equals(category)) {
            return ALLOWED_IMAGE_TYPES.contains(contentType);
        } else if ("document".equals(category)) {
            return ALLOWED_DOCUMENT_TYPES.contains(contentType);
        }
        return false;
    }
}

문제 해결

설정 중 문제가 발생하면 트러블슈팅 가이드를 참고하세요.

주요 해결 방법:

  • Azure/S3 초기화 실패: connection-string이나 access-key 설정 확인
  • MyBatis Type Alias 충돌: Firo는 자동으로 충돌을 방지합니다
  • 파일 업로드 권한 오류: 디렉토리 권한 및 존재 여부 확인