유미의 기록들

[React Native -15] 행정안전부 주소 API 사용하여 직접 구현해보기 본문

MDLAB 기록/차량부품거래애플리케이션

[React Native -15] 행정안전부 주소 API 사용하여 직접 구현해보기

지유미 2022. 12. 1. 18:55
728x90
반응형

이전에는 다음 주소 API를 사용하기 위해 라이브러리를 설치하여 쉽게 구현할 수 있었다

 

하지만, API를 사용하는 법을 제대로 습득하고, 디자인에 대한 자율성을 주고자 행정안전부에서 제공하는 도로명 주소 오픈 API를 사용해서 직접 구현해보기로 하였다

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

 

검색API

본인인증 사용중인 휴대전화번호로 인증 인증하기 아이핀 인증 본인 명의 아이핀 계정으로 인증 인증하기

business.juso.go.kr

 

1. 승인키 발급받기

승인키는 도로명주소 개발자센터 페이지에서 신청하여 실시간으로 발급 가능하다

 

 

2. 승인키 적용방법

행안부 도로명 주소 API는 URL 형태로 제공되며, API요청 URL을 호출하기 위해서는 발급받은 승인키와 필요한 요청변수를 입력해야 한다 

우리는 검색 API를 사용할 것이다

 

 

 

이렇게 발급받은 승인키와 필요한 요청변수를 입력을 하고 API요청 URL을 호출하면

https://business.juso.go.kr/addrlink/addrLinkApi.do?confmKey=승인키&currentPage=1&countPerPage=5&keyword=삼성동&resultType=json

요청한 값들에 대한 데이터가  json형태로 불러온다 

구현할 때 내가 필요한 정보는 common totalCountjusozipNo, readAddr, jibunAddr이다  

 

 

React Native에서 구현해보면,,,,

 

import React, { Component, PureComponent } from 'react';
import { View, Text,  TextInput, TouchableOpacity, FlatList,Keyboard,Modal} from 'react-native';

import { styles } from "../../styles/address_search";

import Icon from 'react-native-vector-icons/MaterialIcons';
import EmptyIcon from 'react-native-vector-icons/SimpleLineIcons';
import PageIcon from 'react-native-vector-icons/AntDesign'
import WebServiceManager from '../../util/webservice_manager';

import Indicator from '../../util/indicator';

class SearchAddress extends Component {
    constructor(props) {
        super(props);
        this.state = {
            addressContents:[],
            commonContents:[],
            searchText: "",
            searchViewVisible:false,
            emptyListViewVisible:false,
            page:1,
            totalCount:0,
            indicator:false,
        }
    }

    //검색 버튼을 눌렀을 때
    searchAddress=()=>{
        if(this.state.searchText == "")
        {
            alert("주소를 입력해주세요");
        }
        else{
            this.setState({page:1},()=>this.goGetAddress(this.state.page))
            this.setState({searchViewVisible:true});
            Keyboard.dismiss();
        }
    }
    goGetAddress=(page)=>{
        this.setState({indicator:true})
        this.callGetAddressAPI(page).then((response) => {
            this.setState({ addressContents: response.results.juso,commonContents: response.results.common,totalCount:response.results.common.totalCount,indicator:false,emptyListViewVisible:false }
                ,()=>{
                    if(this.state.addressContents.length==0){
                        this.setState({emptyListViewVisible:true})
                    }
                });
            //console.log('componentResponse',response)
        });
    }
	//페이지 감소 버튼 클릭
    pageDownClicked=()=>{
        if (this.state.page > 1)
            this.setState({ page: this.state.page - 1 },()=>this.goGetAddress(this.state.page))
    }
    //페이지 증가 버튼 클릭
    pageUpClicked=()=>{
        if (this.state.page < (this.state.totalCount / 4))
            this.setState({ page: this.state.page + 1 },()=>this.goGetAddress(this.state.page))
    }
    async callGetAddressAPI(page) {
        let manager = new WebServiceManager("https://business.juso.go.kr/addrlink/addrLinkApi.do?confmKey=승인키&currentPage=" + page + "&countPerPage=4&keyword=" + this.state.searchText + "&resultType=json");
        let response = await manager.start();
        if (response.ok)
            return response.json();
        else
            Promise.reject(response);
    }
    render() {
        return (
            <View style={styles.total_container}> 
               <View style={styles.search_view}>
                    <View style={styles.search_input}>
                        <View style={styles.row_layout}>
                            <TextInput style={styles.input}
                                onChangeText={(text) => this.setState({ searchText: text  })}
                                onEndEditing={this.searchAddress }
                                placeholder="도로명 또는 지번을 입력하세요"
                                placeholderTextColor="light grey" />
                            <TouchableOpacity style={styles.search_btn} onPress={this.searchAddress}>
                                <Icon name="search" size={30} color="light grey" />
                            </TouchableOpacity>
                        </View>
                    </View>
               </View>
               <View style={styles.content_view}>
               <Modal transparent={true} visible={this.state.indicator}>
                    <Indicator />
                </Modal>
                    {this.state.emptyListViewVisible && <>
                        <View style={{justifyContent:'center',alignItems:'center',paddingTop:'5%'}}>
                        <EmptyIcon name="exclamation" size={40} color="#D1D1D1" />
                        <Text style={{marginTop:'5%'}}>검색 결과가 없습니다</Text>
                        </View>
                    </>}
                    {this.state.searchViewVisible?
                        
                        <FlatList
                        data={this.state.addressContents}
                        renderItem={({item,index})=><AddressItem item={item} navigation={this.props.navigation} addressListener={this.props.route.params.addressListener}/>}/> :
                        <>
                        <Text style={styles.title}>TIP</Text>
                        <Text style={styles.text}>도로명, 건물명, 지번 중 선택하여</Text>
                        <Text style={styles.text2}>입력하세요 </Text>
                        <Text style={styles.content}> 도로명 + 건물번호 <Text style={styles.content2}> 예) 테헤란로 152</Text></Text>
                        <Text style={styles.content}> 동/읍/면/리 + 번지 <Text style={styles.content2}> 예) 역삼동 737</Text> </Text>
                        <Text style={styles.content}> 건물명, 아파트명  <Text style={styles.content2}> 예) 삼성동 힐스테이트</Text></Text>
                        </>}
                   
               </View>
                {this.state.searchViewVisible&&this.state.emptyListViewVisible==false&&
                <View style={styles.page_view}>
                    <View style={styles.row_layout}>
                        <TouchableOpacity onPress={this.pageDownClicked} activeOpacity={0.8} >
                        <PageIcon name="leftsquareo" size={30} color="light grey" />
                        </TouchableOpacity>
                    
                        <Text  style={styles.text}>   <Text style={[styles.text,{color:'blue'}]}>{this.state.page} </Text> / {Math.ceil(this.state.totalCount/4)}   </Text>
                        <TouchableOpacity onPress={this.pageUpClicked} activeOpacity={0.8}>
                            <PageIcon name="rightsquareo" size={30} color="light grey" />
                        </TouchableOpacity>
                    </View>
                </View>}
            </View>
        );
    }
}

✔️ 검색버튼을 누를 시,  주소검색 API호출해서 addressContents와 commonContents 배열에 넣는다 

* 이때 page는 1으로 초기화시켜준다

 

✔️ addressContents가 빈 배열이면 (즉, 검색결과를 불러올 수 없으면) emptyListViewVisible을 true로 setState해주어서 검색결과가 표시되지 않는다는 View를 보여준다

 

✔️ 증가, 감소 버튼을 클릭할 때 마다 page를 setState해준다

 

 

 

 addressContents 배열값에 들어있는 Data를 뿌려주는 부분  (zipNo, roadAddr, jibunAddr 사용)

class AddressItem extends PureComponent{
    constructor(props) {
        super(props);
    }
    addressItemClicked=(zipNo,roadAddr)=>{
        this.props.navigation.navigate('Payment');
        this.props.addressListener(zipNo, roadAddr);
    }
    render(){
        const { zipNo,roadAddr,jibunAddr } = this.props.item;
        return(
        <TouchableOpacity activeOpacity={0.8} onPress={()=>this.addressItemClicked(zipNo,roadAddr)}>
                <View style={styles.outputStyle}>
                    <View style={styles.row_layout}>
                        <View style={styles.titleLayout}>
                            
                            <View style={styles.flex}><Text>도로명</Text></View >
                            <View style={styles.flex}><Text>지번</Text></View >
                        </View>
                        <View style={styles.addressLayout}>
                            <View style={styles.flex}><Text style={{ color: "black" }}>{roadAddr} </Text></View >
                            <View style={styles.flex}><Text style={{ color: "black" }}>{jibunAddr}</Text></View >
                        </View>
                        <View style={styles.numberLayout}>
                            <Text style={[styles.text,{fontWeight:'600'}]}>{zipNo}</Text>
                        </View>
                    </View>
                </View>
        </TouchableOpacity>
        );
       
    }
}

 

 

 

 

추가로 알게 된부분

 

✔️ TextInput에서 onChangeText 는 텍스트가 바뀔 때 마다 함수를 호출하였는데 onEndEditing을 사용하면 입력이 끝났을 때 함수를 호출한다

onEndEditing={() => this.setState({value: this.state.searchText}) }

✔️ 하위 클래스에서 navigation을 사용할 때는 props로 전달해주어야 한다 

{this.state.modal == true && (<SearchView searchText={this.state.value} navigation={this.props.navigation}/>)}

 

728x90
반응형
Comments