Skip to content

Commit

Permalink
[Refactor,Feat] convention 맞추기, RefreshToken 추가 - #110
Browse files Browse the repository at this point in the history
  • Loading branch information
sukangpunch committed Jul 18, 2024
1 parent 2137652 commit 3e6474e
Show file tree
Hide file tree
Showing 43 changed files with 316 additions and 134 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ dependencies {
// Jsoup
implementation 'org.jsoup:jsoup:1.17.2'

//redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'


}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public class QProfilePhoto extends EntityPathBase<ProfilePhoto> {
//inherited
public final DateTimePath<java.time.LocalDateTime> createdDate = _super.createdDate;

public final NumberPath<Long> id = createNumber("id", Long.class);

//inherited
public final DateTimePath<java.time.LocalDateTime> lastModifiedDate = _super.lastModifiedDate;

public final NumberPath<Long> profilePhotoId = createNumber("profilePhotoId", Long.class);

public final StringPath profilePhotoName = createString("profilePhotoName");

public final StringPath profilePhotoPath = createString("profilePhotoPath");
Expand Down
4 changes: 2 additions & 2 deletions src/main/generated/me/snaptime/user/domain/QUser.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ public class QUser extends EntityPathBase<User> {

public final StringPath email = createString("email");

public final NumberPath<Long> id = createNumber("id", Long.class);

//inherited
public final DateTimePath<java.time.LocalDateTime> lastModifiedDate = _super.lastModifiedDate;

Expand All @@ -46,6 +44,8 @@ public class QUser extends EntityPathBase<User> {

public final ListPath<String, StringPath> roles = this.<String, StringPath>createList("roles", String.class, StringPath.class, PathInits.DIRECT2);

public final NumberPath<Long> userId = createNumber("userId", Long.class);

public QUser(String variable) {
this(User.class, forVariable(variable), INITS);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public FindAlbumResDto findAlbum(String uId, Long album_id) {
FindSnapResDto.entityToResDto(
snap,
urlComponent.makePhotoURL(snap.getFileName(), false),
urlComponent.makeProfileURL(snap.getUser().getProfilePhoto().getId())
urlComponent.makeProfileURL(snap.getUser().getProfilePhoto().getProfilePhotoId())
)
)
.collect(Collectors.toList()))
Expand All @@ -90,7 +90,7 @@ public FindAlbumResDto findAlbum(String uId, Long album_id) {
FindSnapResDto.entityToResDto(
snap,
urlComponent.makePhotoURL(snap.getFileName(), snap.isPrivate()),
urlComponent.makeProfileURL(snap.getUser().getProfilePhoto().getId())
urlComponent.makeProfileURL(snap.getUser().getProfilePhoto().getProfilePhotoId())
)
)
.collect(Collectors.toList()))
Expand Down Expand Up @@ -169,7 +169,7 @@ public void removeAlbum(String uId, Long album_id) {
@Override
public void isUserHavePermission(User user, Long album_id) {
Album foundAlbum = albumRepository.findById(album_id).orElseThrow(() -> new CustomException(ExceptionCode.ALBUM_NOT_EXIST));
if(!(Objects.equals(foundAlbum.getUser().getId(), user.getId()))){
if(!(Objects.equals(foundAlbum.getUser().getUserId(), user.getUserId()))){
throw new CustomException(ExceptionCode.ALBUM_USER_NOT_MATCH);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/me/snaptime/exception/ExceptionCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public enum ExceptionCode {
TOKEN_UNAUTHENTICATED(HttpStatus.UNAUTHORIZED, "인증되지 않은 토큰입니다."),
TOKEN_INVALID_FORMAT(HttpStatus.UNAUTHORIZED, "잘못된 형식의 토큰입니다."),
TOKEN_NOT_FOUND(HttpStatus.BAD_REQUEST, "토큰이 비었거나 null입니다"),
INVALID_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED,"리프레시 토큰이 유효하지 않습니다"),

// Jsoup Action
URL_HAVING_PROBLEM(HttpStatus.BAD_REQUEST, "문제가 있는 URL입니다.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public List<Tuple> findFriendList(User targetUser, FriendSearchType searchType,
Pageable pageable= PageRequest.of((int) (pageNum-1),20);

List<Tuple> result = jpaQueryFactory.select(
user.loginId, user.profilePhoto.id, user.name, friend.friendId
user.loginId, user.profilePhoto.profilePhotoId, user.name, friend.friendId
)
.from(friend)
.join(user).on(getJoinBuilder(searchType))
Expand All @@ -50,18 +50,18 @@ public List<Tuple> findFriendList(User targetUser, FriendSearchType searchType,
}

private OrderSpecifier createOrderSpecifier() {
return new OrderSpecifier(Order.ASC, user.id);
return new OrderSpecifier(Order.ASC, user.userId);
}

// WHERE절을 동적으로 만들기 위한 메소드
private BooleanBuilder getWhereBuilder(User targetUser, FriendSearchType friendSearchType, String searchKeyword){
BooleanBuilder builder = new BooleanBuilder();

if(friendSearchType == FriendSearchType.FOLLOWING){
builder.and(friend.sender.id.eq(targetUser.getId()));
builder.and(friend.sender.userId.eq(targetUser.getUserId()));
}
else{
builder.and(friend.receiver.id.eq(targetUser.getId()));
builder.and(friend.receiver.userId.eq(targetUser.getUserId()));
}

if(searchKeyword !=null){
Expand All @@ -75,10 +75,10 @@ private BooleanBuilder getWhereBuilder(User targetUser, FriendSearchType friendS
private BooleanBuilder getJoinBuilder(FriendSearchType friendSearchType){
BooleanBuilder builder = new BooleanBuilder();
if(friendSearchType == FriendSearchType.FOLLOWING){
return builder.and(friend.receiver.id.eq(user.id));
return builder.and(friend.receiver.userId.eq(user.userId));
}
else{
return builder.and(friend.sender.id.eq(user.id));
return builder.and(friend.sender.userId.eq(user.userId));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void sendFollow(String senderLoginId, String receiverLoginId){
throw new CustomException(ExceptionCode.ALREADY_FOLLOW);

// 자기자신에게 팔로우요청을 했다면
if (receiver.getId() == sender.getId())
if (receiver.getUserId() == sender.getUserId())
throw new CustomException(ExceptionCode.SELF_FRIEND_REQ);

friendRepository.save(Friend.builder()
Expand Down Expand Up @@ -111,7 +111,7 @@ public FindFriendResDto findFriendList(String reqLoginId, String targetLoginId,
List<FriendInfo> friendInfoList = result.stream().map(entity ->
{
boolean isMyFriend = checkIsFollow(reqUser ,findUserByLoginId(entity.get(user.loginId)));
String profilePhotoURL = urlComponent.makeProfileURL(entity.get(user.profilePhoto.id));
String profilePhotoURL = urlComponent.makeProfileURL(entity.get(user.profilePhoto.profilePhotoId));
return FriendInfo.toDto(entity,profilePhotoURL,isMyFriend);
}).collect(Collectors.toList());

Expand Down
36 changes: 34 additions & 2 deletions src/main/java/me/snaptime/jwt/JwtProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
Expand All @@ -24,7 +25,11 @@ public class JwtProvider {

private Key secretKey;

private Long accessTokenValidTime= 1000L * 60 * 60*24;
@Value("${accessTokenValidTime}")
private Long accessTokenValidTime;

@Value("${refreshTokenValidTime}")
private Long refreshTokenValidTime;

@PostConstruct
protected void init(){
Expand All @@ -33,10 +38,11 @@ protected void init(){
log.info("[init] JwtTokenProvider 내 secretKey 초기화 완료");
}

public String createAccessToken(String loginId, List<String> roles){
public String createAccessToken(Long userId, String loginId, List<String> roles){
log.info("[createAccessToken] 엑세스 토큰 생성 시작");

Claims claims = Jwts.claims().setSubject(loginId);
claims.put("userId",userId);
claims.put("type","access");
claims.put("roles",roles);
Date now = new Date();
Expand All @@ -51,6 +57,32 @@ public String createAccessToken(String loginId, List<String> roles){
return token;
}

public String createRefreshToken(Long id, String loginId, List<String> roles){
log.info("[createRefreshToken] 리프레시 토큰 생성 시작");

Claims claims = Jwts.claims().setSubject(loginId);
claims.put("userId", id);
claims.put("type", "refresh");
claims.put("roles", roles);
Date now = new Date();
String token = Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(new Date(now.getTime() + refreshTokenValidTime))
.signWith(secretKey)
.compact();

log.info("[createAccessToken] 엑세스 토큰 생성 완료");
return token;
}

public Long getUserId(String token) {
log.info("[getUserId] 토큰 기반 회원 구별 정보 추출");
Long userId = Long.valueOf(Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().get("userId").toString());
log.info("[getUserId] 토큰 기반 회원 구별 정보 추출 완료, userId : {}", userId);
return userId;
}

// 필터에서 인증 성공 후, SecurityContextHolder 에 저장할 Authentication 을 생성
//UsernamePasswordAuthenticationToken 클래스를 사용
public Authentication getAuthentication(String token){
Expand Down
20 changes: 10 additions & 10 deletions src/main/java/me/snaptime/profile/controller/ProfileController.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,30 @@ public class ProfileController {
@Operation(summary = "유저 앨범, 스냅 조회", description = "유저의 앨범들과, 각 앨범의 스냅들을 조회합니다." +
"<br> 자신의 프로필 조회 -> 앨범 당 private, public 관계 없이 최근 snap 2개 리턴" +
"<br> 다른 사람의 프로필 조회 -> snap이 전부 private이거나 없는 경우 앨범 리턴 x 그리고 private 인 snap 리턴 x")
@Parameter(name = "loginId", description = "앨범과 사진들을 가져오기 위한 loginId", required = true)
@Parameter(name = "targetLoginId", description = "앨범과 사진들을 가져오기 위한 loginId", required = true)
@GetMapping("/album-snap")
public ResponseEntity<CommonResponseDto<List<AlbumSnapResDto>>> getAlbumSnap(@AuthenticationPrincipal UserDetails principal,
@RequestParam("loginId")
@RequestParam("targetLoginId")
@NotBlank(message = "로그인 아이디 입력은 필수입니다.") String targetLoginId){
String yourLoginId = principal.getUsername();
List<AlbumSnapResDto> albumSnapResDtoList = profileService.getAlbumSnap(yourLoginId, targetLoginId);
String reqLoginId = principal.getUsername();
List<AlbumSnapResDto> albumSnapResDtos = profileService.getAlbumSnap(reqLoginId, targetLoginId);
return ResponseEntity.status(HttpStatus.OK).body(
new CommonResponseDto<>(
"유저 앨범과 스냅 조회를 성공적으로 완료하였습니다.",
albumSnapResDtoList
albumSnapResDtos
));
}

@Operation(summary = "유저 이름, 프로필 사진 조회", description = "유저의 이름과, 프로필 사진을 조회합니다." +
"<br> 유저 번호, 유저 이름, 프로필 사진 url 리턴(토큰 없이 url 접근 가능)" +
"<br> 토큰이 없어도 해당 Api 엔드포인트를 요청할 수 있습니다.")
@Parameter(name = "loginId", description = "이름과 프로필 사진을 가져오기 위한 loginId", required = true)
@Parameter(name = "targetLoginId", description = "이름과 프로필 사진을 가져오기 위한 loginId", required = true)
@GetMapping("/profile")
public ResponseEntity<CommonResponseDto<UserProfileResDto>> getUserProfile(@AuthenticationPrincipal UserDetails principal,
@RequestParam("loginId")
@NotBlank(message = "로그인 아이디 입력은 필수입니다.") String loginId){
UserProfileResDto userProfileResDto = profileService.getUserProfile(principal.getUsername(),loginId);
@RequestParam("targetLoginId")
@NotBlank(message = "로그인 아이디 입력은 필수입니다.") String targetLoginId){
String reqLoginId = principal.getUsername();
UserProfileResDto userProfileResDto = profileService.getUserProfile(reqLoginId, targetLoginId);
return ResponseEntity.status(HttpStatus.OK).body(
new CommonResponseDto<>(
"유저 이름과, 프로필 사진 조회를 성공적으로 완료하였습니다.",
Expand All @@ -87,7 +88,6 @@ public ResponseEntity<CommonResponseDto<ProfileCntResDto>> getProfileCnt(@Reques
@GetMapping("/tag-snap")
public ResponseEntity<CommonResponseDto<List<ProfileTagSnapResDto>>> getTagSnap(@RequestParam("loginId")
@NotBlank(message = "로그인 아이디 입력은 필수입니다.") String loginId){

List<ProfileTagSnapResDto> profileTagSnapResDto = profileService.getTagSnap(loginId);
return ResponseEntity.status(HttpStatus.OK).body(
new CommonResponseDto<>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public record UserProfileResDto(
public static UserProfileResDto toDto(User user, String profileURL , Boolean isFollow)
{
return UserProfileResDto.builder()
.userId(user.getId())
.userId(user.getUserId())
.userName(user.getName())
.profileURL(profileURL)
.isFollow(isFollow)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
public interface ProfileRepository{

List<AlbumSnapResDto> findAlbumSnap(User targetUser, Boolean checkPermission);
List<ProfileTagSnapResDto> findTagSnap(User reqUser);
List<ProfileTagSnapResDto> findTagSnap(User targetUser);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,22 @@ public class ProfileRepositoryImpl implements ProfileRepository {
//snap에 isPrivate이 존재한다, 내가 조회 -> 전부 리턴 | 남이 조회 -> isPrivate= True 인 snap 제외
@Override
public List<AlbumSnapResDto> findAlbumSnap(User targetUser, Boolean checkPermission) {
List<Tuple> albumList = jpaQueryFactory
List<Tuple> albums = jpaQueryFactory
.select(album.id, album.name).distinct()
.from(user)
.join(album).on(user.id.eq(album.user.id))
.where(user.id.eq(targetUser.getId()))
.join(album).on(user.userId.eq(album.user.userId))
.where(user.userId.eq(targetUser.getUserId()))
.fetch();

Map<Long,String> albumMap = new HashMap<>();

albumList.forEach(tuple ->{
albums.forEach(tuple ->{
Long albumId = tuple.get(album.id);
String albumName = tuple.get(album.name);
albumMap.put(albumId,albumName);
});

List<AlbumSnapResDto> albumSnapResDtoList = new ArrayList<>();

List<AlbumSnapResDto> albumSnapResDtos = new ArrayList<>();

//snap이 없어도 album은 존재할 수 있기 때문에 album 수 만큼 반복한다.
for (Long albumId : albumMap.keySet()) {
Expand All @@ -64,7 +63,7 @@ public List<AlbumSnapResDto> findAlbumSnap(User targetUser, Boolean checkPermiss
.fetch();

//stream 사용하는 걸로 수정
List<String> snapUrlList = albumSnapTwo.stream()
List<String> snapUrls = albumSnapTwo.stream()
.map(tuple -> {
String fileName = tuple.get(snap.fileName);
Boolean isPrivate = tuple.get(snap.isPrivate);
Expand All @@ -73,33 +72,33 @@ public List<AlbumSnapResDto> findAlbumSnap(User targetUser, Boolean checkPermiss
.toList();

//다른 사람의 프로필 검색 일 때, snap이 없거나, private이면 앨범도 private
if(!checkPermission && snapUrlList.isEmpty()){
if(!checkPermission && snapUrls.isEmpty()){
continue;
}

String albumName = albumMap.get(albumId);

albumSnapResDtoList.add(AlbumSnapResDto.builder()
albumSnapResDtos.add(AlbumSnapResDto.builder()
.albumId(albumId)
.albumName(albumName)
.snapUrlList(snapUrlList)
.snapUrlList(snapUrls)
.build());
}

return albumSnapResDtoList;
return albumSnapResDtos;
}

@Override
public List<ProfileTagSnapResDto> findTagSnap(User reqUser) {
List<Tuple> tagSnapList = jpaQueryFactory
public List<ProfileTagSnapResDto> findTagSnap(User targetUser) {
List<Tuple> tagSnaps = jpaQueryFactory
.select(snap.id,snap.user.loginId, snap.fileName, snap.isPrivate, snap.createdDate).distinct()
.from(snap)
.join(snapTag).on(snapTag.snap.id.eq(snap.id))
.where(snapTag.tagUser.loginId.eq(reqUser.getLoginId()))
.where(snapTag.tagUser.loginId.eq(targetUser.getLoginId()))
.orderBy(snap.createdDate.desc())
.fetch();

List<ProfileTagSnapResDto> tagSnapUrlList = tagSnapList.stream()
List<ProfileTagSnapResDto> tagSnapUrls = tagSnaps.stream()
.map(tuple -> {
return ProfileTagSnapResDto.builder()
.taggedSnapId(tuple.get(snap.id))
Expand All @@ -109,7 +108,7 @@ public List<ProfileTagSnapResDto> findTagSnap(User reqUser) {
})
.toList();

return tagSnapUrlList;
return tagSnapUrls;
}

// 자신이 자신의 profile을 조회할 때, 자신이 다른사람의 profile을 조회할 때를 구별하기 위함.
Expand All @@ -125,7 +124,6 @@ private BooleanBuilder whereBuilder(Long albumId, Boolean checkPermission){
builder.and(snap.isPrivate.isFalse());
builder.and(snap.fileName.isNotNull());
}

return builder;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/me/snaptime/profile/service/ProfileService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

public interface ProfileService {
/* 호출자의 loginId, 피호출자의 loginId를 통해 피호출자의 album과 snap을 조회 */
public List<AlbumSnapResDto> getAlbumSnap(String ownLoginId, String targetLoginId);
public List<AlbumSnapResDto> getAlbumSnap(String reqLoginId, String targetLoginId);
/* loginId에 해당하는 User의 profile 사진을 조회 */
public UserProfileResDto getUserProfile(String ownLoginId, String targetLoginId);
public UserProfileResDto getUserProfile(String reqLoginId, String targetLoginId);
/* loginId에 해당하는 User의 스냅, 팔로우, 팔로워 수 리턴 */
public ProfileCntResDto getUserProfileCnt(String loginId);
/* loginId에 해당하는 User가 Tag된 snap들을 조회합니다 */
Expand Down
Loading

0 comments on commit 3e6474e

Please sign in to comment.