Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5 - rank system #6

Open
wants to merge 32 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6eb5796
add :: Rank.java
Kimhanju0210 Nov 11, 2024
1e8da19
add :: RankController.java
Kimhanju0210 Nov 11, 2024
7dce3ef
add :: RankResponse.java
Kimhanju0210 Nov 11, 2024
0ef14a4
add :: RankServiceImpl.java
Kimhanju0210 Nov 11, 2024
91ac7c2
add :: RankService.java
Kimhanju0210 Nov 11, 2024
210b0d0
add :: RedisConfig.java
Kimhanju0210 Nov 11, 2024
7855b49
add :: JwtService.java
Kimhanju0210 Nov 11, 2024
bc65f7a
add :: UserServiceImpl.java
Kimhanju0210 Nov 11, 2024
a2f9ec8
add :: UserService.java
Kimhanju0210 Nov 11, 2024
f274026
modify :: User.java
Kimhanju0210 Nov 11, 2024
4cce774
modify :: UserRepository.java
Kimhanju0210 Nov 11, 2024
07e3606
modify :: build.gradle
Kimhanju0210 Nov 11, 2024
a42a331
modify :: application.yml
Kimhanju0210 Nov 11, 2024
c748742
Merge branch '5-RankSystem' of https://github.com/Team-MindWay/Dormit…
Kimhanju0210 Nov 11, 2024
14e7af4
add :: GetTopRankingServiceImpl.java
Kimhanju0210 Nov 14, 2024
823fdf7
add :: GetTopRankingService.java
Kimhanju0210 Nov 14, 2024
2b1dd70
add :: GetRankingServiceImpl.java
Kimhanju0210 Nov 14, 2024
1f93210
add :: GetRankingService.java
Kimhanju0210 Nov 14, 2024
c2caf7c
add :: UpdateRankingServiceImpl.java
Kimhanju0210 Nov 14, 2024
2fc1e70
add :: UpdateRankingService.java
Kimhanju0210 Nov 14, 2024
6e642a9
modify :: RankController.java
Kimhanju0210 Nov 14, 2024
5854644
modify :: UserServiceImpl.java
Kimhanju0210 Nov 14, 2024
08478b2
delete :: RankServiceImpl.java
Kimhanju0210 Nov 14, 2024
6481c65
delete :: RankService.java
Kimhanju0210 Nov 14, 2024
35e0844
delete :: RedisConfig.java
Kimhanju0210 Nov 14, 2024
7e202be
modify :: GetRankingServiceImpl.java
Kimhanju0210 Nov 19, 2024
593a11e
modify :: GetTopRankingServiceImpl.java
Kimhanju0210 Nov 19, 2024
7581978
modify :: UpdateRankingServiceImpl.java
Kimhanju0210 Nov 19, 2024
ea0e18e
modify :: User.java
Kimhanju0210 Nov 21, 2024
994ac46
modify :: RankResponse.java
Kimhanju0210 Nov 21, 2024
039cbd7
Revert "modify :: User.java"
Kimhanju0210 Nov 21, 2024
e8c46cd
Revert "modify :: RankResponse.java"
Kimhanju0210 Nov 21, 2024
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
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ dependencies {

//redis
implementation ("org.springframework.boot:spring-boot-starter-data-redis")
implementation ("org.springframework.boot:spring-boot-starter-data-redis:2.3.1.RELEASE")


// aws
implementation("org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE")
Expand Down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redis 부분은 제가 만들어 놨는데 또 만드신 이유가 있나요????????

Copy link
Collaborator Author

@Kimhanju0210 Kimhanju0210 Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

35e0844
수정했습니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.domaserver.domain.rank.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;

@EnableRedisRepositories
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String redisHost;

@Value("${spring.redis.port}")
private int redisPort;

@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.domaserver.domain.rank.entity;

import com.example.domaserver.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Rank {

@Id
@GeneratedValue(strategy =GenerationType.IDENTITY)
private Long RankId;
private int PenaltyPoints;
private double RankScore;

@ManyToOne
@JoinColumn(name = "user_id")
private User user;

public Rank(Long rankId, Double rankScore) {
RankId = rankId;
RankScore = rankScore;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.example.domaserver.domain.rank.presentation;


import com.example.domaserver.domain.rank.entity.Rank;
import com.example.domaserver.domain.rank.service.RankService;
import com.example.domaserver.domain.user.entity.User;
import com.example.domaserver.domain.user.service.UserService;
import com.example.domaserver.global.security.jwt.JwtService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/home")
public class RankController {
private final RankService rankService;
private final UserService userService;
private final JwtService jwtService;

@Autowired
public RankController(RankService rankService, UserService userService, JwtService jwtService) {
this.rankService = rankService;
this.userService = userService;
this.jwtService = jwtService;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Autowired를 쓰는거 보다 클래스에 @requiredargsconstructor로 생성자 생성 할 수 있습니다
수정해주세요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6e642a9

5854644
수정했습니다!


@GetMapping("/rank")
public ResponseEntity<List<Rank>> getRanks() {
List<Rank> topRanks = rankService.getTopRanking(25);
return ResponseEntity.ok(topRanks);
}

@GetMapping("/my-rank")
public ResponseEntity<Long> getMyRank(@RequestHeader("Authorization") String token) {
User user = jwtService.getUserFromToken(token.substring(7));
Long rank = rankService.getRanking(user);
return ResponseEntity.ok(rank);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.domaserver.domain.rank.presentation.dto.response;

import lombok.Builder;
import lombok.Getter;

import java.util.UUID;

@Builder
@Getter
public class RankResponse {
private UUID Id;
private String name;
private String profileImageUrl;
private int penaltyPoints;
private double RankScore;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example.domaserver.domain.rank.service;

import com.example.domaserver.domain.rank.entity.Rank;
import com.example.domaserver.domain.user.entity.User;
import java.util.List;

public interface RankService {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

service는 기능을 분리해서 구현해주세요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long getRanking(User user);
void updateRank(Rank rank);
List<Rank> getTopRanking(int topN);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.example.domaserver.domain.rank.service.impl;

import com.example.domaserver.domain.rank.entity.Rank;
import com.example.domaserver.domain.rank.service.RankService;
import com.example.domaserver.domain.user.entity.User;
import com.example.domaserver.global.annotation.ServiceWithTransaction;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;


@ServiceWithTransaction
public class RankServiceImpl implements RankService {

private static final String RANK_KEY = "USER_RANKING";

private final RedisTemplate redisTemplate;

public RankServiceImpl(@Qualifier("redisTemplate") RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}

@Transactional
public Long getRanking(User user) {
Long rank = redisTemplate.opsForZSet().rank(RANK_KEY, user.getId());
return (rank != null) ? rank + 1 : null;
}

@Transactional
public void updateRank(Rank rank) {
redisTemplate.opsForZSet().add(RANK_KEY, rank.getUser().getId(), rank.getPenaltyPoints());
}

@Transactional
public List<Rank> getTopRanking(int topN) {
Set<ZSetOperations.TypedTuple<Long>> rankedUsers =
redisTemplate.opsForZSet().reverseRangeWithScores(RANK_KEY, 0, topN - 1);

List<Rank> userRanks = new ArrayList<>();
for (ZSetOperations.TypedTuple<Long> entry : rankedUsers) {
Long RankId = entry.getValue();
Double RankScore = entry.getScore();
userRanks.add(new Rank(RankId, RankScore));
}
return userRanks;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ public class User {
@Id
@GeneratedValue(generator = "UUID4")
private UUID id;

private String name;

private String email;
private int penaltyPoint;

@Embedded
private StudentNum studentNum;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@

public interface UserRepository extends JpaRepository<User, UUID> {
Optional<User> findByEmail(String email);
Optional<User> findByUsername(String Username);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.domaserver.domain.user.service;

import com.example.domaserver.domain.user.entity.User;

import java.util.UUID;

public interface UserService {
User findByUsername(String name);
User findById(UUID id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.example.domaserver.domain.user.service.impl;

import com.example.domaserver.domain.user.entity.User;
import com.example.domaserver.domain.user.repository.UserRepository;
import com.example.domaserver.domain.user.service.UserService;
import com.example.domaserver.global.annotation.ServiceWithTransaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.UUID;

@ServiceWithTransaction
public class UserServiceImpl implements UserService {

private final UserRepository userRepository;

@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}

@Override
public User findByUsername(String username) {
return userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + username));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

custom exception을 만들어서 예외처리를 해보는건 어떨까요

}

@Override
public User findById(UUID id) {
return userRepository.findById(id)
.orElseThrow(() -> new UsernameNotFoundException("User not found with id: " + id));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.example.domaserver.global.security.jwt;


import com.example.domaserver.domain.user.entity.User;
import com.example.domaserver.domain.user.service.UserService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Value;

import java.util.Date;
import java.util.function.Function;

@Service
@Slf4j
public class JwtService {

private final UserService userService;

@Value("${jwt.secret}")
private String secretKey;

public JwtService(UserService userService) {
this.userService = userService;
}

public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}

public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}

private Claims extractAllClaims(String token) {
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
}

public boolean isTokenValid(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}

private boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}

public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}

public User getUserFromToken(String token) {
String username = extractUsername(token);
return userService.findByUsername(username);
}
}
8 changes: 6 additions & 2 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
server:
redis:
port: 6739
host: localhost

port: 8090
servlet:
context-path: /
Expand Down Expand Up @@ -33,9 +37,9 @@ spring:
port: ${REDIS_PORT}

jwt:
secret: ${JWT_SECRET}
secret: "your_secret_key_here"

gauth:
clientId: ${GAUTH_CLIENT}
clientSecret: ${GAUTH_SECRET}
redirectUri: ${GAUTH_REDIRECT_URI}
redirectUri: ${GAUTH_REDIRECT_URI}
Loading