์ด ๋ฌธ์ ํ๋๋ก ๋ค์ ์์ ์ ์ง์ ๊ตฌํํ ์ ์์ต๋๋ค:
[๋ด ์ ํ๋ฆฌ์ผ์ด์ > ํ๋ซํผ] > Web ํ๋ซํผ ์ถ๊ฐ
http://localhost:8090
http://192.168.16.11:8090
[์นด์นด์ค ๋ก๊ทธ์ธ > Redirect URI ๋ฑ๋ก]
http://192.168.16.11:8090/kakao/callback
[์นด์นด์ค ๋ก๊ทธ์ธ > ๋์ ํญ๋ชฉ] โ ํญ๋ชฉ ์ถ๊ฐ ํ โ์ด์ฉ ์คโ ์ค์
ํญ๋ชฉ ์ด๋ฆ | ID | ์ค๋ช |
---|---|---|
์นด์นด์คํก ๋ฉ์์ง ์ ์ก | talk_message | ์น๊ตฌ์๊ฒ ๋ฉ์์ง ์ ์ก |
์น๊ตฌ ๋ชฉ๋ก | friends | uuid, ๋๋ค์, ํ๋กํ ๋ฑ ์กฐํ |
๋ธ๋ผ์ฐ์ ์์ ์ธ๊ฐ์ฝ๋ ์์ฒญ โ ์ฝ๋ฐฑ์์ access_token ๋ฐ๊ธ
โ ์น๊ตฌ ๋ชฉ๋ก ์์ฒญ โ allowed_msg=true ํํฐ๋ง
โ ๋ฉ์์ง ํ
ํ๋ฆฟ ๊ตฌ์ฑ โ ์น๊ตฌ์๊ฒ ๋ฉ์์ง ์ ์ก
@RestController
@Slf4j
@RequestMapping("/kakao")
public class KakaoFriendMessageController {
private final String CLIENT_ID = "์นด์นด์ค REST API ํค";
private final String REDIRECT_URI = "http://192.168.16.11:8090/kakao/callback";
private KakaoTokenResponse kakaoTokenResponse;
private KakaoFriendsResponse kakaoFriendsResponse;
// STEP 1: ์ธ๊ฐ ์ฝ๋ ์์ฒญ URL
@GetMapping("/getCodeFriends")
public String getCodeFriends() {
return "redirect:https://kauth.kakao.com/oauth/authorize"
+ "?client_id=" + CLIENT_ID
+ "&redirect_uri=" + REDIRECT_URI
+ "&response_type=code"
+ "&scope=friends,talk_message"; // ์น๊ตฌ + ๋ฉ์์ง ๊ถํ ์์ฒญ
}
// STEP 2: access_token ๋ฐ๊ธ
@GetMapping("/callback")
public String callback(@RequestParam("code") String code) {
String url = "https://kauth.kakao.com/oauth/token";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code");
params.add("client_id", CLIENT_ID);
params.add("redirect_uri", REDIRECT_URI);
params.add("code", code);
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(params, headers);
RestTemplate rt = new RestTemplate();
ResponseEntity<KakaoTokenResponse> response = rt.exchange(url, HttpMethod.POST, entity, KakaoTokenResponse.class);
System.out.println("โ
AccessToken ์๋ต: " + response);
this.kakaoTokenResponse = response.getBody();
return "AccessToken ๋ฐ๊ธ ์๋ฃ!";
}
// STEP 3: ์น๊ตฌ ๋ชฉ๋ก ์์ฒญ
@GetMapping("/friends")
public String getFriends() {
String url = "https://kapi.kakao.com/v1/api/talk/friends";
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + kakaoTokenResponse.getAccess_token());
HttpEntity<?> entity = new HttpEntity<>(headers);
RestTemplate rt = new RestTemplate();
ResponseEntity<KakaoFriendsResponse> response = rt.exchange(url, HttpMethod.GET, entity, KakaoFriendsResponse.class);
System.out.println("๐ฅ ์น๊ตฌ ๋ชฉ๋ก ์๋ต: " + response);
this.kakaoFriendsResponse = response.getBody();
return "์น๊ตฌ ๋ชฉ๋ก ์กฐํ ์๋ฃ!";
}
// STEP 4: ์น๊ตฌ์๊ฒ ๋ฉ์์ง ์ ์ก
@GetMapping("/message/friends/{message}")
public String sendMessage(@PathVariable("message") String message) {
String url = "https://kapi.kakao.com/v1/api/talk/friends/message/send";
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + kakaoTokenResponse.getAccess_token());
headers.add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
// allowed_msg = true์ธ ์น๊ตฌ๋ง ์ถ์ถ
JSONArray uuids = new JSONArray();
for (Element friend : kakaoFriendsResponse.getElements()) {
if (friend.isAllowed_msg()) {
uuids.add(friend.getUuid());
}
}
// ํ
ํ๋ฆฟ ๋ฉ์์ง ๊ตฌ์ฑ
JSONObject template = new JSONObject();
template.put("object_type", "text");
template.put("text", message);
template.put("link", new JSONObject()); // ํ์ ๊ตฌ์กฐ
template.put("button_title", ""); // ๋ฒํผ ์์
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("template_object", template.toString());
params.add("receiver_uuids", uuids.toString());
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(params, headers);
RestTemplate rt = new RestTemplate();
ResponseEntity<String> response = rt.exchange(url, HttpMethod.POST, entity, String.class);
System.out.println("๐จ ๋ฉ์์ง ์ ์ก ์๋ต: " + response);
return "์น๊ตฌ์๊ฒ ๋ฉ์์ง ์ ์ก ์๋ฃ!";
}
// Kakao AccessToken DTO
@Data
private static class KakaoTokenResponse {
private String access_token;
private String token_type;
private String refresh_token;
private int expires_in;
private String scope;
private int refresh_token_expires_in;
}
// Kakao ์น๊ตฌ ๋ชฉ๋ก DTO
@Data
private static class Element {
private String profile_nickname;
private String profile_thumbnail_image;
private boolean allowed_msg;
private Object id;
private String uuid;
private boolean favorite;
}
@Data
private static class KakaoFriendsResponse {
private ArrayList<Element> elements;
private int total_count;
private Object after_url;
private int favorite_count;
}
}
ํญ๋ชฉ | ์ค๋ช |
---|---|
โ ํ ํ๋ฆฟ ๋ฉ์์ง ์ ์ฉ | ์น๊ตฌ์๊ฒ๋ ์์ ํ ์คํธ ์ ์ก ๋ถ๊ฐ โ ๋ฐ๋์ template_object ์ฌ์ฉ |
โ allowed_msg ํํฐ๋ง | ์น๊ตฌ ๋ชฉ๋ก ์ค ๋ฉ์์ง ์์ ๋์ํ ์ฌ๋๋ง ๊ฐ๋ฅ |
โ ํ์ ๊ฐ ํ ์คํธ ์ ์ฉ | ์ฑ ํ์์ผ๋ก ๋ฑ๋ก๋ ์ฌ๋๋ผ๋ฆฌ๋ง ๋ฉ์์ง ์ฃผ๊ณ ๋ฐ์ ์ ์์ |
โ ๏ธ ๋ก๊ทธ์ ์๋ต ์ถ๋ ฅ | ์ค์ต ์ค์ด๋ผ๋ฉด ๋ฐ๋์ System.out.println(...)์ผ๋ก ์๋ต ํ์ธํด์ผ ํจ |