[BACKEND]스프링 MVC 공공 Open API 연동 개발
주소정보누리집(도로명주소 안내시스템)
https://www.juso.go.kr/openIndexPage.do







https://business.juso.go.kr/addrlink/openApi/searchApi.do
검색API
본인인증 사용중인 휴대전화번호로 인증 인증하기 아이핀 인증 본인 명의 아이핀 계정으로 인증 인증하기
business.juso.go.kr
[Oracle11gDB 계정 생성]
1. 윈도우즈키 + r키 = cmd
2. C:\Users\starh>sqlplus system/System1234
SQL*Plus: Release 11.2.0.1.0 Production on 월 1월 10 19:23:38 2022
Copyright (c) 1982, 2010, Oracle. All rights reserved.
다음에 접속됨:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
3. SQL>drop user jsp_openapi cascade;
4. SQL>create user jsp_openapi identified by jsp_openapi;
5. SQL>grant connect, resource, dba to jsp_openapi;
6. SQL>conn jsp_openapi/jsp_openapi;
7. SQL>show user
8. SQL>create table jsp_address(
address_id number primary key,
basic_address varchar2(80) not null,
detail_address varchar2(50) not null
);
9. SQL> desc jsp_address;
10. SQL>create sequence idx_seq start with 0 minvalue 0;
11. SQL>select * from user_sequences;
-- select * from tab; 조회 시 휴지통 내용(삭제 내용) 지울때 활용함
12. SQL>purge recyclebin;
13. SQL>select * from jsp_address;
14. SQL> commit;
[Spring Legacy Project 개발환경 세팅]
15. SpringMVC 프로젝트를 다음과 같이 생성합니다.
1) 프로젝트명 = JAVA_Servlet_JSP_SpringMVC_OracleDB
2) top-level package 명 = cohttp://m.openapi.spring
3) STS(또는 Eclipse) 상단 File 클릭 - New - Spring Legacy Project 클릭 선택
- Project name: 필드란에 JAVA_Servlet_JSP_SpringMVC_OracleDB 입력하고,
중앙에 Templates: 에서 하단에 Spring MVC Project 클릭
- Next 버튼 클릭
- Enter a topLevelPackage 하단 필드 입력란에
cohttp://m.openapi.spring 입력 - 하단 Finish 버튼 클릭!
4) 빌드툴 = 메이븐 방식 pom.xml 파일 안에 다음과 같이 소스를 수정 처리함.
~~ 위에 생략 ~~
<java-version>1.8</java-version>
<org.springframework-version>5.0.7.RELEASE</org.springframework-version>
~~ 중간 생략 ~~
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
~~ 아래 생략 ~~
5) 프로젝트 클릭 선택 - Properties - Java Build Path - Libraries - Add Library
- Server Runtime 에서 Apache Tomcat v9.0 선택 추가 바랍니다.
6) 프로젝트 클릭 선택 - Properties - Project Facets에서 Java 버전을 1.8로 변경해 주고,
우측 상단 Runtimes에서 Apache Tomcat v9.0 선택 체크해 줌.
16. ojdbc6.jar 파일 삽입(예시)
C:\app\starh\product\11.2.0\dbhome_1\jdbc\lib 폴더에 있는
ojdbc6.jar 파일을 복사함.
17. webapp 폴더 안에 있는 WEB-INF 폴더 안에 - lib 폴더 안에
ojdbc6.jar 파일을 넣어줌.
18. JAVA_Servlet_JSP_SpringMVC_OracleDB 프로젝트 선택 - 마우스 우클릭 - properties
- Java Build Path 클릭 - Add Library... 클릭 - Web App Libraries 클릭해서 추가해줌.
Microsoft Windows [Version 10.0.19045.3570]
(c) Microsoft Corporation. All rights reserved.
C:\Users\guro-hi>sqlplus system/System1234
SQL*Plus: Release 11.2.0.1.0 Production on 월 11월 6 11:42:24 2023
Copyright (c) 1982, 2010, Oracle. All rights reserved.
다음에 접속됨:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> show user
USER은 "SYSTEM"입니다
SQL> drop user jsp_openapi cascade;
drop user jsp_openapi cascade
*
1행에 오류:
ORA-01918: 사용자 'JSP_OPENAPI'(이)가 존재하지 않습니다
SQL> create user jsp_openapi identified by jsp_openapi;
사용자가 생성되었습니다.
SQL> grant connect, resource, dba to jsp_openapi;
권한이 부여되었습니다.
SQL> conn jsp_openapi/jsp_openapi;
연결되었습니다.
SQL> show user
USER은 "JSP_OPENAPI"입니다
SQL> create table jsp_address(
2 address_id number primary key,
3 basic_address varchar2(80) not null,
4 detail_address varchar2(50) not null
5 );
테이블이 생성되었습니다.
SQL> desc jsp_address;
이름 널? 유형
----------------------------------------- -------- ----------------------------
ADDRESS_ID NOT NULL NUMBER
BASIC_ADDRESS NOT NULL VARCHAR2(80)
DETAIL_ADDRESS NOT NULL VARCHAR2(50)
SQL> create sequence idx_seq start with 0 minvalue 0;
시퀀스가 생성되었습니다.
SQL> select * from user_sequences;
SEQUENCE_NAME MIN_VALUE MAX_VALUE INCREMENT_BY C O CACHE_SIZE
------------------------------ ---------- ---------- ------------ - - ----------
LAST_NUMBER
-----------
IDX_SEQ 0 1.0000E+28 1 N N 20
0
SQL> purge recyclebin;
휴지통이 지워졌습니다.
SQL> select * from jsp_address;
선택된 레코드가 없습니다.
SQL> commit;
커밋이 완료되었습니다.
SQL>
sts 실행






properties 옵션 설정 하기!!

Spring Back_End 코딩
19. JAVA 및 웹 소스 코딩
1) src\main\java\com\openapi\spring 패키지 안에 common 패키지 생성 후 JDBCUtil.java 소스 코딩함
package cohttp://m.openapi.spring.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
// Oracle DB 연결 및 close() 처리 JDBC Utility 클래스 작성
public class JDBCUtil {
public static Connection getConnection() {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
return DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl",
"jsp_openapi", "jsp_openapi");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void close(PreparedStatement stmt, Connection conn) {
if (stmt != null) {
try {
if (!stmt.isClosed()) {
stmt.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
stmt = null;
}
}
if (conn != null) {
try {
if (!conn.isClosed()) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
public static void close(ResultSet rs, PreparedStatement stmt, Connection conn) {
if (rs != null) {
try {
if (!rs.isClosed()) {
rs.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
rs = null;
}
}
if (stmt != null) {
try {
if (!stmt.isClosed()) {
stmt.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
stmt = null;
}
}
if (conn != null) {
try {
if (!conn.isClosed()) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
public static void rollback(Connection conn) {
if(conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
}
}
}
}
2) src\main\webapp 폴더 안에 dbconnTest.jsp 소스 코딩함
<%@page import="cohttp://m.openapi.spring.common.JDBCUtil"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import = "java.sql.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- JDBCUtil 활용 OracleDB 연결 접속을 확인해 봅니다. -->
<%
try (Connection conn = JDBCUtil.getConnection()){
out.println("커넥션 연결 성공함");
} catch (SQLException e) {
out.println("커넥션 연결 실패함 : " + e.getMessage());
application.log("커넥션 연결 실패", e);
}
%>
</body>
</html>
3) dbconnTest.jsp 파일 클릭 선택 - 마우스 우클릭 - Run As - Run on Server 클릭
- 웹 주소창에 http://localhost:9007(사용포트입력바랍니다)/spring/dbconnTest.jsp 입력해서
"커넥션 연결 성공함" 메시지 확인함
4) src\main\java\com\openapi\spring 패키지 안에 address 패키지 생성 후 AddressVO.java 소스 코딩함
package cohttp://m.openapi.spring.address;
import java.util.Map;
// AddressVO 클래스 작성
public class AddressVO {
private String mainAddress; // 기본 주소 필드
private String subAddress; // 상세 주소 필드
public String getMainAddress() {
return mainAddress;
}
public String getSubAddress() {
return subAddress;
}
public void setMainAddress(String mainAddress) {
this.mainAddress = mainAddress;
}
public void setSubAddress(String subAddress) {
this.subAddress = subAddress;
}
// 기본 주소가 비어있는지 검증하는 메서드 작성
public void validateMain(Map<String, Boolean> errors) {
if(mainAddress == null || mainAddress.trim().isEmpty()) {
errors.put("main", Boolean.TRUE);
}
}
// 상세 주소가 비어있는지 검증하는 메서드 작성
public void validateSub(Map<String, Boolean> errors) {
if(subAddress == null || subAddress.trim().isEmpty()) {
errors.put("sub", Boolean.TRUE);
}
}
}
5) src\main\java\com\openapi\spring 패키지 안에 address 패키지 생성 후 AddressDAO.java 소스 코딩함
package cohttp://m.openapi.spring.address;
import java.sql.Connection;
import java.sql.PreparedStatement;
import cohttp://m.openapi.spring.common.JDBCUtil;
// OracleDB 연동 DAO(Data Access Object) AddressDAO 클래스 작성
public class AddressDAO {
private Connection conn = null;
private PreparedStatement stmt = null;
// PreparedStatement 활용 insert 처리 쿼리문 작성
// insert into jsp_address values(idx_seq.nextval, '서울시 행복한 아파트', '살기좋은 동 1004호');
private static final String INSERT_ADDRESS = "insert into jsp_address values(idx_seq.nextVal, ?, ?)";
// insertAddress 메서드 작성
public void insertAddress(AddressVO vo) {
try {
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(INSERT_ADDRESS);
stmt.setString(1, vo.getMainAddress());
stmt.setString(2, vo.getSubAddress());
stmt.executeUpdate();
} catch(Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.close(stmt, conn);
}
}
}
6) src\main\java\com\openapi\spring 패키지 안에 controller 패키지 생성 후 AddressController.java 소스 코딩함
package cohttp://m.openapi.spring.controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cohttp://m.openapi.spring.address.AddressDAO;
import cohttp://m.openapi.spring.address.AddressVO;
// 웹 URL을 /update.do 로 매핑 처리함 : 서블릿 파일로 HttpServlet 상속 AddressController 클래스 작성
@WebServlet("/update.do")
public class AddressController extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
private void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 인코딩 타입 설정
request.setCharacterEncoding("utf-8");
// 기본 주소와 상세 주소를 파라미터로 받은 뒤 변수에 대입해 줍니다.
String mainAddress = request.getParameter("mainAddress");
String subAddress = request.getParameter("subAddress");
// vo 객체 생성 후 위에서 받은 변수로 값을 set 처리합니다.
AddressVO vo = new AddressVO();
vo.setMainAddress(mainAddress);
vo.setSubAddress(subAddress);
// error에 관한 해쉬맵 생성 및 Attribute 설정을 처리합니다.
Map<String, Boolean> errors = new HashMap<>();
request.setAttribute("errors", errors);
// 검증 메서드를 호출합니다.
vo.validateMain(errors);
vo.validateSub(errors);
// DAO 객체 생성 후 insert 메서드를 실행 처리합니다.
AddressDAO addressDAO = new AddressDAO();
addressDAO.insertAddress(vo);
// 만약 errors에 값이 존재한다면!
if(!errors.isEmpty()) {
// 포워딩을 통해 초기화면으로 되돌리게 합니다.
// 포워드는 RequestDispatcher을 이용하여 응답으로 사용할 jsp 방식으로 넘기는 방식으로
// 실행속도가 빠르나 브라우저 입장에서는 URL이 바뀌지 않는 단점이 있습니다.
// 리다이렉트는 두번의 요청과 응답으로 처리되서 실행속도가 느리지만
// 클라이언트가 URL을 확인할 수 있는 장점이 있습니다.
// 1. 에러가 존재하여 초기화면을 돌리는 작업은 같은 페이지 내에서 일어나므로 포워드로 처리하고
request.getRequestDispatcher("index.jsp").forward(request, response);
}
// 2. 에러가 존재하지 않아 성공화면을 보여주는 작업은
// URL이 바뀔 필요가 있으므로 리다이렉트로 처리했습니다.
response.sendRedirect("success.jsp");
}
}

package com.openapi.spring.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
// Oracle DB 연결 및 close() 처리 JDBC Utility 클래스 작성
public class JDBCUtil {
public static Connection getConnection() {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
return DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl",
"jsp_openapi", "jsp_openapi");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void close(PreparedStatement stmt, Connection conn) {
if (stmt != null) {
try {
if (!stmt.isClosed()) {
stmt.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
stmt = null;
}
}
if (conn != null) {
try {
if (!conn.isClosed()) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
public static void close(ResultSet rs, PreparedStatement stmt, Connection conn) {
if (rs != null) {
try {
if (!rs.isClosed()) {
rs.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
rs = null;
}
}
if (stmt != null) {
try {
if (!stmt.isClosed()) {
stmt.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
stmt = null;
}
}
if (conn != null) {
try {
if (!conn.isClosed()) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
public static void rollback(Connection conn) {
if(conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
}
}
}
}










인터페이스 따로 만드는 대신에 구현클래스에 한번에 넣엇다


서블릿을 사용하면 관련된 메소드를 자동으로 만들어준다.



package com.openapi.spring.controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.openapi.spring.address.AddressDAO;
import com.openapi.spring.address.AddressVO;
//웹 URL을 /update.do 로 매핑 처리함 : 서블릿 파일로 HttpServlet 상속 AddressController 클래스 작성
@WebServlet("/update.do")
public class AddressController extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
process(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
process(request, response);
}
private void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{
// 인코딩 타입 설정
request.setCharacterEncoding("utf-8");
// 기본 주소와 상세 주소를 파라미터로 받은 뒤 변수에 대입해 줍니다.
String mainAddress = request.getParameter("mainAddress");
String subAddress = request.getParameter("subAddress");
// vo 객체 생성 후 위에서 받은 변수로 값을 set 처리합니다.
AddressVO vo = new AddressVO();
vo.setMainAddress(mainAddress);
vo.setSubAddress(subAddress);
// error에 관한 해쉬맵 생성 및 Attribute 설정을 처리합니다.
Map<String, Boolean> errors = new HashMap<String, Boolean>();
request.setAttribute("errors", errors);
// 검증 메소드를 호출합니다.
vo.validateMain(errors);
vo.validateSub(errors);
// DAO 객체 생성 후 insert 메소드를 실행 처리합니다.
AddressDAO addressDAO = new AddressDAO();
addressDAO.insertAddress(vo);
// 만약 errors에 값이 존재한다면
if(!errors.isEmpty()) {
// 포워딩을 통해 초기화면으로 되돌리게 합니다.
// 포워드는 RequestDispatcher을 이용하여 응답으로 사용할 jsp 방식으로 넘기는 방식으로
// 실행속도가 빠르나 브라우저 입장에서는 URL이 바뀌지 않는 단점이 있습니다.
// 리다이렉트는 두번의 요청과 응답으로 처리되서 실행속도가 느리지만
// 클라이언트가 URL을 확인할 수 있는 장점이 있습니다.
// 1. 에러가 존재하여 초기화면을 돌리는 작업은 같은 페이지 내에서 일어나므로 포워드로 처리하고
request.getRequestDispatcher("index.jsp").forward(request, response);
// 2. 에러가 존재하지 않아 성공화면을 보여주는 작업은
// URL이 바뀔 필요가 있으므로 리다이렉트로 처리했습니다.
response.sendRedirect("success.jsp");
}
}
}
7) src\main\webapp\resources 폴더 안에 css 폴더 만들고, bootstrap-3.3.2.min.css 파일 넣어줌.
그리고, js 폴더 만들고, jquery-3.5.1.min.js 파일 넣어줌.
8) src\main\webapp 폴더 안에 index.jsp 소스 코딩함
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>주소 입력</title>
<link rel="stylesheet" type="text/css" media="screen" href="resources/css/bootstrap-3.3.2.min.css">
<script type="text/javascript" src="resources/js/jquery-3.5.1.min.js"></script>
<script type="text/javascript">
// 도로명주소 - 주소검색 팝업을 호출합니다.
// https://business.juso.go.kr/addrlink/openApi/popupApi.do 웹사이트에서
// 하단 "주소입력화면 소스보기"를 클릭해서 참고합니다.
function fn_openAddressPopup() {
var url = "addressAPIPopup.jsp";
var name = "AddressPopup";
var option = "width=650, height=500, top=100, left=200, location=no"
window.open(url, name, option);
}
// 주소검색 팝업 호출 콜백 callback_openAddressPopup() 메서드 입니다.
function callback_openAddressPopup(aParam) {
document.getElementById("mainAddress").value = aParam["roadAddr"];
}
</script>
</head>
<body>
<h2>[처음화면]</h2>
<!-- update.do로 데이터 전송 -->
<form action="update.do" method="post">
<div class="input-group">
<span>기본 주소</span>
<br>
<input type="text" id="mainAddress" name="mainAddress" placeholder="주소를 선택하세요!"
readonly="readonly">
<!-- errors Map에 값이 해당하는 값이 있을 경우 메세지를 출력하는 부분 -->
<span>
<c:if test="${errors.main}">기본 주소를 입력하세요!</c:if>
</span>
<button type="button" onclick="javascript:fn_openAddressPopup();">주소 검색</button><br><br>
</div>
<div style="margin-top: 0px;">
<span>상세 주소</span>
<br>
<input type="text" id="subAddress" name="subAddress" placeholder="나머지 주소를 입력하세요! /">
<c:if test="${errors.sub}">상세 주소를 입력하세요!</c:if> <br>
</div> <br>
<input type="submit" value="주소 등록" />
<input type="reset" value="입력 취소" />
</form>
</body>
</html>
9) src\main\webapp 폴더 안에 addressAPIPopup.jsp 소스 코딩함
[중요 : addressAPIPopup.jsp 소스 안에 도로명주소 인증키 값을 입력해 줍니다]
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<link rel='stylesheet' type='text/css' media='screen' href='resources/css/bootstrap-3.3.2.min.css'>
<script src="resources/js/jquery-3.5.1.min.js"></script>
<script>
// https://business.juso.go.kr/addrlink/openApi/searchApi.do 웹사이트에서
// 하단 "웹 호출 소스 보기"에서 "JSON" 클릭해서 참고 합니다.
// 도로명 주소로 검색 api 연동을 ajax로 처리 합니다.
function fn_search(){
$.ajax({
url :"http://www.juso.go.kr/addrlink/addrLinkApiJsonp.do"
,type:"post"
,data:$("#searchForm").serialize()
,dataType:"jsonp"
,crossDomain:true
,success:function(jsonStr){
var errCode = jsonStr.results.common.errorCode;
var errDesc = jsonStr.results.common.errorMessage;
if(errCode != "0"){
alert(errCode+"="+errDesc);
}else{
if(jsonStr != null){
fn_makeListJson(jsonStr); // 아래 fn_makeListJson(jsonStr) 함수 호출
}
}
}
,error: function(xhr,status, error){
alert("에러발생");
}
});
}
// 결과 테이블 생성 : 위에서 호출 받아서 처리할 fn_makeListJson(jsonStr) 메서드 선언
function fn_makeListJson(jsonStr){
var htmlStr = "";
$(jsonStr.results.juso).each(function(){
htmlStr += "<tr onclick=\"javascript:chooseAddress('"+this.roadAddr+"', '"+this.jibunAddr+"', '"+this.zipNo+"');\">";
htmlStr += "<td>";
htmlStr += "<dl>"+this.roadAddr+"</dl>";
htmlStr += "<dl>"+this.jibunAddr+"</dl>";
htmlStr += "</td>";
htmlStr += "<td>"+this.zipNo+"</td>";
htmlStr += "</tr>";
});
$("#addressTableTbody").html(htmlStr);
}
// Enter 키 이벤트
function enterSearch() {
var evt_code = (window.netscape) ? ev.which : event.keyCode;
if (evt_code == 13) {
event.keyCode = 0;
fn_search(); // jsonp사용하여 enter키 입력 확인 : fn_search() 함수 호출
}
}
// 주소 선택
function chooseAddress(roadAddr, jibunAddr, zipNo){
var aParam = [];
aParam["roadAddr"] = roadAddr;
// aParam["jibunAddr"] = jibunAddr; // 필요시 추가 활용함
// aParam["zipNo"] = zipNo; // 필요시 추가 활용함
opener.callback_openAddressPopup(aParam);
window.close();
}
</script>
</head>
<div class="container" style="margin-top:25px;">
<div id="memberSearchDiv" class="text-center">
<form id="searchForm" name="searchForm" method="post" class="navbar-form navbar-left" role="search" onsubmit="event.preventDefault();">
<input type="hidden" name="currentPage" value="1"/>
<input type="hidden" name="countPerPage" value="100"/>
<input type="hidden" name="resultType" value="json"/>
<input type="hidden" id="confmKey" name="confmKey" value="이자리에 Open API 키를 기재하시기 바랍니다"/><!-- 요청 변수 설정 (승인키) -->
<div class="form-group">
<input type="text" id="keyword" name="keyword" class="form-control" placeholder="도로명+건물번호, 건물명, 지번을 입력하세요" onkeypress="javascript:enterSearch();" />
</div>
<input type="button" class="btn btn-default" onclick="javascript:fn_search();" value="주소검색하기" />
</form>
</div>
<div>
<table class="table table-hover">
<thead>
<tr>
<th>주소</th>
<th>우편번호</th>
</tr>
</thead>
<tbody id="addressTableTbody">
</tbody>
</table>
</div>
</div>
10) src\main\webapp 폴더 안에 success.jsp 소스 코딩함
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>주소 정보 연동 입력 성공</title>
</head>
<body>
<h2>* 주소 정보가 제대로 등록 처리 되었습니다!</h2>
<br>
<form action="index.jsp">
<input type="submit" value="처음으로" />
</form>
</body>
</html>
============================================================
20. index.jsp 파일 실행 확인함
1) JAVA_Servlet_JSP_SpringMVC_OracleDB 프로젝트 클릭 선택 - 마우스 우클릭 - Run As - Run on Server 클릭 : [처음 화면] 확인함
2) 상세 주소 검색해서 정상 동작 테스트하고, "처음으로" 버튼 클릭해서 처음으로 이동 확인함.
3) OracleDB 입력 데이터 확인해 봄.
C:\Users\starh>sqlplus jsp_openapi/jsp_openapi
SQL*Plus: Release 11.2.0.1.0 Production on 월 1월 10 19:23:38 2022
Copyright (c) 1982, 2010, Oracle. All rights reserved.
다음에 접속됨:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL>show user
SQL>select * from jsp_address;



https://business.juso.go.kr/addrlink/openApi/popupApi.do






https://business.juso.go.kr/addrlink/openApi/searchApi.do
검색API
본인인증 사용중인 휴대전화번호로 인증 인증하기 아이핀 인증 본인 명의 아이핀 계정으로 인증 인증하기
business.juso.go.kr
function 복사 붙여넣기




결과 테이블 생성: 위에서 호출받아서 처리할 fn_makeListJson(jsonStr) 메서드 선언





AddressDAO
package com.openapi.spring.address;
import java.sql.Connection;
import java.sql.PreparedStatement;
import com.openapi.spring.common.JDBCUtil;
// OracleDB 연동 DAO(Data Access Object) AddressDAO 클래스 작성
public class AddressDAO {
private Connection conn = null;
private PreparedStatement stmt =null;
// PreparedStatement 활용 insert 처리 쿼리문 작성
//insert into jsp_address values(idx_seq.nextval, '서울시 행복한 아파트', '살기좋은동 1004호')
private static final String INSERT_ADDRESS ="insert into jsp_address values(idx_seq.nextval, ?, ?)";
// insertAddress 메서드 작성
public void insertAddress(AddressVO vo) {
try {
conn = JDBCUtil.getConnection();
stmt =conn.prepareStatement(INSERT_ADDRESS);
stmt.setString(1, vo.getMainAddress());
stmt.setString(2, vo.getSubAddress());
stmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.close(stmt, conn);
}
}
}
AddressVO
package com.openapi.spring.address;
import java.util.Map;
// AdressVO 클래스 작성
public class AddressVO {
private String mainAddress; // 기본 주소 필드 선언
private String subAddress; // 상세 주소 필드 선언
public String getMainAddress() {
return mainAddress;
}
public void setMainAddress(String mainAddress) {
this.mainAddress = mainAddress;
}
public String getSubAddress() {
return subAddress;
}
public void setSubAddress(String subAddress) {
this.subAddress = subAddress;
}
// 기본 주소가 비어있는지 검증하는 메서드 작성
public void validateMain(Map<String, Boolean> errors) {
if (mainAddress == null || mainAddress.trim().isEmpty()) {
errors.put("main", Boolean.TRUE);
}
}
// 상세 주소가 비어있는지 검증하는 메서드 작성
public void validateSub(Map<String, Boolean> errors) {
if (subAddress == null || subAddress.trim().isEmpty()) {
errors.put("sub", Boolean.TRUE);
}
}
}
JDBCUtil
package com.openapi.spring.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
// Oracle DB 연결 및 close() 처리 JDBC Utility 클래스 작성
public class JDBCUtil {
public static Connection getConnection() {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
return DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl",
"jsp_openapi", "jsp_openapi");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void close(PreparedStatement stmt, Connection conn) {
if (stmt != null) {
try {
if (!stmt.isClosed()) {
stmt.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
stmt = null;
}
}
if (conn != null) {
try {
if (!conn.isClosed()) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
public static void close(ResultSet rs, PreparedStatement stmt, Connection conn) {
if (rs != null) {
try {
if (!rs.isClosed()) {
rs.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
rs = null;
}
}
if (stmt != null) {
try {
if (!stmt.isClosed()) {
stmt.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
stmt = null;
}
}
if (conn != null) {
try {
if (!conn.isClosed()) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
public static void rollback(Connection conn) {
if(conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
}
}
}
}
AddressController
package com.openapi.spring.controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.openapi.spring.address.AddressDAO;
import com.openapi.spring.address.AddressVO;
//웹 URL을 /update.do 로 매핑 처리함 : 서블릿 파일로 HttpServlet 상속 AddressController 클래스 작성
@WebServlet("/update.do")
public class AddressController extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
process(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
process(request, response);
}
private void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{
// 인코딩 타입 설정
request.setCharacterEncoding("utf-8");
// 기본 주소와 상세 주소를 파라미터로 받은 뒤 변수에 대입해 줍니다.
String mainAddress = request.getParameter("mainAddress");
String subAddress = request.getParameter("subAddress");
// vo 객체 생성 후 위에서 받은 변수로 값을 set 처리합니다.
AddressVO vo = new AddressVO();
vo.setMainAddress(mainAddress);
vo.setSubAddress(subAddress);
// error에 관한 해쉬맵 생성 및 Attribute 설정을 처리합니다.
Map<String, Boolean> errors = new HashMap<String, Boolean>();
request.setAttribute("errors", errors);
// 검증 메소드를 호출합니다.
vo.validateMain(errors);
vo.validateSub(errors);
// DAO 객체 생성 후 insert 메소드를 실행 처리합니다.
AddressDAO addressDAO = new AddressDAO();
addressDAO.insertAddress(vo);
// 만약 errors에 값이 존재한다면
if(!errors.isEmpty()) {
// 포워딩을 통해 초기화면으로 되돌리게 합니다.
// 포워드는 RequestDispatcher을 이용하여 응답으로 사용할 jsp 방식으로 넘기는 방식으로
// 실행속도가 빠르나 브라우저 입장에서는 URL이 바뀌지 않는 단점이 있습니다.
// 리다이렉트는 두번의 요청과 응답으로 처리되서 실행속도가 느리지만
// 클라이언트가 URL을 확인할 수 있는 장점이 있습니다.
// 1. 에러가 존재하여 초기화면을 돌리는 작업은 같은 페이지 내에서 일어나므로 포워드로 처리하고
request.getRequestDispatcher("index.jsp").forward(request, response);
}
// 2. 에러가 존재하지 않아 성공화면을 보여주는 작업은
// URL이 바뀔 필요가 있으므로 리다이렉트로 처리했습니다.
response.sendRedirect("success.jsp");
}
}
home.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Insert title here</title>
</head>
<body>
<h1>
Hello world!
</h1>
<P> The time on the server is ${serverTime}. </P>
</body>
</html>
</body>
</html>
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webapp 폴더 안에 index.jsp 소스코딩</title>
<link rel="stylesheet" type="text/css" media="screen" href="resources/css/bootstrap-3.3.2.min.css">
<script type="text/javascript" src="resources/js/jquery-3.5.1.min.js"></script>
<script type="text/javascript">
//도로명주소 - 주소검색 팝업을 호출합니다.
//https://business.juso.go.kr/addrlink/openApi/popupApi.do 웹사이트에서
//하단 "주소입력화면 소스보기"를 클릭해서 참고합니다.
function fn_openAddressPopup(){
var url = "addressAPIPopup.jsp";
var name= "AddressPopup";
var option = "width=650, height=500, top=100, left=200, location=no"
window.open(url, name, option);
}
// 주소검색 팝업 호출 콜백 callback_openAddressPopup() 메서드 입니다.
function callback_openAddressPopup(aParam){
document.getElementById("mainAddress").value= aParam["roadAddr"];
}
</script>
</head>
<body>
<h2>[처음화면]</h2>
<!-- update.do 로 데이터 전송 -->
<form action="update.do" method="post">
<div class="input-group">
<span>기본주소</span>
<br>
<input type="text" id="mainAddress" name="mainAddress" placeholder="주소를 선택하세요!" size="40" readonly="readonly">
<!-- errors Map 에 값이 해당하는 값이 있을 경우 메시지를 출학하는 부분 -->
<span>
<c:if test="${errors.main}">기본 주소를 입력하세요!</c:if>
</span>
<button type="button" onclick="javascript:fn_openAddressPopup();">주소 검색</button><br><br>
</div>
<div style="margin-top: 0px;">
<span>상세 주소</span>
<br>
<input type="text" id="subAddress" name="subAddress" size="40" placeholder="나머지 주소를 입력하세요!">
<c:if test="${errors.sub}">상세 주소를 입력하세요!</c:if>
</div> <br>
<input type="submit" value="주소등록" />
<input type="reset" value="입력취소" />
</form>
</body>
</html>
addressAPIPopup.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webapp 폴더 안에 addressAPIPopup.jsp 소스 코딩</title>
<link rel='stylesheet' type='text/css' media='screen' href='resources/css/bootstrap-3.3.2.min.css'>
<script src="resources/js/jquery-3.5.1.min.js"></script>
<script type="text/javascript">
// https://business.juso.go.kr/addrlink/openApi/searchApi.do 웹사이트에서
// 하단 "웹 호출 소스 보기"에서 "JSON" 클릭해서 참고 합니다.
// 도로명 주소로 검색 api 연동을 ajax로 처리 합니다.
function fn_search(){
$.ajax({
url :"https://business.juso.go.kr/addrlink/addrLinkApiJsonp.do" //인터넷망
,type:"post"
,data:$("#searchForm").serialize()
,dataType:"jsonp"
,crossDomain:true
,success:function(jsonStr){
var errCode = jsonStr.results.common.errorCode;
var errDesc = jsonStr.results.common.errorMessage;
if(errCode != "0"){
alert(errCode+"="+errDesc);
}else{
if(jsonStr != null){
fn_makeListJson(jsonStr);
}
}
}
,error: function(xhr,status, error){
alert("에러발생");
}
});
}
// 결과 테이블 생성: 위에서 호출받아서 처리할 fn_makeListJson(jsonStr) 메서드 선언
function fn_makeListJson(jsonStr){
var htmlStr = "";
$(jsonStr.results.juso).each(function(){
htmlStr += "<tr onclick=\"javascript:chooseAddress('"+this.roadAddr+"', '"+this.jibunAddr+"', '"+this.zipNo+"');\">";
htmlStr += "<td>"
htmlStr += "<dl>"+this.roadAddr+"</dl>";
htmlStr += "<dl>"+this.jibunAddr+"</dl>";
htmlStr += "</td>"
htmlStr += "<td>"+this.zipNo+"</td>";
htmlStr += "</tr>";
});
$("#addressTableTbody").html(htmlStr);
}
// Enter 키 이벤트 처리 enterSearch() 메서드 선언
function enterSearch() {
var evt_code = (window.netscape) ? ev.which : event.keyCode;
if (evt_code == 13) {
event.keyCode = 0;
fn_search(); //jsonp사용시 enter검색
}
}
// 주소 선택
function chooseAddress(roadAddr, jibunAddr, zipNo) {
var aParam = [];
aParam["roadAddr"] = roadAddr;
// aParam["jibunAddr"] = jibunAddr; // 필요시 추가 활용함
// aParam["zipNo"] = zipNo; // 필요시 추가 활용함
opener.callback_openAddressPopup(aParam);
window.close();
}
</script>
</head>
<body>
<div class="container" style="margin-top:25px;">
<div id ="memberSearchDiv" class="text-center">
<form name="searchForm" id="searchForm" method="post" class="navbar-form navbar=left" role="search" onsubmit="event.preventDefault();">
<input type="hidden" name="currentPage" value="1"/>
<input type="hidden" name="countPerPage" value="100"/>
<input type="hidden" name="resultType" value="json"/>
<input type="hidden" name="confmKey" id="confmKey" value="devU01TX0FVVEgyMDIzMTEwNjE1MTU1MzExNDI0NTU="/><!-- 요청 변수 설정 (승인키) -->
<div class="form-group">
<input type="text" width="80px" id="keyword" name="keyword" class="form-control" placeholder="도로명 + 건물 번호, 건물명, 지번을 입력하세요" onkeypress="javascript:enterSearch();" />
</div>
<input type="button" class="btn btn-default" onclick="javascript:fn_search();" value="주소 검색하기" />
</form>
</div>
<div>
<table class="table table-hover">
<thead>
<tr>
<th>주소</th>
<th>우편번호</th>
</tr>
</thead>
<tbody id="addressTableTbody">
</tbody>
</table>
</div>
</div>
</body>
</html>
dbconnTest.jsp
<%@page import="com.openapi.spring.common.JDBCUtil"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import = "java.sql.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>webapp 폴더 안에 dbconnTest.jsp 소스 코딩</title>
</head>
<body>
<!-- JDBCUtil 활용 OracleDB 연결 접속을 확인해 봅니다. -->
<%
try (Connection conn = JDBCUtil.getConnection()){
out.println("커넥션 연결 성공함");
} catch (SQLException e) {
out.println("커넥션 연결 실패함 : " + e.getMessage());
application.log("커넥션 연결 실패", e);
}
%>
</body>
</html>
success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webapp 폴더 안에 success.jsp 소스 코딩</title>
</head>
<body>
<h2> * 주소 정보가 제대로 등록 처리 되었습니다!</h2>
<br>
<form action="index.jsp">
<input type="submit" value="처음으로">
</form>
</body>
</html>