Backend

openApi 활용(4) : servlet redirection, GeoLocation, 버튼 구현

openDeveloper 2023. 4. 17. 02:00

지난 글에서 java 코드로 DB 연결을 성공하였고, 이번 글에서는 web application에서 DB에 접근하고, 가까운 거리 순으로 wifi 위치를 표시하기 위해서 client의 공인 ip를 확인하고, ip 기반으로 GeoLocatin api를 사용해 위도,경도로 변경하여 저장하였다.

 

 

openApi 활용(3) DB 연동하기

지난 글에서 Gson 라이브러리를 사용해 get 호출로 받은 Json 데이터를 파싱하여 객체에 저장하였다. 이번 글에서는 MariaDB를 사용하여 java에서 객체를 데이터베이스를 저장한다. 1. DB 시스템 구성(Ma

myu7769.tistory.com

 

리다이렉션으로 DB에 저장하기

 

jsp 파일에서 servlet 리다이렉션을 하여 init() 단계에서 전체 wifi 객체 를 get api로 가져와 DB에 저장한다.

<a href="load-wifi"> api 호출 후 저장 </a>
@WebServlet(name = "loadWifiServlet", value = "/load-wifi")  //loadOnStartup = 1
//

public class loadWifi extends HttpServlet {
    private String message;

    public void init() {
        getController getController = new getController();
        int wifiAllCnt = getController.getAllWifi();
        message = wifiAllCnt +"";
    }

servlet의 생명 주기는 아래와 같은 순서로 이루어진다.

 

https://victorydntmd.tistory.com/154

1. 요청이 오면, Servlet 클래스가 로딩되어 요청에 대한 Servlet 객체가 생성됩니다.
2. 서버는 init() 메소드를 호출해서 Servlet을  초기화 합니다.
3. service() 메소드를 호출해서 Servlet이 브라우저의 요청을 처리하도록 합니다.
4. service() 메소드는 특정 HTTP 요청(GET, POST 등)을 처리하는 메서드 (doGet(), doPost() 등)를 호출합니다.
5. 서버는 destroy() 메소드를 호출하여 Servlet을 제거합니다.

 

톰캣은 Servlet을 다음과 같이 관리하고 있습니다.

 Servlet 객체를 생성하고 초기화하는 작업은 비용이 많은 작업이므로, 다음에 또 요청이 올 때를 대비하여 이미 생성된 Servlet 객체는 메모리에 남겨둡니다. 또 톰캣이 종료되기 전이나 reload 전에 모든 Servlet을 제거하게 됩니다. 이렇게 톰캣은 자원을 아끼면서 Servlet을 사용하고 있습니다. 개발자인 우리들도 자원을 효과적으로 사용하기 위해서 노력을 기울여야 합니다.

이에 대한 방법으로 초기화하는데 호출되는 init() 메서드를 활용합니다.

즉, 요청이 매 번 똑같은 로직을 거쳐서 똑같은 결과를 산출하는 작업은 딱 한 번만 수행 되도록 init() 에서 처리하는 것입니다. 또한, servlet에 아무런 옵션을 주지 않으면 리다이렉션을 진행할 때 servlet init() 함수가 실행되지만, LoadOnstartUp 옵션을 주게 되면 web application이 구동될 때 init() 실행하여 page 반응 속도를 높일 수 있다.

(servlet이 초기화 된 후에는 servlet을 다시 열 때에는 init() 진행하지 않음)

 

init()

 - 한 번만 수행됨
 - 클라이언트(browser)의 요청에 따라 적절한 Servlet이 생성되고 이 Servlet이 메모리에 로드될 때 init() 메서드가 호출
 - 역할 : Servlet 객체를 초기화  

service(request, response)

 - 응답에 대한 모든 내용은 service() 메서드에 구현해야 함
 - Servlet이 수신한 모든 request에 대해 service() 메서드가 호출됨
  - HttpServlet을 상속받은 Servlet 클래스 (이하 하위 클래스) 에서 service() 메서드를 오버라이드 하지 않았다면,
  그 부모인 HttpServlet의 service()가 호출됨
- service() 메서드는 request의 type(HTTP Method : GET, POST, PUT, DELETE 등)에 따라 적절한 메서드
 (doGet, doPost, doPut, doDelete 등)를 호출함
- 즉, 하위 클래스에서 doGet, doPost 등의 메서드를 오버라이드 해두면 HttpServlet의 service() 메서드가 요청에
맞는 메서드(하위 클래스에서 오버라이드한 메서드)를 알아서 호출할 수 있게 되는 것
 - 메서드가 return 하면 해당 thread는 제거됨
 
destory()

 - 한 번만 수행됨
 - Web Application이 갱신되거나 WAS가 종료될 때 호출됨
 - 역할 : Servlet 객체를 메모리에서 제거 

HttpServletRequest request 객체

 - 사용자가 HTML Form에 입력한 내용(username과 password)을 request 객체에서 받아온다.
   즉, HTTP 프로토콜의 Request 정보를 Servlet에게 전달
 - 헤더 정보, 파라미터, 쿠키, URI, URL, Body의 Stream 등을 읽어 들이는 메서드가 있다.
 - getHeader(“원하는 헤더 이름”) : 이 메서드를 통해 원하는 헤더 정보를 확인할 수 있다.
 - getParameter() : 이 메서드를 호출하여 form parameter 값을 가져온다.
   이런 parameter 값은 URL 또는 form의 input tag를 통해서 넘어올 수 있다.
 - getParameterValues()
    form parameter가 두 번 이상 나타나고 여러 개의 값을 반환할 때 이 메서드를 호출한다. (Ex. checkbox)

HttpServletResponse response 객체


 - 인자의 내용에 맞게 동적인 HTML 코드를 생성하여 response 객체에 담아 반환한다.
 - getWriter() 메서드를 호출하여 PrintWriter 객체을 가져온 후 해당 객체에서 print, println 메서드를 실행한다.
 - 즉, form data를 처리한 결과를 Web Page에 생성(view 생성)하여 반환한다.

 

출처 : https://victorydntmd.tistory.com/154

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("text/html;charset=UTF-8");

    PrintWriter out = response.getWriter();
    out.print("<html><head><title>Query 문자열 테스트</title></head>");
    out.println("<body>");
    out.println("<h1>" + message + "개의 Wifi 정보를 정상적으로 저장하였습니다. </h1>");
    out.println("</body></html>");
    out.println("<a href=\"index.jsp\">홈 으로 가기</a>");
    out.close();
}

 

GeoLocation

 

 GeoLocation은 사용자 IP 기반 위치 정보를 제공하는 국내 유일의 서비스입니다. 이 서비스를 이용하여 사용자의 위치 및 지역 기반 콘텐츠 개인화, 광고 타겟팅, 트래픽 분석, DRM 관리, 어뷰징/ Fraud 탐지 등을 할 수 있습니다. GeoLocation 서비스는 네이버 클라우드 플랫폼에서 제공하는 API 서비스로, 아래 그림처럼 고객 서버에서 질의한 IP 주소에 대하여 지역 정보 DB(GeoLocation DB)를 검색하여 해당 지역의 정보를 고객 서버로 전달합니다. 이때 제공되는 정보에는 국가, 시/군/구, 동, 인근 지역의 좌표, 통신사 정보 등입니다. IP 주소별 위치 정보는 매일 수시로 갱신되며 항상 최신 정보를 반영할 수 있도록 유지되고 있습니다.

 

 client에 IP에 따라 위치 정보를 받아 오고 싶어, Naver GeoLocation api를 사용하였다. 월별 최대 호출 건수를 임의로 선택 할수도 쿼리 요청 횟수도 그래프로 볼 수 있어 좋은 듯하다.

 

 

NAVER CLOUD PLATFORM

cloud computing services for corporations, IaaS, PaaS, SaaS, with Global region and Security Technology Certification

www.ncloud.com

 

 

GeoLocation 개요

 

api.ncloud-docs.com

 실제 사용하기 위해서는 로그인 후 계정 관리 > 인증키 관리에서 Access key ID와 Secret Key를 생성한 후 get 요청을 날려야 한다.  아래는 네이버에서 공개한 샘플 pdf이고, 네이버 페이지에는 예제가 다운로드 안되지만 pdf 내에 예제 파일 링크가 존재한다. 

 

geoLocation.pdf
0.10MB

public class Geocoding {

    public Location getLocation() {

        String ip = new ipSearch().getIpAddress(); // 공인 IP 입력
        ApiKeys apikeys = new ApiKeys();
        ApiClient apiClient = new ApiClient(apikeys.getAccessKey(), apikeys.getSecretKey());
        String response = "";
        String objectLat;
        String objectLnt;

        try {
            response = apiClient.run(ip);
            JsonParser jsonParser = new JsonParser();
            JsonObject object = (JsonObject) jsonParser.parse(response);
            object = (JsonObject)object.get("geoLocation");
            objectLat = object.get("lat").getAsString();
            objectLnt = object.get("long").getAsString();

            return new Location(objectLat, objectLnt);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


    }
}

 

샘플 코드를 기반으로 코드를 조금 수정하여 ip별 위도, 경도를  return 하도록 구현하였다.

 

jsp 파일에서 button 클릭 시 태그 값 변화시키기

 

 p 태그, value 0.0으로 초기화되어 있는 값을 버튼 클릭 시 IP를 받아와 값 변화를 해주는 것을 목표로 이것 저것 찾아보았지만, 제대로 구현되지 않았다. <script> 태그 내에서 <% %> 로 감싸 java 코드로 구현하여 값을 넣으려고 했는데, <% %> 서버에서 실행되는 코드로 서버 내에서 값을 생성해 jsp 파일에 쓰려고 하니 할당된 변수를 jsp 파일에서 명시할 수가 없었다. (jsp파일은 클라이언트에서 돌아 그런 듯하다)

 

따라서 버튼 클릭 시 getLocation.jsp를 구현하고 호출될 때 json으로 값을 리턴하는 방식으로 값을 전달하였다.

 

<script>
    function myLocation() {

        $.ajax({
            url: "getLocation.jsp",
            type: "GET",
            dataType: "json",
            success: function(data) {
                // alert(data.lat);
                // alert(data.lnt);
                // $("#LAT").text(data.lat);
                // $("#LNT").text(data.lnt);
                document.getElementById("LAT").value = data.lat;
                document.getElementById("LNT").value = data.lnt;
            },
            error: function(xhr, status, error) {
                console.log("Error: " + error);
            }
        });
    }
</script>

 id가 "LAT", "LNT"인 p 태그의 값을 변경시켜줌.

 

<p>LAT: <input type="Text" id="LAT" value="0.0"  size="15"> LNT: </p> <input type="Text" id="LNT" value="0.0" size="15">

getLocation.jsp은 java 코드로 구현하였으며, 아래와 같다.

<%@ page import="Location.*" %>

<%
  Geocoding geocoding = new Geocoding();
  Location location = geocoding.getLocation();
  String lat = location.getLat();
  String lnt = location.getLnt();

  String jsonData = "{\"lat\": \"" + lat + "\", \"lnt\": \"" + lnt + "\"}";
  response.setContentType("application/json; charset=UTF-8");
  response.getWriter().print(jsonData);
%>

 

다음 진행으로는 위도,경도에 따라 거리를 계산해 거리가 가까운 순으로 위도,경도를 구현해봐야겠다.

 

궁금점 :

client의 위도, 경도에 따라 가까운 거리에 따라 표현하는 법이 모든 DB 테이블을 보고 O(n)으로 구현해야하나 의문이 든다.

'Backend' 카테고리의 다른 글

SOLID : 객체 지향 설계 5원칙  (0) 2023.05.12
openApi 활용(3) DB 연동하기  (0) 2023.04.16
openApi 활용(2) : gson  (0) 2023.04.11
openApi 활용(1) : okhttp3 사용해보기  (0) 2023.04.11