55. [ JAVA ] API 문서 문제 : JWT(Json Web Token)(보안) / Admin(2)
문제
어드민 API 명세서
3. 상위 리뷰어 목록
서비스의 핵심 사용자인 상위 리뷰어들의 정보를 제공합니다. 리뷰어 수(size)를 쿼리파라미터로 보냅니다.
설명
- 리뷰 작성 수 기준으로 상위 사용자들을 식별합니다.
- 각 리뷰어의 평균 평점과 최근 활동 정보를 함께 제공합니다.
- 이 데이터를 통해 서비스의 핵심 사용자들의 특성을 파악할 수 있습니다.
활용 방안
- VIP 사용자 관리
- 우수 리뷰어 보상 프로그램 운영
- 인플루언서 마케팅 대상 선정
- URL: /api/v1/admin/crm/users/top-reviewers?size=5
- Method: GET
- 헤더에 토큰 필수
- Response 예시와 설명:
{
"topReviewers": [
{
"userId": 3,
"nickname": "맛있는생활",
"reviewCount": 50, // 전체 리뷰 작성 수
"averageRating": 4.2, // 평균 평점
"lastReviewDate": "2024-02-27" // 최근 리뷰 작성일
},
{
"userId": 21,
"nickname": "리뷰짱",
"reviewCount": 39, // 전체 리뷰 작성 수
"averageRating": 3.8, // 평균 평점
"lastReviewDate": "2024-02-21" // 최근 리뷰 작성일
}
]
}
2. 기간별 리뷰 통계
지정된 기간 동안의 리뷰 작성 현황과 평점을 분석합니다.
설명
- 일자별, 카테고리별 리뷰 작성 추이를 파악할 수 있습니다.
- 전체 평균 평점과 카테고리별 평균 평점을 비교할 수 있습니다.
- 특정 기간의 리뷰 트렌드를 분석할 수 있습니다.
활용 방안
- 서비스 성과 모니터링
- 카테고리별 인기도 분석
- 시즌별 트렌드 파악
- URL: /api/v1/admin/crm/reviews/stats
- Method: GET
- 헤더에 토큰 필수
- Query Parameters:
startDate: 조회 시작일 (필수)
endDate: 조회 종료일 (필수)
- Response:
{
"total": {
"reviewCount": 1000,
"averageRating": 4.3
},
"byDate": [
{
"date": "2024-02-27",
"reviewCount": 50,
"averageRating": 4.2
},
{
"date": "2024-02-28",
"reviewCount": 32,
"averageRating": 4.4
}
],
"byCategory": [
{
"category": "한식",
"reviewCount": 400,
"averageRating": 4.4
},
{
"category": "중식",
"reviewCount": 500,
"averageRating": 4.1
}
]
}
5. 인기 음식점 통계
리뷰 수와 평점을 기준으로 인기 음식점을 분석합니다.
설명
- 리뷰 수와 평점을 기준으로 인기 음식점을 식별합니다.
- 카테고리별 통계를 통해 각 분야의 인기 업체를 파악할 수 있습니다.
- 최근 리뷰 일자를 통해 지속적인 인기도를 확인할 수 있습니다.
활용 방안
- 추천 음식점 선정
- 카테고리별 벤치마킹 업체 선정
- 우수 음식점 마케팅 프로모션
- URL: /api/v1/admin/crm/restaurants/popular
- Method: GET
- 헤더에 토큰 필수
- Query Parameters:
category: 음식점 카테고리 (선택)
minReviews: 최소 리뷰 수 (선택)
- Response:
{
"topRestaurants": [
{
"id": 3,
"name": "맛있는 식당",
"category": "한식",
"reviewCount": 100,
"averageRating": 4.5,
"lastReviewDate": "2024-02-27"
},
{
"id": 1,
"name": "한상차림",
"category": "중식",
"reviewCount": 210,
"averageRating": 4.4,
"lastReviewDate": "2024-02-11"
}
]
}
공통 사항
데이터 기준
- 모든 통계는 실제 데이터베이스 테이블의 데이터를 기반으로 합니다.
- USER, RESTAURANT, REVIEW 테이블의 데이터를 활용합니다.
- 날짜/시간은 각 테이블의 created_at 컬럼을 기준으로 합니다.
성능 고려사항
- 대량의 데이터 조회 시 페이징 처리가 필요할 수 있습니다.
인증 및 권한
- 모든 API는 어드민 권한을 가진 사용자만 접근 가능합니다.
- Authorization 헤더에 유효한 어드민 토큰이 필요합니다.
에러 처리
- 잘못된 요청: 400 Bad Request
- 서버 에러: 500 Internal Server Error
데이터 신뢰성
- 모든 통계는 실시간 데이터를 기반으로 합니다.
풀이
3. 상위 리뷰어 목록
서비스의 핵심 사용자인 상위 리뷰어들의 정보를 제공합니다. 리뷰어 수(size)를 쿼리파라미터로 보냅니다.
설명
- 리뷰 작성 수 기준으로 상위 사용자들을 식별합니다.
- 각 리뷰어의 평균 평점과 최근 활동 정보를 함께 제공합니다.
- 이 데이터를 통해 서비스의 핵심 사용자들의 특성을 파악할 수 있습니다.
활용 방안
- VIP 사용자 관리
- 우수 리뷰어 보상 프로그램 운영
- 인플루언서 마케팅 대상 선정
Postman
- URL: /api/v1/admin/crm/users/top-reviewers?size=5
- Method: GET
- 헤더에 토큰 필수
참고
1. 로그인 => 토근 발급
2. Key : Authorization Value : Bearer(공란)발급받은 토큰 (위에 대해서는 intellJ에서 추가 설명 진행하겠습니다. )
// Bearer(공란) = substrin(7)은 제외
jwtConfig.getTokenClaims(token.substring(7)).getSubject();
Postman
intelliJ
controller 패키지 - CRMController 클래스 생성
getTopReviewers(@RequestHeader("Authorization") String token,
@RequestParam ("size")int size){
crmService.getTopReviewers(token, size);
service 패키지 - CRMservice 클래스 생성
public ReviewerListResponse getTopReviewers(String token, int size) {
jwtConfig.getTokenClaims(token.substring(7)).getSubject();
crmDAO.getTopReviewers(token, size);
@Autowired
JwtConfig jwtConfig;
jwtConfig.getTokenClaims(token.substring(7)).getSubject();
설명
1. @Autowired (어노테이션)
Spring Framework에서 제공하는 어노테이션으로, 의존성 주입(Dependency Injection)을 간단하게 구현할 수 있도록 도와줍니다. 이 어노테이션을 사용하면 Spring이 관리하는 Bean을 자동으로 해당 필드, 생성자 또는 메서드에 주입합니다.
2. getTokenClaims(token.substring(7)).getSubject()
Token 작성시 token.substring(7) ( = Bearer+ (공란) ) 을 제외한 나머지 string(문자)로 진행해주시면됩니다.
- Response 예시와 설명:
{
"topReviewers": [
{
"userId": 3,
"nickname": "맛있는생활",
"reviewCount": 50, // 전체 리뷰 작성 수
"averageRating": 4.2, // 평균 평점
"lastReviewDate": "2024-02-27" // 최근 리뷰 작성일
},
{
"userId": 21,
"nickname": "리뷰짱",
"reviewCount": 39, // 전체 리뷰 작성 수
"averageRating": 3.8, // 평균 평점
"lastReviewDate": "2024-02-21" // 최근 리뷰 작성일
}
]
}
dao패키지 - CrmDAO 클래스 생성
DBeaver
intelliJ
public List<ReviewerResponse> getTopReviewers(String token, int size) {
String sql = "SELECT u.id, u.nickname ,COUNT(r.id)as review_count,\\n" +
"ROUND(IFNULL(AVG(r.rating),0),2)as average_rating,\\n" +
"MAX(r.created_at) as lastReview_date\\n" +
"FROM user u\\n" +
"left join review r \\n" +
"on u.id = r.user_id \\n" +
"WHERE role = 'USER'\\n" +
"GROUP by u.id\\n" +
"order by review_count desc,average_rating desc\\n" +
"limit ?;";
return jdbcTemplate.query(sql, new TopReviewerRowMapper(), size);
}
dto패키지 - ReviewerResponse 클래스 생성
@NoArgsConstructor
@AllArgsConstructor
@Data
public class ReviewerResponse {
public Long userId;
public String nickname;
public Integer reviewCount;
public Double averageRating;
public String lastReviewDate;
}
dto패키지 - ReviewerListResponse 클래스 생성
@NoArgsConstructor
@AllArgsConstructor
@Data
public class ReviewerListResponse {
public List<ReviewerResponse> reviewerList;
}
CRMservice 클래스
public ReviewerListResponse getTopReviewers(String token, int size) {
jwtConfig.getTokenClaims(token.substring(7)).getSubject();
List<ReviewerResponse> reviewerList = crmDAO.getTopReviewers(token, size);
return new ReviewerListResponse(reviewerList);
}
CRMController 클래스
@GetMapping("/api/v1/admin/crm/users/top-reviewers")
public ResponseEntity<ReviewerListResponse> getTopReviewers(@RequestHeader("Authorization") String token,
@RequestParam ("size")int size){
ReviewerListResponse reviewerListResponse =
crmService.getTopReviewers(token, size);
return ResponseEntity.status(200).body(reviewerListResponse);
}
@GetMa
Postman
2. 기간별 리뷰 통계
지정된 기간 동안의 리뷰 작성 현황과 평점을 분석합니다.
설명
- 일자별, 카테고리별 리뷰 작성 추이를 파악할 수 있습니다.
- 전체 평균 평점과 카테고리별 평균 평점을 비교할 수 있습니다.
- 특정 기간의 리뷰 트렌드를 분석할 수 있습니다.
활용 방안
- 서비스 성과 모니터링
- 카테고리별 인기도 분석
- 시즌별 트렌드 파악
- URL: /api/v1/admin/crm/reviews/stats
- Method: GET
- 헤더에 토큰 필수
- Query Parameters:
startDate: 조회 시작일 (필수)
endDate: 조회 종료일 (필수)
Postman
intelliJ
@GetMapping("/api/v1/admin/crm/reviews/stats")
getStats(@RequestHeader("Authorization") String token,
@RequestParam("startDate")String startDate,
@RequestParam("endDate")String endDate){
crmService.getStats(token,startDate,endDate);
getStats(String token, String startDate, String endDate) {
// JWT 토큰에서 사용자 정보 추출
jwtConfig.getTokenClaims(token.substring(7)).getSubject();
// 리뷰 통계 정보 조회
List<TotalResponse> totalList =
crmDAO.getByTotal(token, startDate, endDate);
List<DateResponse> dateList =
crmDAO.getByDate(token, startDate, endDate);
List<CategoryResponse> categoryList =
crmDAO.getByCategory(token, startDate, endDate);
}
DBeaver
intelliJ
public List<TotalResponse> getByTotal(String token, String startDate, String endDate) {
String sql = "SELECT \\n" +
"COUNT(r.id) AS review_count,\\n" +
"ROUND(IFNULL(AVG(r.rating), 0), 2) AS average_rating\\n" +
"FROM review r\\n" +
"WHERE r.created_at BETWEEN ? \\n" + // 파라미터 바인딩
"AND ?\\n" +
"GROUP BY r.rating\\n" +
"ORDER BY review_count DESC;";
// SQL 파라미터는 new Object[]로 전달
return jdbcTemplate.query(sql, new TotalRowMapper(), startDate, endDate);
}
- Response:
{
"total": {
"reviewCount": 1000,
"averageRating": 4.3
},
"byDate": [
{
"date": "2024-02-27",
"reviewCount": 50,
"averageRating": 4.2
},
{
"date": "2024-02-28",
"reviewCount": 32,
"averageRating": 4.4
}
],
"byCategory": [
{
"category": "한식",
"reviewCount": 400,
"averageRating": 4.4
},
{
"category": "중식",
"reviewCount": 500,
"averageRating": 4.1
}
]
}
@NoArgsConstructor
@AllArgsConstructor
@Data
public class TotalResponse {
public Integer reviewCount;
public double averageRating;
}
@NoArgsConstructor
@AllArgsConstructor
@Data
public class DateResponse {
public String date;
public Integer reviewCount;
public double averageRating;
}
@NoArgsConstructor
@AllArgsConstructor
@Data
public class CategoryResponse {
public String category;
public Integer reviewCount;
public double averageRating;
}
@NoArgsConstructor
@AllArgsConstructor
@Data
public class StatsResponse {
public List<TotalResponse> total;
public List<DateResponse> byDate;
public List<CategoryResponse> byCategory;
}
public StatsResponse getStats(String token, String startDate, String endDate) {
// JWT 토큰에서 사용자 정보 추출
jwtConfig.getTokenClaims(token.substring(7)).getSubject();
// 리뷰 통계 정보 조회
List<TotalResponse> totalList = crmDAO.getByTotal(token, startDate, endDate);
List<DateResponse> dateList = crmDAO.getByDate(token, startDate, endDate);
List<CategoryResponse> categoryList = crmDAO.getByCategory(token, startDate, endDate);
return new StatsResponse(totalList, dateList, categoryList);
}
@GetMapping("/api/v1/admin/crm/users/top-reviewers")
public ResponseEntity<ReviewerListResponse> getTopReviewers(@RequestHeader("Authorization") String token,
@RequestParam ("size")int size){
ReviewerListResponse reviewerListResponse =
crmService.getTopReviewers(token, size);
return ResponseEntity.status(200).body(reviewerListResponse);
}
@GetMa
Postman
5. 인기 음식점 통계
리뷰 수와 평점을 기준으로 인기 음식점을 분석합니다.
설명
- 리뷰 수와 평점을 기준으로 인기 음식점을 식별합니다.
- 카테고리별 통계를 통해 각 분야의 인기 업체를 파악할 수 있습니다.
- 최근 리뷰 일자를 통해 지속적인 인기도를 확인할 수 있습니다.
활용 방안
- 추천 음식점 선정
- 카테고리별 벤치마킹 업체 선정
- 우수 음식점 마케팅 프로모션
- URL: /api/v1/admin/crm/restaurants/popular
- Method: GET
- 헤더에 토큰 필수
- Query Parameters:
category: 음식점 카테고리 (선택)
minReviews: 최소 리뷰 수 (선택)
Postman
intelliJ
@GetMapping("/api/v1/admin/crm/restaurants/popular")
(@RequestHeader("Authorization") String token,
@RequestParam(value = "category", required = false) String category,
@RequestParam(value = "minReviews", required = false) Integer minReviews) {
crmService.getPopular(token, category, minReviews);
category 선택시 작성 구문
음식점 카테고리 (선택)
@RequestParam(value = "category", required = false) String category
minReviews: 최소 리뷰 수 (선택)
@RequestParam(value = "minReviews", required = false) Integer minReviews)
- @RequestParam은 요청에서 특정 쿼리 파라미터를 추출하여 메서드의 매개변수에 바인딩(어노테이션)
- value 속성은 HTTP 요청의 쿼리 파라미터 이름을 지정합니다.
- required = false는 해당 파라미터가 필수가 아님(false)을 명시하며파라미터가 없을 경우 null이 전달됩니다.
- Response:
{
"topRestaurants": [
{
"id": 3,
"name": "맛있는 식당",
"category": "한식",
"reviewCount": 100,
"averageRating": 4.5,
"lastReviewDate": "2024-02-27"
},
{
"id": 1,
"name": "한상차림",
"category": "중식",
"reviewCount": 210,
"averageRating": 4.4,
"lastReviewDate": "2024-02-11"
}
]
}
Postman