Skip to content

Commit

Permalink
Merge pull request #24 from f-lab-edu/develop
Browse files Browse the repository at this point in the history
PostGIS 연동 및 테스트
  • Loading branch information
electronyoon authored Jan 29, 2025
2 parents 3686356 + c76980d commit 9f8db75
Show file tree
Hide file tree
Showing 12 changed files with 288 additions and 2 deletions.
2 changes: 2 additions & 0 deletions zipsoonapp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ dependencies {
// Development Tools
compileOnly 'org.projectlombok:lombok:1.18.36'
annotationProcessor 'org.projectlombok:lombok:1.18.36'
testCompileOnly 'org.projectlombok:lombok:1.18.36'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.36'
developmentOnly 'org.springframework.boot:spring-boot-devtools:3.4.2'
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.zipsoon.zipsoonapp.config.jackson;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties({"firstPoint", "lastPoint"})
public abstract class PointMixin {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.zipsoon.zipsoonapp.config.typehandler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;

import java.sql.*;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

@MappedTypes(LocalDateTime.class)
public class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, LocalDateTime parameter, JdbcType jdbcType) throws SQLException {
ps.setTimestamp(i, Timestamp.from(parameter.toInstant(ZoneOffset.UTC)));
}

@Override
public LocalDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {
Timestamp timestamp = rs.getTimestamp(columnName);
return timestamp != null ? timestamp.toLocalDateTime() : null;
}

@Override
public LocalDateTime getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
Timestamp timestamp = rs.getTimestamp(columnIndex);
return timestamp != null ? timestamp.toLocalDateTime() : null;
}

@Override
public LocalDateTime getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
Timestamp timestamp = cs.getTimestamp(columnIndex);
return timestamp != null ? timestamp.toLocalDateTime() : null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.zipsoon.zipsoonapp.config.typehandler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import org.postgis.PGgeometry;
import org.postgis.Point;

import java.sql.*;

@MappedTypes(Point.class)
public class PointTypeHandler extends BaseTypeHandler<Point> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Point parameter, JdbcType jdbcType)
throws SQLException {
String pointWkt = String.format("POINT(%f %f)", parameter.getX(), parameter.getY());
ps.setObject(i, pointWkt, Types.OTHER);
}

@Override
public Point getNullableResult(ResultSet rs, String columnName) throws SQLException {
PGgeometry geometry = (PGgeometry) rs.getObject(columnName);
return geometry != null ? convertToPoint(geometry) : null;
}

@Override
public Point getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
PGgeometry geometry = (PGgeometry) rs.getObject(columnIndex);
return geometry != null ? convertToPoint(geometry) : null;
}

@Override
public Point getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
PGgeometry geometry = (PGgeometry) cs.getObject(columnIndex);
return geometry != null ? convertToPoint(geometry) : null;
}

private Point convertToPoint(PGgeometry geometry) {
org.postgis.Point pgPoint = (org.postgis.Point) geometry.getGeometry();
return new Point(pgPoint.x, pgPoint.y);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.zipsoon.zipsoonapp.domain;

public enum PlatformType {
NAVER("네이버부동산");

private final String description;

PlatformType(String description) {
this.description = description;
}

public String getDescription() {
return description;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.zipsoon.zipsoonapp.domain;

import lombok.*;
import org.postgis.Point;

import java.time.LocalDateTime;

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Property {
private Long id;
private PlatformType platformType;
private String platformId;
private String articleName;
private String articleStatus;
private String realEstateTypeCode;
private String realEstateTypeName;
private String articleRealEstateTypeCode;
private String articleRealEstateTypeName;
private String tradeTypeCode;
private String tradeTypeName;
private String verificationTypeCode;
private String floorInfo;
private String priceChangeState;
private boolean isPriceModification;
private String price;
private String rentPrc;
private String dealOrWarrantPrc;
private String areaName;
private Double area1;
private Double area2;
private String direction;
private String articleConfirmYmd;
private String representativeImgUrl;
private String articleFeatureDesc;
private String[] tags;
private String buildingName;
private Integer sameAddrCnt;
private Integer sameAddrDirectCnt;
private String sameAddrMaxPrc;
private String sameAddrMinPrc;
private String cpid;
private String cpName;
private String cpPcArticleUrl;
private String cpPcArticleBridgeUrl;
private Boolean cpPcArticleLinkUseAtArticleTitleYn;
private Boolean cpPcArticleLinkUseAtCpNameYn;
private String cpMobileArticleUrl;
private Boolean cpMobileArticleLinkUseAtArticleTitleYn;
private Boolean cpMobileArticleLinkUseAtCpNameYn;
private Boolean isLocationShow;
private String realtorName;
private String realtorId;
private Boolean tradeCheckedByOwner;
private Boolean isDirectTrade;
private Boolean isInterest;
private Boolean isComplex;
private String detailAddress;
private String detailAddressYn;
private String virtualAddressYn;
private Boolean isVrExposed;
private Point location;
private PropertyStatusType status;
private LocalDateTime lastChecked;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private LocalDateTime deletedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.zipsoon.zipsoonapp.domain;

public enum PropertyStatusType {
ACTIVE("활성"),
DELETED("삭제됨");

private final String description;

PropertyStatusType(String description) {
this.description = description;
}

public String getDescription() {
return description;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.zipsoon.zipsoonapp.repository;

import com.zipsoon.zipsoonapp.domain.Property;
import com.zipsoon.zipsoonapp.repository.mapper.PropertyMapper;
import lombok.RequiredArgsConstructor;
import org.postgis.Point;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class PropertyRepository {
private final PropertyMapper propertyMapper;

public List<Property> findPropertiesWithinDistance(Point coord, int radius) {
return propertyMapper.findPropertiesWithinDistance(coord, radius);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.zipsoon.zipsoonapp.repository.mapper;

import com.zipsoon.zipsoonapp.domain.Property;
import org.apache.ibatis.annotations.Mapper;
import org.postgis.Point;

import java.util.List;

@Mapper
public interface PropertyMapper {
List<Property> findPropertiesWithinDistance(Point coord, int radius);
}
6 changes: 4 additions & 2 deletions zipsoonapp/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
spring:
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/testdbapp
url: jdbc:postgresql://localhost:5432/testdbbatch
username: postgres
password: postgres

mybatis:
mapper-locations: classpath:mapper/**/*.xml
configuration:
map-underscore-to-camel-case: true
map-underscore-to-camel-case: true
type-handlers-package: com.zipsoon.zipsoonapp.config.typehandler
# type-aliases-package: com.zipsoon.zipsoonapp.domain
21 changes: 21 additions & 0 deletions zipsoonapp/src/main/resources/mapper/PropertyMapper.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.zipsoon.zipsoonapp.repository.mapper.PropertyMapper">
<select id="findPropertiesWithinDistance" resultType="com.zipsoon.zipsoonapp.domain.Property">
SELECT
p.*,
ST_Distance(
p.location::geography,
ST_SetSRID(ST_MakePoint(#{coord.x}, #{coord.y}), 4326)::geography
) as distance
FROM property p
WHERE ST_DWithin(
p.location::geography,
ST_SetSRID(ST_MakePoint(#{coord.x}, #{coord.y}), 4326)::geography,
#{radius}
)
ORDER BY distance
</select>
</mapper>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.zipsoon.zipsoonapp;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.zipsoon.zipsoonapp.config.jackson.PointMixin;
import com.zipsoon.zipsoonapp.domain.Property;
import com.zipsoon.zipsoonapp.repository.mapper.PropertyMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.postgis.Point;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@Slf4j
@SpringBootTest
class PostGISConfigurationTest {
@Autowired
private PropertyMapper propertyMapper;

private final ObjectMapper objectMapper = new ObjectMapper()
.enable(SerializationFeature.INDENT_OUTPUT)
.addMixIn(org.postgis.Point.class, PointMixin.class)
.registerModule(new JavaTimeModule());

@Test
void shouldHandleGeometryType() throws JsonProcessingException {
Point coord = new Point(126.96, 37.572); // 독립문역 사거리
int radius = 100; // 미터

List<Property> properties = propertyMapper.findPropertiesWithinDistance(coord, radius);

String prettyJson = objectMapper.writeValueAsString(properties);
log.info("Properties within {}m of ({}, {}): total {} found\n{}", radius, coord.getX(), coord.getY(), properties.size(), prettyJson);

assertThat(properties).isNotNull();
}
}

0 comments on commit 9f8db75

Please sign in to comment.