1. ๊ฐ์
์งํ์ค์ธ ํ๋ก์ ํธ์์ ํ์ฌ ์ฌ์ฉ์๊ฐ ๋ณด๊ณ ์๋ ์ง๋ ํ๋ฉด์ ์ผ์๋ฆฌ๋ฅผ ๋์์ฃผ๋ ๊ธฐ๋ฅ์ ๊ฐ๋ฐํ๊ฒ๋๋ค.
์์ด๋น์๋น ๊ฐ์ ์๋ฐ ์ ์, ๋ค์ด๋ฒ ๋ถ๋์ฐ๊ฐ์ ๋ถ๋์ฐ ํ๋ซํผ์์๋ ์ฝ๊ฒ ๋ณผ ์ ์๋ ๊ธฐ๋ฅ์ด๋ค.
์ฐ๋ฆฌ ์๋น์ค์๋ ์ด์ ๋น์ทํ ๊ธฐ๋ฅ์ด ์๊ณ , ์๋๋ ๊ฐ๋ฐ ์ค์ธ ์๋น์ค์ ์ด์ ๋์์ธ์ด๋ค.
๊ฐ ์ผ์๋ฆฌ ๋ชจ์ง ๊ณต๊ณ ์๋ ์ด๋ฏธ ์๋, ๊ฒฝ๋ ๋ฐ์ดํฐ๋ฅผ ํจ๊ป ๊ฐ๊ณ ์๋ค.
๋ฐ๋ผ์ ํ์ฌ ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๊ณ ์๋ ์ง๋์ ๋ถ๋์ชฝ, ๋จ์์ชฝ ์๋, ๊ฒฝ๋๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์ ํ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ ค ์กฐํํด ์ฌ ์๊ฐ์ด๋ค.
์ฌ์ค ํ์ต์ด ๊ฝค๋ ํ์ํ๊ฑฐ๋, ์ ๋ฆฌํ ๊ฒ ์๋ ๊ฒฝ์ฐ์๋ง ํฌ์คํฐ๋ฅผ ์์ฑํ๋ ํธ์ธ๋ฐ ์ด๋ฒ์ ๊ตฌ๊ธ๋ง ํ์ ๋ ์๋ฃ๊ฐ ๋๋ฌด ์์ด์ ์ฒ์ ํ์๋ ๋ถ๋ค์ด๊ฒ ์กฐ๊ธ์ด๋๋ง ๋์์ด ๋๊ณ ์ ์ฐ๊ณ ์๋ค.
2. ์นด์นด์ค Map Key ๋ฐ๊ธ
์ง๋์ ๊ฒฝ๊ณ ๋ถ๋ถ ์๋, ๊ฒฝ๋๋ ํ๋ก ํธ ํ์ด ์์์ ์ ๋๊ฒจ์ฃผ๊ฒ ์ง๋ง ๊ฐ๋ฐ ํ ํ ์คํธ๋ฅผ ์ํด ์นด์นด์ค ๋งต API๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ํ๋ค.
- ์นด์นด์ค API ์ ์
- ๋ด ์ ํ๋ฆฌ์ผ์ด์ ์ด๋
- ์ ํ๋ฆฌ์ผ์ด์ ์ถ๊ฐ
- JavaScript ํค ๋ณต์ฌ
- ํ๋ซํผ์ ์ฌ์ฉํ URL ๋ฑ๋ก
์ฌ๊ธฐ์ ์ฌ์ฉํ ํค๋ JavaScript ํค ์ด๋ค.
๋ง์ง๋ง์ผ๋ก ํ๋ซํผ ๋ฉ๋ด์์ URL์ ๋ฑ๋ก์์ผ์ค์ผ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
์๋๋ ์นด์นด์ค Map์ ์์ฑ ํ ์๋, ๊ฒฝ๋๋ฅผ ์ ๋ ฅํด Center ์์น๋ฅผ ์ก๊ณ , ๋ถ๋์ชฝ ๊ฒฝ๊ณ, ๋จ์์ชฝ ๊ฒฝ๊ณ์ ์๋, ๊ฒฝ๋ ์ขํ๋ฅผ ๊ตฌํ๋ ๊ฐ๋จํ HTML JS ์ฝ๋์ด๋ค.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script
type="text/javascript"
src="http://dapi.kakao.com/v2/maps/sdk.js?appkey=ab9e6700f2bc6a1dee2720143aade0cf"
></script>
<div id="map" style="width: 100%; height: 350px"></div>
<div id="mapInfo"></div>
<script>
var mapContainer = document.getElementById('map'), // ์ง๋๋ฅผ ํ์ํ div
mapOption = {
center: new kakao.maps.LatLng(33.450701, 126.570667), // ์ง๋์ ์ค์ฌ์ขํ
level: 3, // ์ง๋์ ํ๋ ๋ ๋ฒจ
};
var map = new kakao.maps.Map(mapContainer, mapOption); // ์ง๋๋ฅผ ์์ฑํฉ๋๋ค
// ์ผ๋ฐ ์ง๋์ ์ค์นด์ด๋ทฐ๋ก ์ง๋ ํ์
์ ์ ํํ ์ ์๋ ์ง๋ํ์
์ปจํธ๋กค์ ์์ฑํฉ๋๋ค
var mapTypeControl = new kakao.maps.MapTypeControl();
// ์ง๋ ํ์
์ปจํธ๋กค์ ์ง๋์ ํ์ํฉ๋๋ค
map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);
function getInfo() {
// ์ง๋์ ํ์ฌ ์ค์ฌ์ขํ๋ฅผ ์ป์ด์ต๋๋ค
var center = map.getCenter();
// ์ง๋์ ํ์ฌ ๋ ๋ฒจ์ ์ป์ด์ต๋๋ค
var level = map.getLevel();
// ์ง๋ํ์
์ ์ป์ด์ต๋๋ค
var mapTypeId = map.getMapTypeId();
// ์ง๋์ ํ์ฌ ์์ญ์ ์ป์ด์ต๋๋ค
var bounds = map.getBounds();
// ์์ญ์ ๋จ์์ชฝ ์ขํ๋ฅผ ์ป์ด์ต๋๋ค
var swLatLng = bounds.getSouthWest();
// ์์ญ์ ๋ถ๋์ชฝ ์ขํ๋ฅผ ์ป์ด์ต๋๋ค
var neLatLng = bounds.getNorthEast();
// ์์ญ์ ๋ณด๋ฅผ ๋ฌธ์์ด๋ก ์ป์ด์ต๋๋ค. ((๋จ,์), (๋ถ,๋)) ํ์์
๋๋ค
var boundsStr = bounds.toString();
var message = '์ง๋ ์ค์ฌ์ขํ๋ ์๋ ' + center.getLat() + ', <br>';
message += '๊ฒฝ๋ ' + center.getLng() + ' ์ด๊ณ <br>';
message += '์ง๋ ๋ ๋ฒจ์ ' + level + ' ์
๋๋ค <br> <br>';
message += '์ง๋ ํ์
์ ' + mapTypeId + ' ์ด๊ณ <br> ';
message +=
'์ง๋์ ๋จ์์ชฝ ์ขํ๋ ' +
swLatLng.getLat() +
', ' +
swLatLng.getLng() +
' ์ด๊ณ <br>';
message +=
'๋ถ๋์ชฝ ์ขํ๋ ' +
neLatLng.getLat() +
', ' +
neLatLng.getLng() +
' ์
๋๋ค';
document.getElementById('mapInfo').innerHTML = message;
}
getInfo();
</script>
</body>
</html>
์นด์นด์ค ๋ณธ์ฌ๋ฅผ ์ค์ฌ ์ขํ๋ก ์ฐ๊ณ , ์ง๋์ ํ๋ ๋ ๋ฒจ์ 3์ผ๋ก ํ์ ๋ ๋ถ๋์ชฝ ์ขํ์ ๋จ์์ชฝ ์ขํ๋ฅผ ์๋์ ๊ฐ์ด ๊ตฌํ ์ ์๋ค.
๋์๋ํ๊ต ์๋, ๊ฒฝ๋๋ฅผ ์ฐพ์ ํ ์คํธํด๋ณด๋ฉด ์๋์ ๊ฐ์ด ๋์จ๋ค. ๋จ์์ชฝ ์ขํ์ ์์๋ ์ด๋ฑํ๊ต๊ฐ ์์นํ๋๋ฐ, ํด๋น ์ขํ๋ฅผ ์ผํฐ ์ขํ๋ก ๊ณ ์ ํ๊ณ ์ง๋๋ฅผ ๋์ฐ๋ฉด ์์๋ ์ด๋ฑํ๊ต๊ฐ ์ ๋จ๋๊ฑธ ํ์ธํ ์ ์๋ค.
3. ๊ตฌํ & Test
์ด ๋ค๋ก ๋ฐ๋ก ์ค๋ช
์ด ํ์์์ ๊ฒ ๊ฐ์ ์ฝ๋๋ง ์ฒจ๋ถํ์๋ค.
- Controller
์ง๋ ๊ฒฝ๊ณ์ ์๋, ๊ฒฝ๋์ ๊ฐ๋จํ ํํฐ๋ง ์กฐ๊ฑด์ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์์ฃผ์๋ค.
@Operation(summary = "์ง๋์์ ๋ชจ์ง ๊ณต๊ณ ์กฐํ")
@GetMapping("/api/worker/job-post/map")
public ResponseEntity<Response> getJobPostOnMap(@AuthenticationPrincipal PrincipalDetails principalDetails,
@RequestParam(name = "northEastLat") Float northEastLat,
@RequestParam(name = "northEastLng") Float northEastLng,
@RequestParam(name = "southWestLat") Float southWestLat,
@RequestParam(name = "southWestLng") Float southWestLng,
@RequestParam(name = "workDateList", required = false) List<LocalDate> dateList,
@RequestParam(name = "scrap", required = false) Boolean scrap) {
List<JobPostMapResponse> jobPostsOnMap = jobPostWorkerService.findJobPostsOnMap(principalDetails.getMember().getId(), northEastLat, northEastLng, southWestLat, southWestLng, dateList, scrap);
return ResponseEntity.ok(new Response(jobPostsOnMap, "์ง๋์์ ๊ฒฝ๊ณ ์์ ์ํ ๋ชจ์ง ๊ณต๊ณ ์กฐํ ์๋ฃ"));
}
- Service
/**
* ๋ชจ์ง ๊ณต๊ณ ์ง๋์์ ์กฐํ
*/
@Transactional(readOnly = true)
public List<JobPostMapResponse> findJobPostsOnMap(Long workerId, Float northEastLat, Float northEastLng, Float southWestLat, Float southWestLng, List<LocalDate> dateList, Boolean scrap) {
Member worker = memberRepository.findById(workerId)
.orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));
return jobPostRepository.findJobPostOnMap(worker.getId(), northEastLat, northEastLng, southWestLat, southWestLng, dateList, scrap).stream()
.map(JobPostMapResponse::from)
.collect(Collectors.toList());
}
- Repository
@Override
public List<JobPost> findJobPostOnMap(Long memberId, Float northEastLat, Float northEastLng, Float southWestLat, Float southWestLng, List<LocalDate> dateList, Boolean scrap) {
return queryFactory
.selectFrom(jobPost)
.where(
jobPost.address.latitude.between(southWestLat, northEastLat).and(jobPost.address.longitude.between(southWestLng, northEastLng)),
eqWorkDate(dateList),
eqScrap(memberId, scrap)
)
.fetch();
}
swagger์์ ์๋, ๊ฒฝ๋ ์ขํ๋ฅผ ์ ๋ ฅํ๊ณ ํํฐ๋ง์ ๊ฑด ํ ์์ฒญํ๋ฉด ์๋์ ๊ฐ์ด ์ฟผ๋ฆฌ๊ฐ ์ ๋๊ฐ๋๊ฑธ ํ์ธํ ์ ์๋ค.
select
// ์๋ต
from
job_post j1_0
where
j1_0.latitude between 35.103577 and 35.126644
and j1_0.longitude between 128.89316 and 129.02708
and exists(select
1
from
work_date w1_0
where
w1_0.date in('2024-04-10T00:00:00.000+0900','2024-04-11T00:00:00.000+0900')
and j1_0.job_post_id=w1_0.job_post_id)