토스페이먼츠
PG : 여러 카드사의 서비스를 아우르는 서비스, 각 카드사의 api를 하나하나 따올 필요가 없게 해준다.
토스페이먼츠는 이러한 PG 중 하나다.
예시
var clientKey = 'test_ck_jkYG57Eba3GwB6eY1dQ3pWDOxmA1';
var tossPayments = TossPayments(clientKey);
var button = document.getElementById('payment-button'); // 결제하기 버튼
button.addEventListener('click', function () {
tossPayments.requestPayment('카드', {
amount: 15000,
orderId: 'Qvz6OPnQ8a22cDm0fxUer',
orderName: '토스 티셔츠 외 2건',
customerName: '박토스',
successUrl: 'http://localhost:8080/success',
failUrl: 'http://localhost:8080/fail',
})
});
이렇게 자바스크립트로 결제정보를 넘기게 된다.
위험하진 않나? => 토스페이먼츠에서 다시한번 백엔드 서비스에 검증을 요청하기 때문에 결제정보 변조의 위험으로부터 안전하다.
requestPayment
의 인자에 "계좌이체"를 넣어주면 됨.
이러한 정보는 토스페이먼츠 문서에 자세히 나와있다.
토스페이먼츠-공식문서(결제정보)
클라이언트 코드: 결제를 기획
시크릿 코드: 결제를 승인
백엔드 서버에서 클라이언트로부터의 클라이언트 키에 클라이언트 시크릿을 덧붙혀서 토스 서버로 보낸다.
자바스크립트로부터의 데이터는 너무나도 쉽게 데이터조작이 가능하다.
따라서 해당 결제 데이터가 상점서비스의 데이터와 일치하는지 유효성 검사를 한 후에 토스 api를 호출해야 한다.
컨트롤러에서 이런식으로 검증을 하게 된다.
@GetMapping(value = "success")
public String paymentResult(
Model model,
@RequestParam(value = "orderId") String orderId,
@RequestParam(value = "amount") Integer amount,
@RequestParam(value = "paymentKey") String paymentKey) throws Exception {
// 상품이 50000원이었는데 프론트에서 가격을 조작했을 때 이에 대한 검증로직
if (orderId.startsWith("sample-") && amount != 50000) {
throw new Exception("해킹의심");
}
...
TDD로 알고리즘문제 풀기
@Test
@DisplayName("100, 100, {10} -> 101")
void test1() {
assertThat(s.solution(100, 100, new int[]{10})).isEqualTo(10);
}
class Solution {
public int solution(int bridge_length, int weight, int[] truck_weights){
return 101;
}
}
@Test
@DisplayName("100, 100, {10,10,10,10,10,10,10,10,10,10} → 110")
void test2() {
assertThat(s.solution(100, 100, new int[]{10, 10, 10, 10, 10, 10, 10, 10, 10, 10})).isEqualTo(110);
}
class Solution {
public int solution(int bridge_length, int weight, int[] truck_weights){
return bridge_length + truck_weights.length;
}
}
TDD없이 푼 코드
class Solution {
public int solution(int bridge_length, int weight, int[] truck_weights) {
Queue<int[]> Q = new LinkedList<>();
int latency;
int popCount = 0;
int nextIdx = 0;
for (latency = 1; popCount < truck_weights.length; latency++) {
if (!Q.isEmpty() && latency - Q.peek()[1] >= bridge_length) {
weight += Q.poll()[0];
popCount++;
}
if (popCount == truck_weights.length) {
return latency;
}
else if (Q.size() < bridge_length && nextIdx < truck_weights.length && weight - truck_weights[nextIdx] >= 0) {
Q.offer(new int[]{truck_weights[nextIdx], latency});
weight -= truck_weights[nextIdx++];
}
}
return latency;
}
}