Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ out/

### VS Code ###
.vscode/

### API ###
applicaiton-api.properties
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ dependencies {
// Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

//json
implementation group: 'org.json', name: 'json', version: '20210307'
//gson
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.0'

//Querydsl 추가
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/kcs/funding/fundingboost/api/common/Const.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kcs.funding.fundingboost.api.common;

public class Const {
public static final String POST = "POST";

public static final String GET = "GET";

public static final String EMPTY = "";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package kcs.funding.fundingboost.api.controller;

import kcs.funding.fundingboost.api.service.CustomMessageService;
import kcs.funding.fundingboost.api.service.KakaoService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.view.RedirectView;

@RestController
@RequiredArgsConstructor
public class KakaoContoller {

private final KakaoService kakaoService;

private final CustomMessageService customMessageService;

@RequestMapping("/login")
public RedirectView goKakaoOAuth() {
return kakaoService.goKakaoOAuth();
}

@RequestMapping("/login-callback")
public RedirectView loginCallback(@RequestParam("code") String code) {
return kakaoService.loginCallback(code);
}

@GetMapping("/profile")
public String getProfile() {
return kakaoService.getProfile();
}

@GetMapping("/friends")
public String getFriends() {
return kakaoService.getFriends();
}

@RequestMapping("/logout")
public String logout() {
return kakaoService.logout();
}

@GetMapping("/send/me")
public void sendMyMessage() {
customMessageService.sendReminderMessage();
}

@GetMapping("/send/friends")
public void sendMessageToFriends() {
customMessageService.sendMessageToFriends();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package kcs.funding.fundingboost.api.dto;


public record DefaultMessageDto(String objType, String text, String webUrl, String btnTitle) {
public static DefaultMessageDto createDefaultMessageDto(String objType, String text, String webUrl, String btn) {
return new DefaultMessageDto(objType, text, webUrl, btn);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package kcs.funding.fundingboost.api.service;

import java.util.Arrays;
import java.util.List;
import kcs.funding.fundingboost.api.dto.DefaultMessageDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class CustomMessageService {
private final MessageService messageService;

public boolean sendReminderMessage() {
DefaultMessageDto myMsg = DefaultMessageDto.createDefaultMessageDto("text", "바로 확인하기",
"https://www.naver.com", "펀딩 남은 기간이 2일 남았습니다!!");
String accessToken = HttpCallService.accessToken;
return messageService.sendMessageToMe(accessToken, myMsg);
}

public boolean sendMessageToFriends() {
DefaultMessageDto myMsg = DefaultMessageDto.createDefaultMessageDto("text", "버튼 버튼",
"https://www.naver.com", "내가 지금 생각하고 있는 것은??");
String accessToken = HttpCallService.accessToken;
List<String> friendUuids = Arrays.asList("친구의 UUID 여기에 추가"); // TODO: 실제로는 적절한 UUID 목록을 제공해야 합니다.
return messageService.sendMessageToFriends(accessToken, myMsg, friendUuids);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package kcs.funding.fundingboost.api.service;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

public class HttpCallService {
public static String accessToken;

public String CallwithToken(String method, String reqURL, String access_Token) {
String header = "Bearer " + access_Token;
accessToken = access_Token;
return Call(method, reqURL, header, null);
}

public String Call(String method, String reqURL, String header, String param) {
String result = "";
try {
String response = "";
URL url = new URL(reqURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(method);
conn.setRequestProperty("Authorization", header);
if (param != null) {
System.out.println("param : " + param);
conn.setDoOutput(true);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
bw.write(param);
bw.flush();

}
int responseCode = conn.getResponseCode();
System.out.println("responseCode : " + responseCode);

System.out.println("reqURL : " + reqURL);
System.out.println("method : " + method);
System.out.println("Authorization : " + header);
InputStream stream = conn.getErrorStream();
if (stream != null) {
try (Scanner scanner = new Scanner(stream)) {
scanner.useDelimiter("\\Z");
response = scanner.next();
}
System.out.println("error response : " + response);
}
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = "";
while ((line = br.readLine()) != null) {
result += line;
}
System.out.println("response body : " + result);

br.close();
} catch (IOException e) {
return e.getMessage();
}
return result;
}

/**
* Http 요청 클라이언트 객체 생성 method
*
* @ param Map<String,String> header HttpHeader 정보
* @ param Object params HttpBody 정보
* @ return HttpEntity 생성된 HttpClient객체 정보 반환
* @ exception 예외사항
*/
public HttpEntity<?> httpClientEntity(HttpHeaders header, Object params) {
HttpHeaders requestHeaders = header;

if (params == null || "".equals(params)) {
return new HttpEntity<>(requestHeaders);
} else {
return new HttpEntity<>(params, requestHeaders);
}
}

/**
* Http 요청 method
*
* @ param String url 요청 URL 정보
* @ param HttpMethod method 요청 Method 정보
* @ param HttpEntity<?> entity 요청 EntityClient 객체 정보
* @ return HttpEntity 생성된 HttpClient객체 정보 반환
*/
public ResponseEntity<String> httpRequest(String url, HttpMethod method, HttpEntity<?> entity) {
RestTemplate restTemplate = new RestTemplate();
return restTemplate.exchange(url, method, entity, String.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package kcs.funding.fundingboost.api.service;

import com.google.gson.JsonParser;
import jakarta.servlet.http.HttpSession;
import kcs.funding.fundingboost.api.common.Const;
import kcs.funding.fundingboost.api.transformer.Trans;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.view.RedirectView;

@RequiredArgsConstructor
@Service
public class KakaoService {

private final HttpSession httpSession;

private final HttpCallService httpCallService;

public static String token;

@Value("${rest-api-key}")
private String REST_API_KEY;

@Value("${redirect-uri}")
private String REDIRECT_URI;

@Value("${authorize-uri}")
private String AUTHORIZE_URI;

@Value("${token-uri}")
public String TOKEN_URI;

@Value("${client-secret}")
private String CLIENT_SECRET;

@Value("${kakao-api-host}")
private String KAKAO_API_HOST;


public RedirectView goKakaoOAuth() {
String uri = AUTHORIZE_URI + "?redirect_uri=" + REDIRECT_URI + "&response_type=code&client_id=" + REST_API_KEY;
if (!"".isEmpty()) {
uri += "&scope=" + "";
}
return new RedirectView(uri);
}

public RedirectView loginCallback(String code) {
String param = "grant_type=authorization_code&client_id=" + REST_API_KEY + "&redirect_uri=" + REDIRECT_URI
+ "&client_secret=" + CLIENT_SECRET + "&code=" + code;
String rtn = httpCallService.Call(Const.POST, TOKEN_URI, Const.EMPTY, param);
token = Trans.token(rtn, new JsonParser());
httpSession.setAttribute("token", token);

return new RedirectView("/index.html");
}

public String getProfile() {
String uri = KAKAO_API_HOST + "/v2/user/me";
return httpCallService.CallwithToken(Const.GET, uri, httpSession.getAttribute("token").toString());
}

public String getFriends() {
String uri = KAKAO_API_HOST + "/v1/api/talk/friends";
return httpCallService.CallwithToken(Const.GET, uri, httpSession.getAttribute("token").toString());
}

public String logout() {
String uri = KAKAO_API_HOST + "/v1/user/logout";
return httpCallService.CallwithToken(Const.POST, uri, httpSession.getAttribute("token").toString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package kcs.funding.fundingboost.api.service;

import java.util.List;
import kcs.funding.fundingboost.api.dto.DefaultMessageDto;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

@Service
@Slf4j
public class MessageService extends HttpCallService {
private static final String MSG_SEND_TO_ME_URL = "https://kapi.kakao.com/v2/api/talk/memo/default/send";
private static final String MSG_SEND_TO_FRIENDS_URL = "https://kapi.kakao.com/v1/api/talk/friends/message/default/send";
private static final String SEND_SUCCESS_MSG = "메시지 전송에 성공했습니다.";
private static final String SEND_FAIL_MSG = "메시지 전송에 실패했습니다.";

private static final String SUCCESS_CODE = "0"; //kakao api에서 return해주는 success code 값

public boolean sendMessageToMe(String accessToken, DefaultMessageDto msgDto) {
MultiValueMap<String, String> parameters = createMessageParameters(msgDto, null);
return sendMessage(MSG_SEND_TO_ME_URL, accessToken, parameters);
}

public boolean sendMessageToFriends(String accessToken, DefaultMessageDto msgDto, List<String> uuids) {
JSONArray receiverUuids = new JSONArray(uuids);
MultiValueMap<String, String> parameters = createMessageParameters(msgDto, receiverUuids.toString());
return sendMessage(MSG_SEND_TO_FRIENDS_URL, accessToken, parameters);
}

private MultiValueMap<String, String> createMessageParameters(DefaultMessageDto msgDto, String receiverUuids) {
JSONObject templateObj = createTemplateObject(msgDto);
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
parameters.add("template_object", templateObj.toString());
if (receiverUuids != null) {
parameters.add("receiver_uuids", receiverUuids);
}
return parameters;
}

private boolean sendMessage(String url, String accessToken, MultiValueMap<String, String> parameters) {
HttpHeaders headers = createHeaders(accessToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(parameters, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
return processResponse(response.getBody());
}

private HttpHeaders createHeaders(String accessToken) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.set("Authorization", "Bearer " + accessToken);
return headers;
}

private JSONObject createTemplateObject(DefaultMessageDto msgDto) {
JSONObject linkObj = new JSONObject();
linkObj.put("web_url", msgDto.webUrl());
JSONObject templateObj = new JSONObject();
templateObj.put("object_type", msgDto.objType());
templateObj.put("text", msgDto.text());
templateObj.put("link", linkObj);
templateObj.put("button_title", msgDto.btnTitle());
return templateObj;
}

private boolean processResponse(String responseBody) {
JSONObject jsonData = new JSONObject(responseBody);
String resultCode = jsonData.optString("result_code", "");
if (SUCCESS_CODE.equals(resultCode) || !jsonData.optString("successful_receiver_uuids", "").isEmpty()) {
log.info(SEND_SUCCESS_MSG);
return true;
} else {
log.debug(SEND_FAIL_MSG);
return false;
}
}
}
12 changes: 12 additions & 0 deletions src/main/java/kcs/funding/fundingboost/api/transformer/Trans.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package kcs.funding.fundingboost.api.transformer;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

public class Trans {

public static String token(String rtn, JsonParser parser) {
JsonElement element = parser.parse(rtn);
return element.getAsJsonObject().get("access_token").getAsString();
}
}
Loading