<?xml version="1.0" encoding="UTF-8"?><response><header><resultCode>30</resultCode><resultMsg>SERVICE KEY IS NOT REGISTERED ERROR.</resultMsg></header></response>
만약 계속해서 30번 에러가 발생한다면 2가지 상황을 의심해볼 수 있습니다.
1. api제공 업체의 문제 2. uri 호출 방식의 문제
1. 공공데이터포털에서 제공하는 "미리보기" 조차 불가능한 경우
만약 미리보기조차 불가능하다면 코드의 문제보다는 api 제공업체에 정상적으로 키가 등록되지 않은 경우입니다.
이건 Q&A 문의글을 남겨두면 간단히 해결됩니다. 대신 1~2일의 시간이 요소되기 때문에 다른 코드부터 짜고 계실 것을 추천드립니다.
실제로 저는 미리보기 조차 안되어서 문의글을 남겼더니 다음날 바로 해결해주셨습니다~ 홈페이지에서는 1~2시간 걸린다고 되어 있었는데 하루정도 소요됐네요 ㅎㅎ
2. uri 호출 방식의 문제
1) 인코딩 문제
restTemplate.getForObject(uri, String.class) 방식으로 api를 호출할 때, uri 부분에 String 또는 StringBuilder 데이터타입을 사용하셨나요...?
그럼 안됩니다!
URL에서 특수 문자는 특정 의미를 가지므로, 예를 들어, 공백()은 %20으로 변환되어야 하는데 String 형식으로 전송하면 공백문자가 %20로 변환되지 않기 때문입니다~
따라서 URLEncoder 또는 UriComponentsBuilder 를 사용해서 api를 호출해야 "쿼리 파라미터" 부분이 인코딩되어 HTTP 요청이 올바르게 처리됩니다!!
2) 예제코드
package org.dev2ne1.speedalertapi.service;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.IOException;
import java.net.URI;
@RequiredArgsConstructor
@Service
public class TrafficCameraService {
private final RestTemplate restTemplate;
@Value("${api.key}") // application.properties에서 api.key 값을 읽어옵니다.
private String apiKey;
// API Key 인코딩
String encodedApiKey = URLEncoder.encode(apiKey, StandardCharsets.UTF_8.toString());
// 기본 URL과 파라미터 설정
URI uri = UriComponentsBuilder.fromHttpUrl("http://api.data.go.kr/openapi/tn_pubr_public_unmanned_traffic_camera_api")
.queryParam("serviceKey", encodedApiKey)
.queryParam("pageNo", 1)
.queryParam("numOfRows", 100)
.queryParam("type", "xml")
.queryParam("latitude", latitude) // 위도
.queryParam("longitude", longitude) // 경도
.build(true) // true로 설정하면 자동 인코딩
.toUri();
System.out.println("Request URI: " + uri);
try {
// 요청 실행 및 결과 반환
return restTemplate.getForObject(uri, String.class);
} catch (Exception e) {
// 예외 처리
System.err.println("Error while fetching traffic camera data: " + e.getMessage());
throw new RuntimeException("Failed to fetch traffic camera data", e);
}
}
}
여러 개의 Docker 컨테이너들을 하나의 서비스로 정의하고 구성해 하나의 묶음으로 관리할 수 있는 것이다.
2. 도커 엔진만 설치해도 될까?
단일 컨테이너를 실행하거나 간단한 테스트만 할 때는 도커 엔진만 설치해도 된다. 예를 들어 백엔드 Springboot 컨테이너 하나 실행해서 서버 테스트만 해볼 때는 도커 컴포즈를 굳이 설치하지 않아도 된다.
3. 도커 컴포즈는 왜 설치해야 할까?
여러 컨테이너를 함께 실행하고, 이를 쉽게 관리하려는 경우에 도커 컴포즈를 설치해야 한다. 예를 들어, 웹 서버(Nginx), 데이터베이스(MySQL), 백엔드 서버(Spring Boot)를 한 번에 관리하고자 할 때는 도커 컴포즈를 설치하여 여러 개의 도커 컨테이너를 하나의 묶음으로 관리할 수 있다.
from collections import deque
# 1. 입력받기
n=int(input()) # 컴퓨터 개수
v=int(input()) # 연결선 개수
graph = [[] for i inrange(n+1)] # 그래프 초기화for i inrange(v): # 그래프 생성
a,b=map(int,input().split())
graph[a]+=[b] # a에 b 연결
graph[b]+=[a] # b에 a 연결 -> 양방향#print(graph)# 2. 노드 탐색 (bfs / 큐)
visited = [0] * (n+1) # 방문 여부 체크
visited[1]=1# 1번 컴퓨터부터 시작이니 방문 표시
Q=deque([1])
while Q:
c=Q.popleft() # 왼쪽에서 빼기for nx in graph[c]:
if visited[nx]==0:
Q.append(nx) #오른쪽에 추가
visited[nx]=1print(sum(visited)-1)
풀이 (dfs)
# 1. 입력받기
n = int(input())
v = int(input())
graph = [[] for i inrange(n+1)] # 그래프 초기화for i inrange(v):
a,b = map(int, input().split())
graph[a] += [b]
graph[b] += [a]
#print(graph)
visited = [0] * (n+1)
# 2. dfs 함수 구현 (재귀)defdfs(v):
visited[v]=1for nx in graph[v]:
if visited[nx]==0:
dfs(nx)
#print(f"v={v} | nx={nx} | {visited}")# 3. 노드 탐색 (dfs / 재귀)
dfs(1)
#print(visited)print(sum(visited) -1)
1. 리스트 0으로 초기화 : answer = [[0 for i in range(n)] for j in range(n)]
정답코드
defsolution(n):
answer = [[]]
answer = [[0for i inrange(n)] for j inrange(n)]
val = 0#우 하 좌 상
d = 0
dx = [0, 1, 0, -1] #행
dy = [1, 0, -1, 0] #열#현재 좌표
cur = [0,0]
while val < n*n:
#현재좌표 값 채우기
val += 1
answer[cur[0]][cur[1]] = val
#다음 좌표
x = cur[0] + dx[d]
y = cur[1] + dy[d]
next = [x, y]
#print(f"next={next}")#다음좌표값이 0보다 크면 방향 바꾸기#다음좌표가 맨끝이면 방향바꾸기 if (x>n-1or x<0or y>n-1or y<0) or answer[next[0]][next[1]] > 0:
if d < 3:
d += 1else:
d = 0#print(f"d={d}")#현재좌표를 다음 좌표로 바꾸기
x = cur[0] + dx[d]
y = cur[1] + dy[d]
next = [x, y]
cur = next#print(answer)return answer