Search

[Applicaion]18.카카오 쇼핑 연동: kakao-BE

Publish Date
2024/11/28
Tags
Status
Done
1 more property
kakao-BE
쿠폰 서비스와 카카오 쇼핑 서비스의 연동을 위해 kakao-BE를 구축한다. 쿠폰 발급 요청 시 사용자 인증과 데이터 처리의 신뢰성을 확보한다.

배경 및 목표

쿠폰 시스템 프로젝트의 확장성을 높이고, 카카오 쇼핑 서비스와의 연동한다. 이를 통해 사용자 인증과 쿠폰 발급을 하나의 시스템에서 관리할 수 있으며, 사용자 이메일을 기반으로 userID를 조회하는 기능을 추가해 정확한 쿠폰 발급과 데이터 일관성을 보장한다.

kakaohop-BE

구조 및 구현

kakaoshop-BE ├── src/ │ ├── main/ │ │ ├── java/com/example/kakao/ │ │ │ ├── coupon/ │ │ │ │ ├── CouponController.java │ │ │ │ └── CouponRegisterRequest.java │ │ │ └── user/ │ │ │ ├── UserJPARepository.java │ │ │ ├── UserRestController.java │ │ │ └── UserService.java │ │ └── resources/ │ │ └── application-local.yml │ └── build.gradle
Java
복사
파일명
내용
application-local.yml
서버 포트와 MySQL 데이터베이스 설정, Hibernate JPA 설정, 로깅 설정 정의
CouponController.java
쿠폰 발급 요청 처리 및 백엔드 쿠폰 서비스 호출
CouponRegisterRequest.java
쿠폰 발급 요청 데이터를 담는 DTO 클래스
UserJPARepository.java
이메일 기반 사용자 조회를 위한 JPA Repository
UserRestController.java
사용자 로그인, 회원가입 및 사용자 ID 조회를 처리하는 컨트롤러
UserService.java
사용자 데이터 검증, ID 조회 및 비즈니스 로직 구현

소스코드 (쿠폰 서비스와 연결 된 부분 중심)

applicaion-local.yml
서버 포트, 데이터베이스 연결 설정 및 로깅 수준을 정의한다.
server: servlet: encoding: charset: utf-8 force: true port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/coupon driver-class-name: com.mysql.cj.jdbc.Driver username: abcd password: 1234 jpa: hibernate: ddl-auto: update show-sql: true logging: level: '[com.example.kakao]': DEBUG '[org.hibernate.type]': TRACE file: path: ./images/
SQL
복사
설정 항목
설명
server.port
서버가 실행될 포트 번호 (8080)
datasource.url
MySQL 데이터베이스 URL 및 인코딩 설정
jpa.ddl-auto
테이블 스키마 자동 업데이트 설정
logging.level
Hibernate SQL 및 애플리케이션 로그 출력 설정
CouponController.java
사용자 요청을 받아 쿠폰 백엔드 서비스로 전달한다.
package com.example.kakao.coupon; import com.example.kakao._core.security.CustomUserDetails; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.Map; @Slf4j @RestController @RequiredArgsConstructor @RequestMapping("/coupon") public class CouponController { private final RestTemplate client; private final String COUPON_BACKEND_URL = "http://localhost:8081"; // CHECK @PostMapping("/v1/issue") public ResponseEntity<?> registerCouponV1(@RequestBody CouponRegisterRequest request, @AuthenticationPrincipal CustomUserDetails userDetails) { request.setUserId((long) userDetails.getUser().getId()); log.info("/v1/issue: request[{}]", request); return ResponseEntity.ok(client.postForObject(COUPON_BACKEND_URL + "/v1/issue", request, Map.class)); } @PostMapping("/v2/issue-async") public ResponseEntity<?> registerCouponV3(@RequestBody CouponRegisterRequest request) { log.info("/v2/issue-async: request[{}]", request); return ResponseEntity.ok(client.postForObject(COUPON_BACKEND_URL + "/v2/issue-async", request, Map.class)); } }
Java
복사
기능
설명
POST 요청 처리
쿠폰 발급 요청을 쿠폰 백엔드로 전달
RestTemplate 사용
외부 API 요청을 통해 쿠폰 발급을 처리
유저 ID 주입
사용자 인증 정보를 통해 userId를 설정
CouponRegisterRequest.java
쿠폰 발급 요청 데이터를 저장하는 DTO이다.
package com.example.kakao.coupon; import lombok.Data; @Data public class CouponRegisterRequest { private Long userId; private Long couponId; }
Java
복사
필드
설명
userId
사용자 ID
couponId
발급할 쿠폰 ID
UserJPARepository.java
이메일을 통해 사용자 정보를 조회하는 JPA Repository이다.
package com.example.kakao.user; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.Optional; @Repository public interface UserJPARepository extends JpaRepository<User, Integer> { Optional<User> findByEmail(String email); // 반환 타입이 Optional<User> }
Java
복사
기능
설명
findByEmail
이메일을 기반으로 사용자 정보를 조회
UserRestController.java
로그인, 회원가입, 사용자 ID 조회 기능을 제공한다.
package com.example.kakao.user; import com.example.kakao._core.security.JWTProvider; import com.example.kakao._core.utils.ApiUtils; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.util.Map; @RequiredArgsConstructor @RestController public class UserRestController { private final UserService userService; // (기능3) 이메일 중복체크 @PostMapping("/check") public ResponseEntity<?> check(@RequestBody @Valid UserRequest.EmailCheckDTO emailCheckDTO, Errors errors) { userService.sameCheckEmail(emailCheckDTO.getEmail()); return ResponseEntity.ok(ApiUtils.success(null)); } // (기능4) 회원가입 @PostMapping("/join") public ResponseEntity<?> join(@RequestBody @Valid UserRequest.JoinDTO requestDTO, Errors errors) { userService.join(requestDTO); return ResponseEntity.ok().body(ApiUtils.success(null)); } // (기능5) 로그인 @PostMapping("/login") public ResponseEntity<?> login(@RequestBody @Valid UserRequest.LoginDTO requestDTO, Errors errors) { String jwt = userService.login(requestDTO); return ResponseEntity.ok().header(JWTProvider.HEADER, jwt).body(ApiUtils.success(null)); } // (추가) @PostMapping("/find-id") public ResponseEntity<?> findUserId(@RequestBody Map<String, String> request) { String email = request.get("email"); if (email == null || email.isEmpty()) { return ResponseEntity.badRequest().body("Email is required"); } Integer userId = userService.findUserIdByEmail(email); if (userId != null) { return ResponseEntity.ok(Map.of("userId", userId)); } else { return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User not found"); } } // 로그아웃 사용안함 - 프론트에서 JWT 토큰을 브라우저의 localstorage에서 삭제하면 됨. }
Java
복사
기능
설명
사용자 ID 조회
이메일 기반으로 사용자 ID를 반환
유효성 검증
이메일이 없을 경우 BAD_REQUEST 반환
UserService.java
사용자 데이터 검증 및 조회 로직을 처리한다.
package com.example.kakao.user; import com.example.kakao._core.errors.exception.Exception400; import com.example.kakao._core.errors.exception.Exception500; import com.example.kakao._core.security.JWTProvider; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Optional; @Transactional(readOnly = true) @RequiredArgsConstructor @Service public class UserService { private final PasswordEncoder passwordEncoder; private final UserJPARepository userJPARepository; @Transactional public void join(UserRequest.JoinDTO requestDTO) { sameCheckEmail(requestDTO.getEmail()); requestDTO.setPassword(passwordEncoder.encode(requestDTO.getPassword())); try { userJPARepository.save(requestDTO.toEntity()); } catch (Exception e) { throw new Exception500("unknown server error"); } } public String login(UserRequest.LoginDTO requestDTO) { User userPS = userJPARepository.findByEmail(requestDTO.getEmail()).orElseThrow( () -> new Exception400("이메일을 찾을 수 없습니다 : "+requestDTO.getEmail()) ); if(!passwordEncoder.matches(requestDTO.getPassword(), userPS.getPassword())){ throw new Exception400("패스워드가 잘못입력되었습니다"); } return JWTProvider.create(userPS); } public void sameCheckEmail(String email) { Optional<User> userOP = userJPARepository.findByEmail(email); if (userOP.isPresent()) { throw new Exception400("동일한 이메일이 존재합니다 : " + email); } } public Integer findUserIdByEmail(String email) { return userJPARepository.findByEmail(email) .map(User::getId) // 그대로 Integer로 반환 .orElse(null); } }
Java
복사
기능
설명
findUserIdByEmail
이메일을 통해 사용자 ID를 조회
Optional 처리
조회 결과가 없을 경우 null 반환 처리

결론

쿠폰 발급 요청 및 사용자 ID 조회를 위한 기능을 추가하여 카카오 쇼핑 서비스와 쿠폰 백엔드를 효과적으로 연동하였다. 이를 통해 사용자 데이터 검증 및 쿠폰 처리의 신뢰성과 안정성을 확보한다.
Search
Main PageCategoryTagskkogggokkAbout MeContact