ITN Dev 07-22
feat: 시트 업로드 시드 서비스 추가
@fb32720244f1c6b49b3be1225e83d024c456b55a
 
src/main/java/kr/itn/itnhub/seed/SeedReport.java (added)
+++ src/main/java/kr/itn/itnhub/seed/SeedReport.java
@@ -0,0 +1,4 @@
+package kr.itn.itnhub.seed;
+
+public record SeedReport(int created, int updated, int total) {
+}
 
src/main/java/kr/itn/itnhub/seed/SeedService.java (added)
+++ src/main/java/kr/itn/itnhub/seed/SeedService.java
@@ -0,0 +1,64 @@
+package kr.itn.itnhub.seed;
+
+import kr.itn.itnhub.org.Organization;
+import kr.itn.itnhub.org.OrganizationMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Service
+public class SeedService {
+
+    private final SeedParser parser;
+    private final OrganizationMapper mapper;
+
+    public SeedService(SeedParser parser, OrganizationMapper mapper) {
+        this.parser = parser;
+        this.mapper = mapper;
+    }
+
+    @Transactional
+    public SeedReport seed(InputStream xlsx) {
+        List<SeedRow> rows = parser.parse(xlsx);
+
+        Set<String> before = new HashSet<>();
+        for (Organization existing : mapper.findAll()) {
+            before.add(key(existing.getOrgNo(), existing.getOrgName()));
+        }
+
+        int created = 0;
+        int updated = 0;
+
+        for (SeedRow row : rows) {
+            if (before.contains(key(row.orgNo(), row.orgName()))) {
+                updated++;
+            } else {
+                created++;
+            }
+            mapper.upsertBySeed(toOrganization(row));
+        }
+
+        return new SeedReport(created, updated, rows.size());
+    }
+
+    private String key(String orgNo, String orgName) {
+        return orgNo + " " + orgName;
+    }
+
+    private Organization toOrganization(SeedRow row) {
+        Organization org = new Organization();
+        org.setOrgNo(row.orgNo());
+        org.setOrgName(row.orgName());
+        org.setChannelSlug(row.channelSlug());
+        org.setDeptName(row.deptName());
+        org.setManagerName(row.managerName());
+        org.setManagerTitle(row.managerTitle());
+        org.setManagerPhone(row.managerPhone());
+        org.setManagerEmail(row.managerEmail());
+        return org;
+    }
+}
 
src/test/java/kr/itn/itnhub/seed/SeedServiceTest.java (added)
+++ src/test/java/kr/itn/itnhub/seed/SeedServiceTest.java
@@ -0,0 +1,117 @@
+package kr.itn.itnhub.seed;
+
+import kr.itn.itnhub.AbstractDbTest;
+import kr.itn.itnhub.org.OrgStatus;
+import kr.itn.itnhub.org.Organization;
+import kr.itn.itnhub.org.OrganizationMapper;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class SeedServiceTest extends AbstractDbTest {
+
+    @Autowired
+    SeedService seedService;
+
+    @Autowired
+    OrganizationMapper mapper;
+
+    @Autowired
+    JdbcTemplate jdbc;
+
+    @BeforeEach
+    void clean() {
+        jdbc.update("delete from organization");
+    }
+
+    private byte[] workbook(String[]... dataRows) throws Exception {
+        try (XSSFWorkbook wb = new XSSFWorkbook();
+             ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+
+            Sheet sheet = wb.createSheet(SeedParser.SHEET_NAME);
+            sheet.createRow(0);
+            sheet.createRow(1);
+
+            int rowNum = 2;
+            for (String[] data : dataRows) {
+                Row row = sheet.createRow(rowNum++);
+                row.createCell(1).setCellValue(data[0]);
+                row.createCell(2).setCellValue(data[1]);
+                row.createCell(5).setCellValue(data[2]);
+                if (data[3] != null) row.createCell(6).setCellValue(data[3]);
+                if (data[4] != null) row.createCell(7).setCellValue(data[4]);
+                if (data[5] != null) row.createCell(8).setCellValue(data[5]);
+                if (data[6] != null) row.createCell(9).setCellValue(data[6]);
+                if (data[7] != null) row.createCell(10).setCellValue(data[7]);
+            }
+            wb.write(out);
+            return out.toByteArray();
+        }
+    }
+
+    @Test
+    void 최초_시드는_전부_신규다() throws Exception {
+        byte[] xlsx = workbook(
+                new String[]{"001", "00", "국제방송교류재단", "팀", "송민지", "과장", "02-1", "a@b.kr"},
+                new String[]{"002", "00", "세종학당재단", "팀", "권유나", "6급", "02-2", "c@d.kr"});
+
+        SeedReport report = seedService.seed(new ByteArrayInputStream(xlsx));
+
+        assertThat(report.created()).isEqualTo(2);
+        assertThat(report.updated()).isZero();
+        assertThat(report.total()).isEqualTo(2);
+        assertThat(mapper.findAll()).hasSize(2);
+    }
+
+    @Test
+    void 같은_파일을_다시_올려도_행이_늘지_않는다() throws Exception {
+        byte[] xlsx = workbook(
+                new String[]{"001", "00", "국제방송교류재단", "팀", "송민지", "과장", "02-1", "a@b.kr"});
+
+        seedService.seed(new ByteArrayInputStream(xlsx));
+        SeedReport second = seedService.seed(new ByteArrayInputStream(xlsx));
+
+        assertThat(second.created()).isZero();
+        assertThat(second.updated()).isEqualTo(1);
+        assertThat(mapper.findAll()).hasSize(1);
+    }
+
+    @Test
+    void 재시드는_이미_만든_채널ID를_보존한다() throws Exception {
+        byte[] xlsx = workbook(
+                new String[]{"001", "00", "국제방송교류재단", "팀", "송민지", "과장", "02-1", "a@b.kr"});
+
+        seedService.seed(new ByteArrayInputStream(xlsx));
+        Long id = mapper.findAll().get(0).getId();
+        mapper.updateChannelIdMj(id, "chan-mj");
+        mapper.updateChannelIdLaw(id, "chan-law");
+
+        seedService.seed(new ByteArrayInputStream(xlsx));
+
+        assertThat(mapper.findById(id).getStatus()).isEqualTo(OrgStatus.ACTIVE);
+    }
+
+    @Test
+    void 담당자정보가_없는_기관은_정보대기로_들어온다() throws Exception {
+        byte[] xlsx = workbook(
+                new String[]{"008", "00", "경찰청", "데이터정책계", "박진우", "경위", "02-3", "e@f.kr"},
+                new String[]{"008", "01", "경찰청_치안정책연구소", null, null, null, null, null});
+
+        seedService.seed(new ByteArrayInputStream(xlsx));
+
+        List<Organization> all = mapper.findAll();
+        assertThat(all).hasSize(2);
+        assertThat(all).extracting(Organization::getStatus)
+                .containsExactly(OrgStatus.READY, OrgStatus.INFO_PENDING);
+    }
+}
Add a comment
List