Spring Boot 위치 기반 기능 구현

wellbeing-dough·2023년 9월 4일
0

1. 요구사항

  1. 유저가 확대한 범위의 좌측상단/우측하단 위도, 경도를 프론트에게 받는다
  2. 좌측 상단 범위와 우측 하단 사이에 있는 데이터를 전부 프론트에게 보내준다

2. 해야 할 것

  • 엑셀에 있는 데이터의 위치값을 이용해서 위도 경도 값을 입력한다
  • 그 위도 경도 값이 들어간 엑셀 데이터를 DB에 넣는다
  • 요구사항을 구현한다

3. 엑셀에 있는 데이터의 위치값을 이용해서 위도 경도 값을 입력

public class AddressResolver {

    private static final String KAKAO_API_URL = "https://dapi.kakao.com/v2/local/search/address.json?query=";
    private static final String API_KEY = "";

    private List<AddressData> addressDataList;
    private int rowIndex;

    public AddressResolver(String excelFilePath) {
        this.addressDataList = new ArrayList<>();
        this.rowIndex = 0;
        loadAddressData(excelFilePath);
    }

    public void resolveAddresses() {
        for (AddressData addressData : addressDataList) {
            try {
                resolveAddress(addressData);
                Thread.sleep(200);
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void resolveAddress(AddressData addressData) throws IOException {
        String keyword = URLEncoder.encode(addressData.getAddress(), "UTF-8");
        String apiUrl = KAKAO_API_URL + keyword;

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(apiUrl);
            httpGet.addHeader("Authorization", "KakaoAK " + API_KEY);

            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                HttpEntity entity = response.getEntity();
                String responseBody = EntityUtils.toString(entity);

                JsonObject jsonObject = JsonParser.parseString(responseBody).getAsJsonObject();
                JsonArray documents = jsonObject.getAsJsonArray("documents");

                if (documents.size() > 0) {
                    JsonObject document = documents.get(0).getAsJsonObject();
                    double latitude = document.get("y").getAsDouble();
                    double longitude = document.get("x").getAsDouble();
                    addressData.setLatitude(latitude);
                    addressData.setLongitude(longitude);
                } else {
                    addressData.setLatitude(0);
                    addressData.setLongitude(0);
                }
            }
        }
    }

    public void saveAddressData(String excelFilePath) throws IOException {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet();

            for (AddressData addressData : addressDataList) {
                Row row = sheet.createRow(rowIndex);
                row.createCell(0).setCellValue(addressData.getAddress());
                row.createCell(1).setCellValue(addressData.getLatitude());
                row.createCell(2).setCellValue(addressData.getLongitude());
                rowIndex++;
            }

            try (FileOutputStream outputStream = new FileOutputStream(excelFilePath)) {
                workbook.write(outputStream);
                System.out.println("주소 데이터가 엑셀에 저장되었습니다!");
            }
        }
    }

    private void loadAddressData(String excelFilePath) {
        try (Workbook workbook = new XSSFWorkbook(new FileInputStream(excelFilePath))) {
            Sheet sheet = workbook.getSheetAt(0);

            while (true) {
                Row row = sheet.getRow(rowIndex);
                if (row == null) {
                    break;
                }

                Cell cell = row.getCell(0);
                if (cell != null) {
                    String address = cell.getStringCellValue();
                    addressDataList.add(new AddressData(address));
                }

                rowIndex++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        String inputExcelFilePath = "src/main/resources/전통주_데이터.xlsx";
        String outputExcelFilePath = "src/main/resources/전통주_데이터_카카오.xlsx";

        AddressResolver addressResolver = new AddressResolver(inputExcelFilePath);
        addressResolver.resolveAddresses();
        try {
            addressResolver.saveAddressData(outputExcelFilePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class AddressData {
    private String address;
    private double latitude;
    private double longitude;

    public AddressData(String address) {
        this.address = address;
    }

    public String getAddress() {
        return address;
    }

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
        this.longitude = longitude;
    }
}

간단하게 기능만 구현될 수 있게 작성했다 카카오 지도 api를 사용해서 위치 데이터를 기반으로 위도 경도 값을 받아올 수 있다
엑셀 데이터를 사용해서 엑셀에 있는 위치 데이터를 카카오 지도 api에 보낼 수 있게 했고 거기서 생긴 위도 경도 값을 다시 엑셀에 넣어 주었다

4. 기능 구현

Controller

    @Operation(summary = "전통주 지도 조회", description = "요청시 쿼리 파라미터로 좌측상단 좌표, 우측상단 좌표 보내주세요")
    @GetMapping("/map")
    public ResponseEntity<Slice<GetMapInDrinksResponse>> getMapInDrinks(@RequestParam Double startX, @RequestParam Double startY, @RequestParam Double endX, @RequestParam Double endY, @RequestParam int page, @RequestParam int size) {
        Slice<GetMapInDrinksResponse> drinks = drinkService.getMapInDrinks(startX, startY, endX, endY, page, size);
        return new ResponseEntity(drinks, HttpStatus.OK);
    }

페이지네이션을 위해 page, size를 받았다

Service

    public Slice<GetMapInDrinksResponse> getMapInDrinks(Double startX, Double startY, Double endX, Double endY, int page, int size) {
        PageRequest pageRequest = PageRequest.of(page, size);
        Slice<MapInDrinkData> drinkData = drinkRepository.findDrinksByCoordinate(pageRequest, startX, startY, endX, endY);
        return new SliceImpl<>(getGetMapInDrinksResponses(drinkData), drinkData.getPageable(), drinkData.hasNext());

    }

Repository

    @Query("SELECT new co.kr.jurumarble.drink.domain.dto.MapInDrinkData(d.id, d.name, d.region, d.latitude, d.longitude) FROM Drink d " +
            "WHERE (d.latitude BETWEEN :startX AND :endX AND d.longitude BETWEEN :startY AND :endY) " +
            "ORDER BY d.name")
    Slice<MapInDrinkData> findDrinksByCoordinate(PageRequest pageRequest, @Param("startX") Double startX, @Param("startY") Double startY, @Param("endX") Double endX, @Param("endY") Double endY);

0개의 댓글

관련 채용 정보