api의 데이터를 db에 저장하기 위해 코드를 작성해야 한다
저장하는 과정에서 JPA를 사용하기 위해
Mountain 패키지에 MountainEntity와 MountainRepository를 생성했다
그 다음
ApiParseExplorer.java
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class ApiParseExplorer {
@Autowired
private MountainRepository mountainRepository;
@GetMapping("/mountain-info")
public void saveMountainData() throws IOException {
// 중간 생략
String mtName = temp.has("frtrlNm") ? temp.get("frtrlNm").getAsString() : "";
String mtLocation = temp.has("addrNm") ? temp.get("addrNm").getAsString() : "";
int mtHeight = temp.has("aslAltide") ? temp.get("aslAltide").getAsInt() : 0;
double mtLot = temp.has("mtLot") ? temp.get("mtLot").getAsDouble() : 0;
double mtLat = temp.has("mtLat") ? temp.get("mtLat").getAsDouble() : 0;
MountainEntity mountainEntity = MountainEntity.builder()
.mtName(mtName)
.mtLocation(mtLocation)
.mtHeight(mtHeight)
.mtLot(mtLot)
.mtLat(mtLat)
.build();
mountainRepository.save(mountainEntity);
}
}
}
}
저장해주는 코드로 수정, 추가 했다
MountainEntity.java
@ToString
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name = "mountain")
@Entity
public class MountainEntity {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name = "mtName")
private String mtName;
@Column(name = "mtMap")
private String mtMap;
@Column(name = "mtLocation")
private String mtLocation;
@Column(name = "mtHeight")
private int mtHeight;
@Column(name = "mtLot")
private double mtLot;
@Column(name = "mtLat")
private double mtLat;
@UpdateTimestamp
@Column(name = "createdAt", updatable = false)
private ZonedDateTime createdAt;
@UpdateTimestamp
@Column(name = "updatedAt")
private ZonedDateTime updatedAt;
}
MountainRepository.java
@Repository
public interface MountainRepository extends JpaRepository<MountainEntity, Integer> {
}
이렇게 작성 한 다음 실행 해봤더니

could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
500 에러가 발생했다.
찾아보니 테이블의 컬럼을 추가하려고 했을 때 외래키의 무결성 계약조건에 위배되어 발생한 오류라고 한다
에러 로그를 보면 ConstraintViolationException: 제약조건 위반 예외 이다
SQL을 공부할 때 제약조건을 걸어주는 이유가 무결성을 지키기 위해서라고 배운 기억이 있다
ConstraintViolationException: 에는 다양한 에러들이 있었는데
그래서 테이블을 자세히 보다가 mtHeight의 자료형이 int인것을 발견했다
고도는 "aslAltide": 1051.0, 이런식의 데이터이기 때문에 혹시 이 자료형 문제인가 싶어서 double로 변경했다 근데 에러는 그대로 였다..
console을 보니
Hibernate:
insert
into
mountain
(createdAt, mtHeight, mtLat, mtLocation, mtLot, mtMap, mtName, updatedAt)
values
(?, ?, ?, ?, ?, ?, ?, ?)
2024-02-01 18:37:16,542 INFO [p6spy] #1706780236542 | took 0ms | statement | connection 2| url jdbc:mysql://localhost:3306/mountain?characterEncoding=UTF-8
insert into mountain (createdAt, mtHeight, mtLat, mtLocation, mtLot, mtMap, mtName, updatedAt) values (?, ?, ?, ?, ?, ?, ?, ?)
insert into mountain (createdAt, mtHeight, mtLat, mtLocation, mtLot, mtMap, mtName, updatedAt) values ('2024-02-01T18:37:16.541+0900', 1051.0, 0.0, '강원도 춘천시 북산면ㆍ동면, 홍천군 두촌면ㆍ화촌면', 0.0, NULL, '가리산', '2024-02-01T18:37:16.541+0900');
2024-02-01 18:37:16,543 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] SQL Error: 1048, SQLState: 23000
2024-02-01 18:37:16,543 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] Column 'mtMap' cannot be null
2024-02-01 18:37:16,543 INFO [p6spy] #1706780236543 | took 0ms | rollback | connection 2| url jdbc:mysql://localhost:3306/mountain?characterEncoding=UTF-8
;
2024-02-01 18:37:16,544 ERROR [org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet]] Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
java.sql.SQLIntegrityConstraintViolationException: Column 'mtMap' cannot be null
프로젝트 초기에 map api 적용 방법을 아예 모를 때
mountain 테이블을 만들면서 mtMap이라는 컬럼도 만들었었는데..
아무 생각 없이 수정을 하지 않았다
kakao map을 사용할 때는 위도와 경도만 있으면 되는데
결국 db에 insert할 때 mtMap에 왜 아무 값도 안줘? 라는 에러였다
sql의 테이블도 수정하고, mountain의 domain, entity, mountainMapper.xml까지 잘 수정 해준 뒤에 수행 했더니
Hibernate:
insert
into
mountain
(createdAt, mtHeight, mtLat, mtLocation, mtLot, mtName, updatedAt)
values
(?, ?, ?, ?, ?, ?, ?)
2024-02-01 18:54:23,953 INFO [p6spy] #1706781263953 | took 0ms | statement | connection 1| url jdbc:mysql://localhost:3306/mountain?characterEncoding=UTF-8
insert into mountain (createdAt, mtHeight, mtLat, mtLocation, mtLot, mtName, updatedAt) values (?, ?, ?, ?, ?, ?, ?)
insert into mountain (createdAt, mtHeight, mtLat, mtLocation, mtLot, mtName, updatedAt) values ('2024-02-01T18:54:23.952+0900', 629.0, 0.0, '서울특별시 관악구, 경기도 안양시, 과천시', 0.0, '관악산', '2024-02-01T18:54:23.952+0900');
2024-02-01 18:54:23,954 INFO [p6spy] #1706781263954 | took 0ms | commit | connection 1| url jdbc:mysql://localhost:3306/mountain?characterEncoding=UTF-8
;
콘솔에 이런식으로 찍히면서

테이블에서 저장이 되었다
그런데 위도와 경도가 안찍혀서 자세히 보니까 자료형이 double이 되면 안되는거였다
다시 double을 decimal로 수정하고

MountainEntity.java
@Column(name = "mtLot", precision =13, scale = 10) //13자리 중 소수점아래가 10자리까지 확보되었다
private BigDecimal mtLot;
@Column(name = "mtLat", precision =13, scale = 10)
private BigDecimal mtLat;
ApiParseExplorer.java
BigDecimal mtLot = temp.has("mtLot") ? temp.get("mtLat").getAsBigDecimal() : BigDecimal.ZERO;
BigDecimal mtLat = temp.has("mtLat") ? temp.get("mtLat").getAsBigDecimal() : BigDecimal.ZERO;
실행했더니 이번에는 소수점은 보이는데 또 데이터가 제대로 저장이 안됐다

뭐가 문제일까 고민하다가 오타를 발견했다
위의 코드에서 api에서의 값을 잘못 입력해놨다
ApiParseExplorer.java
BigDecimal mtLot = temp.has("lot") ? temp.get("lot").getAsBigDecimal() : BigDecimal.ZERO;
BigDecimal mtLat = temp.has("lat") ? temp.get("lat").getAsBigDecimal() : BigDecimal.ZERO;
수정을 한 뒤 다시 실행했더니

이번에는 모든 값이 다 잘 저장되었다.. !!!
open api에 대해서 하나도 모르는 상태로 구현을 시작하면서
1~2주 정도의 시간을 잡았는데 총 3주가 걸렸다 ㅎㅎ..
외부의 api를 가져와서 내 프로젝트에 적용시킨다는게 참 어려워보이고 막막했는데 검색하고 검색하면서 한단계씩 해냈다는게 뿌듯하다
api 다루는것에 좀더 자신감이 생겼고 앞으로 속도를 더 내서 나머지 기능들도 구현해봐야겠다