Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.9'
implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.4.4'
implementation 'com.opencsv:opencsv:5.11.2'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.threestar.trainus.domain.lesson.admin.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.threestar.trainus.domain.lesson.admin.service.LocationCsvService;

import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/location")
public class LocationCsvController {

private final LocationCsvService locationCsvService;

// 업로드 api
@PostMapping("/upload-location")
@Operation(summary = "법정동명 csv파일 업로드 api", description = "현재 쓰이는 열만 필터링하여 업로드")
public ResponseEntity<String> uploadCsv(@RequestParam("file") MultipartFile file) {
locationCsvService.processCsv(file);
return ResponseEntity.ok("법정동 업로드 완료");
}

// 검증용 api
@GetMapping("/exists")
@Operation(summary = "법정동명 검증 api", description = "")
public ResponseEntity<Boolean> checkExists(
@RequestParam String city,
@RequestParam String district,
@RequestParam String dong,
@RequestParam(required = false) String ri
) {
boolean exists = locationCsvService.checkLocation(city, district, dong, ri);
return ResponseEntity.ok(exists);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.threestar.trainus.domain.lesson.admin.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "location")
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Location {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String city; // 시도명
private String district; // 시군구명
private String dong; // 읍면동명
private String ri; // 리명

public Location(String city, String district, String dong, String ri) {
this.city = city;
this.district = district;
this.dong = dong;
this.ri = ri;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.threestar.trainus.domain.lesson.admin.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.threestar.trainus.domain.lesson.admin.entity.Location;

public interface LocationRepository extends JpaRepository<Location, Long> {
boolean existsByCityAndDistrictAndDongAndRi(String city, String district, String dong, String ri);

boolean existsByCityAndDistrictAndDong(String city, String district, String dong);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.threestar.trainus.domain.lesson.admin.service;

import static com.threestar.trainus.global.exception.domain.ErrorCode.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvException;
import com.threestar.trainus.domain.lesson.admin.entity.Location;
import com.threestar.trainus.domain.lesson.admin.repository.LocationRepository;
import com.threestar.trainus.global.exception.handler.BusinessException;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class LocationCsvService {

private final LocationRepository locationRepository;

public void processCsv(MultipartFile file) {
List<Location> locations = new ArrayList<>();

try (Reader reader = new BufferedReader(new InputStreamReader(file.getInputStream()));
CSVReader csvReader = new CSVReaderBuilder(reader).withSkipLines(1).build()) {

String[] row;
while ((row = csvReader.readNext()) != null) {
String city = row[1].trim();
String district = row[2].trim();
String dong = row[3].trim();
String ri = row[4].trim();

// 동이 존재하는 경우에 저장
if (!city.isBlank() && !district.isBlank() && !dong.isBlank()) {
locations.add(new Location(city, district, dong, ri));
}
}

locationRepository.saveAll(locations);

} catch (IOException | CsvException e) {
throw new BusinessException(INTERNAL_SERVER_ERROR);
}
}

public boolean checkLocation(String city, String district, String dong, String ri) {
if (ri == null || ri.isBlank()) {
return locationRepository.existsByCityAndDistrictAndDong(city, district, dong);
} else {
return locationRepository.existsByCityAndDistrictAndDongAndRi(city, district, dong, ri);
}
}
}