프론트에서 서울특별시 영등포구 여의대로 108(더현대)의 주소를 받아온 뒤 해당 주소의 위도와 경도를 가져오기 위해서 Geocoding을 이용해 위도 경도를 받아와 보자
네이버 클라우드에 Geocoding 사용 등록을 해야한다.
등록한 뒤 Client-ID와 Client-Secret을 기억할 필요가 있다.
X-NCP-APIGW-API-KEY-ID : Client-ID
X-NCP-APIGW-API-KEY : Client-secret
형식으로 Header에 보내줘야 Geocoding이 사용된다.
URL :
https://naveropenapi.apigw.ntruss.com/map-geocode/v2/geocode?query=서울특별시 영등포구 여의대로 108
Header에 아래 키를 넣어준다.
X-NCP-APIGW-API-KEY-ID : Client-ID
X-NCP-APIGW-API-KEY : Client-secret
query뒤에 주소를 넣으면 해당 주소의 위도 경도 포함 모든 정보가 나온다.
{
"status": "OK",
"meta": {
"totalCount": 1,
"page": 1,
"count": 1
},
"addresses": [
{
"roadAddress": "서울특별시 영등포구 여의대로 108 파크원",
"jibunAddress": "서울특별시 영등포구 여의도동 22 파크원",
"englishAddress": "108, Yeoui-daero, Yeongdeungpo-gu, Seoul, Republic of Korea",
"addressElements": [
{
"types": [
"SIDO"
],
"longName": "서울특별시",
"shortName": "서울특별시",
"code": ""
},
{
"types": [
"SIGUGUN"
],
"longName": "영등포구",
"shortName": "영등포구",
"code": ""
},
{
"types": [
"DONGMYUN"
],
"longName": "여의도동",
"shortName": "여의도동",
"code": ""
},
{
"types": [
"RI"
],
"longName": "",
"shortName": "",
"code": ""
},
{
"types": [
"ROAD_NAME"
],
"longName": "여의대로",
"shortName": "여의대로",
"code": ""
},
{
"types": [
"BUILDING_NUMBER"
],
"longName": "108",
"shortName": "108",
"code": ""
},
{
"types": [
"BUILDING_NAME"
],
"longName": "파크원",
"shortName": "파크원",
"code": ""
},
{
"types": [
"LAND_NUMBER"
],
"longName": "22",
"shortName": "22",
"code": ""
},
{
"types": [
"POSTAL_CODE"
],
"longName": "07335",
"shortName": "07335",
"code": ""
}
],
"x": "126.9271941",
"y": "37.5266691",
"distance": 0.0
}
],
"errorMessage": ""
}
이런 식으로 데이터가 나오는데 그렇다면 spring boot에서 Geocoding을 사용해보자
package com.ssafy.bangrang.domain.event.entity;
import com.ssafy.bangrang.domain.event.api.request.EventUpdateDto;
import com.ssafy.bangrang.domain.event.api.request.UpdateEventRequestDto;
import com.ssafy.bangrang.domain.inquiry.entity.Inquiry;
import com.ssafy.bangrang.domain.stamp.entity.Stamp;
import com.ssafy.bangrang.domain.member.entity.WebMember;
import com.ssafy.bangrang.global.common.entity.CommonEntity;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "event")
@ToString(of = {"idx", "title"})
public class Event extends CommonEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "event_idx")
private Long idx;
@Column(name = "event_title", nullable = false, columnDefinition = "TEXT")
private String title;
@Column(name = "event_sub_title", columnDefinition = "TEXT")
private String subTitle;
@Column(name = "event_content", columnDefinition = "TEXT")
private String content;
@Column(name = "event_image", columnDefinition = "TEXT")
private String image;
// 이미지 1
@Column(name = "event_subImage", columnDefinition = "TEXT")
private String subImage;
// 이미지 2
@Column(name = "event_start_date")
private LocalDateTime startDate;
@Column(name = "event_end_date")
private LocalDateTime endDate;
@Column(name = "event_address", columnDefinition = "TEXT")
private String address;
@Column(name = "event_latitude")
private Double latitude;
@Column(name = "event_longitude")
private Double longitude;
@Column(name = "event_url", columnDefinition = "TEXT")
private String eventUrl;
// 행사 메인 페이지
// 행사 등록한 사람
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_idx")
private WebMember webMember;
// 행사에 대한 문의사항
@OneToMany(mappedBy = "event")
private List<Inquiry> inquiries = new ArrayList<>();
// 좋아요 수
@OneToMany(mappedBy = "event")
private List<Likes> likes = new ArrayList<>();
@OneToOne(mappedBy = "event")
private Stamp stamp;
@Builder
public Event(Long idx,String title, String subTitle, String content, String image, String subImage, LocalDateTime startDate, LocalDateTime endDate, String address, Double latitude, Double longitude, String eventUrl, WebMember webMember){
this.idx = idx;
this.title = title;
this.subTitle = subTitle;
this.content = content;
this.image = image;
this.subImage = subImage;
this.startDate = startDate;
this.endDate = endDate;
this.address = address;
this.latitude = latitude;
this.longitude = longitude;
this.eventUrl = eventUrl;
this.changeWebMember(webMember);
}
public void changeWebMember(WebMember webMember) {
this.webMember = webMember;
webMember.getEvents().add(this);
}
/**
* 이벤트 상태 변경
*/
public void updateEvent(UpdateEventRequestDto updateEventRequestDto, double changelati, double changelong) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
this.title=updateEventRequestDto.getTitle();
this.subTitle=updateEventRequestDto.getSubTitle();
this.content=updateEventRequestDto.getContent();
this.startDate=LocalDateTime.parse(updateEventRequestDto.getStartDate(),formatter);
this.endDate=LocalDateTime.parse(updateEventRequestDto.getEndDate());
this.address=updateEventRequestDto.getAddress();
this.latitude=changelati;
this.longitude=changelong;
this.eventUrl=updateEventRequestDto.getEventUrl();
}
public void updateEventImg(String ImgUrl) {
this.image=ImgUrl;
}
public void updateEventSubImg(String ImgUrl) {
this.subImage=ImgUrl;
}
}
public JsonNode getLatiLong (String address) throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.add("X-NCP-APIGW-API-KEY-ID", client_id);
headers.add("X-NCP-APIGW-API-KEY", client_secret);
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
String query = address;
String url = "https://naveropenapi.apigw.ntruss.com/map-geocode/v2/geocode?query="+query;
log.info("네이버 Geocoding api요청 시작");
ResponseEntity<String> response =
restTemplate.exchange(url,
HttpMethod.GET,
new HttpEntity<>(null, headers),
String.class);
String body = response.getBody();
log.info("네이버 Geocoding api요청 완료");
JsonNode root = objectMapper.readTree(body);
JsonNode addresses = root.get("addresses");
return addresses;
}
HttpHeaders headers = new HttpHeaders();
headers.add("X-NCP-APIGW-API-KEY-ID", client_id); // client_id 넣어주기
headers.add("X-NCP-APIGW-API-KEY", client_secret); // client_secreit 넣어주기
RestTemplate restTemplate = new RestTemplate(); // java에서 api 요청 보내기 위해 RestTemplate을 활용하기
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
String query = address; // 어떤 주소 정보
String url = "https://naveropenapi.apigw.ntruss.com/map-geocode/v2/geocode?query="+query; // Geocoding 활용 API url
// "네이버 Geocoding api요청 시작"
ResponseEntity<String> response =
restTemplate.exchange(url,
HttpMethod.GET,
new HttpEntity<>(null, headers),
String.class);
String body = response.getBody(); // 가져온 데이터 body에 저장
// "네이버 Geocoding api요청 완료"
JsonNode root = objectMapper.readTree(body); // objectMapper를 활용해 읽어온 데이터 key value로 저장하기
JsonNode addresses = root.get("addresses"); // 해당 주소의 위도와 경도 가져오기
return addresses; // 위도 경도 리턴
@Override
@Transactional
public void createEvent(CreateEventRequestDto createEventRequestDto, MultipartFile image, MultipartFile subImage, UserDetails userDetails) throws Exception{
WebMember user = webMemberRepository.findById(userDetails.getUsername())
.orElseThrow(() -> new EmptyResultDataAccessException("해당 유저는 존재하지 않습니다.", 1));
JsonNode addresses = getLatiLong(createEventRequestDto.getAddress());
if (!addresses.isArray() || addresses.size() <= 0)
throw new Exception("위도, 경도 오류");
JsonNode firstAddress = addresses.get(0);
double longitude = Double.parseDouble(firstAddress.get("x").asText());
double latitude = Double.parseDouble(firstAddress.get("y").asText());
String img;
String subImg;
if (image!=null && !image.isEmpty()) {
String fileName = s3Service.generateEventImageName(image, createEventRequestDto.getTitle());
byte[] fileBytes = image.getBytes();
img = s3Service.uploadToS3(fileName,fileBytes, image.getContentType());
} else img = null;
if (subImage!=null && !subImage.isEmpty()) {
String fileName = s3Service.generateEventSubImageName(subImage, createEventRequestDto.getTitle());
byte[] fileBytes = subImage.getBytes();
subImg = s3Service.uploadToS3(fileName,fileBytes, subImage.getContentType());
} else subImg = null;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
Event event = Event.builder()
.title(createEventRequestDto.getTitle())
.subTitle(createEventRequestDto.getSubTitle())
.address(createEventRequestDto.getAddress())
.content(createEventRequestDto.getContent())
.eventUrl(createEventRequestDto.getEventUrl())
.longitude(longitude)
.latitude(latitude)
.startDate(LocalDateTime.parse(createEventRequestDto.getStartDate(),formatter))
.endDate(LocalDateTime.parse(createEventRequestDto.getEndDate(),formatter))
.image(img)
.subImage(subImg)
.webMember(user)
.build();
eventRepository.save(event);
Event saveEvent = eventRepository.findByTitle(createEventRequestDto.getTitle())
.orElseThrow();
Stamp stamp = Stamp.builder()
.name(saveEvent.getTitle())
.event(saveEvent)
.build();
stampRepository.save(stamp);
}
WebMember user = webMemberRepository.findById(userDetails.getUsername())
.orElseThrow(() -> new EmptyResultDataAccessException("해당 유저는 존재하지 않습니다.", 1)); // User 체크하기
// geocoding을 활용해 찾아낸 위도와 경도 함수 활용
JsonNode addresses = getLatiLong(createEventRequestDto.getAddress());
// 만약 위도와 경도를 찾아내지 못할시 에러 발생
if (!addresses.isArray() || addresses.size() <= 0)
throw new Exception("위도, 경도 오류");
// 위도와 경도를 각각 저장하고 Double 데이터 타입으로 변경
JsonNode firstAddress = addresses.get(0);
double longitude = Double.parseDouble(firstAddress.get("x").asText());
double latitude = Double.parseDouble(firstAddress.get("y").asText());
// img, subimg를 저장할 객체를 만들어줌
String img;
String subImg;
// img를 s3에 저장하자
if (image!=null && !image.isEmpty()) {
String fileName = s3Service.generateEventImageName(image, createEventRequestDto.getTitle()); // s3에 이미지의 이름을 저장하는 코드
byte[] fileBytes = image.getBytes(); // 이미지를 bytes로 변환해 저장
img = s3Service.uploadToS3(fileName,fileBytes, image.getContentType()); // s3에 이미지 주소, 파일, 콘텐츠타입을 가져와 저장하기
} else img = null;
if (subImage!=null && !subImage.isEmpty()) {
String fileName = s3Service.generateEventSubImageName(subImage, createEventRequestDto.getTitle());
byte[] fileBytes = subImage.getBytes();
subImg = s3Service.uploadToS3(fileName,fileBytes, subImage.getContentType());
} else subImg = null;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
Event event = Event.builder() // 데이터를 저장 startDate와 endDate는
.title(createEventRequestDto.getTitle())
.subTitle(createEventRequestDto.getSubTitle())
.address(createEventRequestDto.getAddress())
.content(createEventRequestDto.getContent())
.eventUrl(createEventRequestDto.getEventUrl())
.longitude(longitude)
.latitude(latitude)
.startDate(LocalDateTime.parse(createEventRequestDto.getStartDate(),formatter))
.endDate(LocalDateTime.parse(createEventRequestDto.getEndDate(),formatter))
.image(img)
.subImage(subImg)
.webMember(user)
.build();
eventRepository.save(event);