Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-redis")
implementation("mysql:mysql-connector-java:8.0.33")

compileOnly("org.projectlombok:lombok")
testCompileOnly("org.projectlombok:lombok")
testAnnotationProcessor("org.projectlombok:lombok")
runtimeOnly("com.h2database:h2")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/example/log4u/Log4UApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing
@SpringBootApplication
public class Log4UApplication {

Expand Down
28 changes: 28 additions & 0 deletions src/main/java/com/example/log4u/common/entity/BaseEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.example.log4u.common.entity;

import java.time.LocalDateTime;

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
abstract public class BaseEntity {

@CreatedDate
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt;

@LastModifiedDate
@Column(nullable = false)
private LocalDateTime updatedAt;

private String deleteYn = "N";
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,4 @@ public String testIllegalArgument() {
public String testLog4uException() {
throw new NotFoundCommentException(); // 또는 임의의 ServiceException
}

}
58 changes: 58 additions & 0 deletions src/main/java/com/example/log4u/domain/diary/entity/Diary.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.example.log4u.domain.diary.entity;

import com.example.log4u.common.entity.BaseEntity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class Diary extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long diaryId;

//JPA 연관관계 사용 X
// 외래키 방식을 사용 O
@Column(nullable = false)
private Long userId;

@Column(nullable = false)
private String title;

private String thumbnailUrl;

@Column(nullable = false)
private String content;

@Column(nullable = false)
private Double latitude;

@Column(nullable = false)
private Double longitude;

@Column(nullable = false)
private Long likeCount;

public Long incrementLikeCount() {
this.likeCount++;
return this.likeCount;
}

public Long decreaseLikeCount() {
this.likeCount--;
return this.likeCount;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.example.log4u.domain.diary.exception;

import org.springframework.http.HttpStatus;

import com.example.log4u.common.exception.base.ErrorCode;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum DiaryErrorCode implements ErrorCode {

NOT_FOUND_DIARY(HttpStatus.NOT_FOUND, "다이어리를 찾을 수 없습니다.");

private final HttpStatus httpStatus;
private final String message;

@Override
public HttpStatus getHttpStatus() {
return httpStatus;
}

@Override
public String getErrorMessage() {
return message;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example.log4u.domain.diary.exception;

import com.example.log4u.common.exception.base.ErrorCode;
import com.example.log4u.common.exception.base.ServiceException;

public class DiaryException extends ServiceException {
public DiaryException(ErrorCode errorCode) {
super(errorCode);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.log4u.domain.diary.exception;

public class NotFoundDiaryException extends DiaryException {
public NotFoundDiaryException() {
super(DiaryErrorCode.NOT_FOUND_DIARY);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.log4u.domain.diary.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.log4u.domain.diary.entity.Diary;

public interface DiaryRepository extends JpaRepository<Diary, Long>
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.example.log4u.domain.diary.service;

import org.springframework.stereotype.Service;

import com.example.log4u.domain.diary.entity.Diary;
import com.example.log4u.domain.diary.exception.NotFoundDiaryException;
import com.example.log4u.domain.diary.repository.DiaryRepository;

import lombok.RequiredArgsConstructor;


@Service
@RequiredArgsConstructor
public class DiaryService {

private final DiaryRepository diaryRepository;

public Diary getDiary(Long diaryId) {
return diaryRepository.findById(diaryId)
.orElseThrow(NotFoundDiaryException::new);
}

public Long incrementLikeCount(Long diaryId) {
Diary diary = getDiary(diaryId);
return diary.incrementLikeCount();
}

public Long decreaseLikeCount(Long diaryId) {
Diary diary = getDiary(diaryId);
return diary.decreaseLikeCount();
}

public Long getLikeCount(Long diaryId) {
Diary diary = getDiary(diaryId);
return diary.getLikeCount();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.example.log4u.domain.like.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
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 com.example.log4u.domain.like.dto.request.LikeAddRequestDto;
import com.example.log4u.domain.like.dto.response.LikeAddResponseDto;
import com.example.log4u.domain.like.dto.response.LikeCancelResponseDto;
import com.example.log4u.domain.like.service.LikeService;

import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@Tag(name = "좋아요 API")
@RestController
@RequiredArgsConstructor
@RequestMapping("/likes")
public class LikeController {

private final LikeService likeService;

@PostMapping
public ResponseEntity<LikeAddResponseDto> addLike(@Valid @RequestBody LikeAddRequestDto requestDto) {
Long userId = 1L; // 실제 구현에서는 토큰에서 추출

LikeAddResponseDto response = likeService.addLike(userId, requestDto);
return ResponseEntity.ok(response);
}

@DeleteMapping("/{diaryId}")
public ResponseEntity<LikeCancelResponseDto> cancelLike(@PathVariable Long diaryId){
Long userId = 1L;// 실제 구현에서는 토큰에서 추출

LikeCancelResponseDto response = likeService.cancelLike(userId, diaryId);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.log4u.domain.like.dto.request;

import com.example.log4u.domain.like.entity.Like;

public record LikeAddRequestDto(
Long diaryId

) {

public Like toEntity(Long userId) {
return Like.builder()
.userId(userId)
.diaryId(diaryId)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.log4u.domain.like.dto.response;

public record LikeAddResponseDto(
boolean liked,
Long likeCount) {

public static LikeAddResponseDto of(boolean liked, Long likeCount) {
return new LikeAddResponseDto(liked, likeCount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.log4u.domain.like.dto.response;

public record LikeCancelResponseDto(
boolean liked,
Long likeCount) {

public static LikeCancelResponseDto of(boolean liked, Long likeCount) {
return new LikeCancelResponseDto(liked, likeCount);
}
}
34 changes: 34 additions & 0 deletions src/main/java/com/example/log4u/domain/like/entity/Like.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.example.log4u.domain.like.entity;

import com.example.log4u.common.entity.BaseEntity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@Table(name = "likes")
public class Like extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long likeId;

@Column(nullable = false)
private Long userId;

@Column(nullable = false)
private Long diaryId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.log4u.domain.like.exception;

public class DuplicateLikeException extends LikeException {
public DuplicateLikeException() {
super(LikeErrorCode.DUPLICATE_LIKE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.log4u.domain.like.exception;

import org.springframework.http.HttpStatus;

import com.example.log4u.common.exception.base.ErrorCode;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum LikeErrorCode implements ErrorCode {

NOT_FOUND_LIKE(HttpStatus.NOT_FOUND, "좋아요 정보를 찾을 수 없습니다."),
DUPLICATE_LIKE(HttpStatus.BAD_REQUEST, "이미 좋아요를 눌렀습니다.");


private final HttpStatus httpStatus;
private final String message;

@Override
public HttpStatus getHttpStatus() {
return httpStatus;
}

@Override
public String getErrorMessage() {
return message;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.log4u.domain.like.exception;

import com.example.log4u.common.exception.base.ErrorCode;
import com.example.log4u.common.exception.base.ServiceException;

public class LikeException extends ServiceException {
public LikeException(ErrorCode errorCode) {
super(errorCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.log4u.domain.like.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.log4u.domain.like.entity.Like;

public interface LikeRepository extends JpaRepository<Like, Long> {
boolean existsByUserIdAndDiaryId(Long userId, Long diaryId);

Optional<Like> findByUserIdAndDiaryId(Long userId, Long diaryId);
}
Loading