TouristController.java
@Controller
@RequestMapping("/tourist")
@RequiredArgsConstructor
public class TouristController {
// Integer area : 지역 코드
// Integer contentTypeId : 관광지 타입
// String keyword : 검색어
// Integer pageNo : 요청한 페이지 번호
@GetMapping("/list/{pageNo}")
public String touristList(
@RequestParam(required = false) Integer area,
@RequestParam(required = false) Integer contentTypeId ,
@RequestParam(required = false) String keyword,
@PathVariable(required = false) Integer pageNo,
Model model) throws IOException {
TouristListDTO board = dataPortalService.findAll(area, contentTypeId, keyword, pageNo);
List<TouristItemDTO> items = board.getList();
//.. 페이징 처리를 위한 과정 - 코드 생략
model.addAttribute("items", items);
return "tourist/touristList";
}
}
DataPortalService.java
@Service
@RequiredArgsConstructor
public class DataPortalService {
public TouristListDTO findAll(Integer area, Integer contentTypeId , String keyword, Integer pageNo) throws IOException{
return dataPortalRequest.searchKeyword(area, contentTypeId ,keyword, pageNo);
}
}
application.properties
공공데이터 포털의 URL 주소와 인증 키를 설정 파일에 저장한다.
public-data.korservice.key.encoding=ke9Ra%...
public-data.korservice.url.keyword=https://apis.data.go.kr/B551011/KorService1/searchKeyword1
DataPortalRequest.java
// `@Value`은 `String` 멤버 변수 위에 선언하여 설정 파일에 저장된 값을 멤버 변수에 할당시킨다.
@Value("${public-data.korservice.key.encoding}")
private String serviceKey;
@Value("${public-data.korservice.url.keyword}")
private String searchKeywordURL;
@Component
public class DataPortalRequest {
public TouristListDTO searchKeyword(Integer area, Integer contentTypeId ,String keyword, int pageNo) throws IOException{
// UriComponentsBuilder URI의 쿼리 스트링을 구성해주는 객체이다.
UriComponentsBuilder uriBuilder = UriComponentsBuilder
.fromUriString(searchKeywordURL)
.queryParam("serviceKey", serviceKey)
.queryParam("keyword", keyword)
.queryParam("MobileOS", "ETC")
.queryParam("MobileApp", "AppTest")
.queryParam("_type", "json")
.queryParam("numOfRows", numOfRows)
.queryParam("pageNo", pageNo)
;
if(area != null) uriBuilder.queryParam("areaCode", area); // 지역 코드
if(contentTypeId != null) uriBuilder.queryParam("contentTypeId", contentTypeId); // 관광 코드
/* HttpURLConnection 공공데이터 포털에 요청(Request)할 수 있는 객체.
* openConnection() 메서드로 공공 데이터에 요청을 보낸다.
*/
URL url = new URL(uriBuilder.build().toUriString())
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// conn.getInputStream() 메서드를 호출하고 Response 결과 값을 스트림으로 읽어내고 스프링 빌더로 문자열로 담아내는 과정이 필요. - 코드는 생략됨.
String responseBody = stringBuilder.toString();
// ObjectMapper 객체를 Json 형식으로 또는 Json을 객체로 변환해주는 객체.
ObjectMapper mapper = new ObjectMapper();
String findInfo = mapper.readTree(responseBody).findPath("body").toString();
// Json 형식으로 된 문자열을 객체로 변환해주는 메소드
return mapper.readValue(findInfo, TouristListDTO.class); // 변환된 객체의 타입 TouristListDTO
}
}
## 📜`TouristListDTO.java`
```java
// DataPortalRequest.java에서 Json에서 자바 객체로 변환된 객체.
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter @ToString @NoArgsConstructor
public class TouristListDTO {
// 페이징 처리 시 필요한 멤버 변수
private int numOfRows;
private int pageNo;
private int totalCount;
/* 관광지 게시판 목록
파싱하기 위해 내부 클래스를 선언함.
*/
@JsonProperty(value = "items")
@Getter(lombok.AccessLevel.NONE)
private TouristItems items;
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter @ToString @NoArgsConstructor
class TouristItems{
@JsonProperty(value = "item")
private List<TouristItemDTO> list;
}
public List<TouristItemDTO> getList(){
return items.getList();
}
}
TouristController.java
public class TouristController {
@GetMapping("/detail/{contentId}")
public String touristDetail(@PathVariable("contentId") Long contentId, Model model,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : #this") MemberDetails memberDetails)
throws IOException {
// contentId : 공공 데이터 관광지의 고유 번호(ID)
// 공공데이터 포털에서 상세 내용 요청
TouristDTO touristDTO = dataPortalService.findOne(contentId);
// DB 처리 - 저장또는 조회
// 공공데이터의 모든 데이터를 전부 db에 넣을 수 없기 때문에, 얼마나 있는 지 모르고 너무 많기 때문..
Board board = boardService.findOne(contentId, touristDTO);
// 좋아요 처리
// 북마크 처리
// 댓글
model.addAttribute("item", touristDTO);
return "tourist/touristDetail";
}
}
BoardService.java
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class BoardService {
@Transactional
public Board findOne(Long contentId, TouristDTO touristDTO) {
Board board = findOne(contentId);
// 조회가 되면 그대로 쓰고, 조회가 안되면 새로 만든다.
// 댓글과 좋아요, 북마크와 연관 짓기 위해서..
if(board == null){
board = new Board();
Tourist tourist = Tourist.builder()
.contentId(contentId)
.title(touristDTO.getTitle())
.address(touristDTO.getAddress1())
.image(touristDTO.getImage1())
.build();
board.setTourist(tourist);
boarderRepository.save(board);
}
return boarderRepository.findByContentId(contentId);
}
}
BoarderRepository.java
public interface BoarderRepository extends JpaRepository<Board, Long> {
@Query("SELECT b FROM Board b WHERE b.tourist.contentId = :contentId")
public Board findByContentId(@Param("contentId") Long contentId);
public Board findBoardById(Long contentId);
}
이런 형태로 가져와봤다.