Skip to content

Commit 7c71c69

Browse files
authored
Release v1.0.0
Release v1.0.0
2 parents 9f72fa4 + 00b89de commit 7c71c69

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2356
-406
lines changed

Dockerfile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,10 @@ COPY ${JAR_FILE} app.jar
77
# jar 파일 실행
88
# 생성된 이미지를 컨테이너로 실행하는 시점에 app.jar 실행
99
# Duser.timezone : 타임 존 지정
10-
ENTRYPOINT ["java", "-jar", "-Duser.timezone=Asia/Seoul", "/app.jar"]
10+
ENTRYPOINT ["java", "-jar",\
11+
"-Duser.timezone=Asia/Seoul",\
12+
"-Dspring.profiles.active=dev",\
13+
"-javaagent:./pinpoint/pinpoint-bootstrap-2.5.3.jar",\
14+
"-Dpinpoint.agentId=purebasket01","-Dpinpoint.applicationName=purebasket",\
15+
"-Dpinpoint.config=./pinpoint/pinpoint-root.config",\
16+
"/app.jar"]

build.gradle

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ dependencies {
2727
//redis
2828
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
2929

30+
// Kafka
31+
implementation 'org.springframework.kafka:spring-kafka'
32+
3033
// aws
3134
implementation 'io.awspring.cloud:spring-cloud-aws-starter:3.0.0'
3235
implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3:3.0.0'
@@ -42,6 +45,19 @@ dependencies {
4245
implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
4346
implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'
4447

48+
// prometheus grafana
49+
implementation 'org.springframework.boot:spring-boot-starter-actuator'
50+
implementation 'io.micrometer:micrometer-core'
51+
implementation 'io.micrometer:micrometer-registry-prometheus'
52+
53+
// elk es 8.11.1
54+
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
55+
implementation 'net.logstash.logback:logstash-logback-encoder:7.4'
56+
implementation 'com.github.danielwegener:logback-kafka-appender:0.2.0-RC2'
57+
58+
// email service
59+
implementation 'org.springframework.boot:spring-boot-starter-mail'
60+
4561
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
4662
implementation 'org.springframework.boot:spring-boot-starter-validation'
4763
implementation 'org.springframework.boot:spring-boot-starter-web'
@@ -60,25 +76,32 @@ tasks.named('test') {
6076
}
6177

6278
test {
63-
useJUnitPlatform()
79+
useJUnitPlatform() // JUnit5
6480
finalizedBy jacocoTestReport // report is always generated after tests run
6581
}
6682

6783
jacoco {
6884
// JaCoCo 버전
6985
toolVersion = '0.8.9'
7086
reportsDirectory = layout.buildDirectory.dir('customJacocoReportDir')
71-
7287
}
7388

7489
jacocoTestReport {
7590
dependsOn test // tests are required to run before generating the report
7691
reports {
77-
xml.required = false
78-
csv.required = false
79-
html.outputLocation = layout.buildDirectory.dir('jacocoHtml')
92+
html.destination file('build/reports/testReport.html')
8093
finalizedBy 'jacocoTestCoverageVerification'
94+
}
8195

96+
afterEvaluate {
97+
classDirectories.setFrom(files(classDirectories.files.collect {
98+
fileTree(dir: it, exclude: [
99+
'**/PureBasketBeApplication',
100+
'**/security/*',
101+
'**/*dto*',
102+
'**/config/*'
103+
])
104+
}))
82105
}
83106
}
84107

@@ -88,17 +111,13 @@ jacocoTestCoverageVerification {
88111
enabled = true
89112
element = 'CLASS'
90113

91-
// 라인 커버리지 제한을 70%로 설정
92-
// limit {
93-
// counter = 'LINE'
94-
// value = 'COVEREDRATIO'
95-
// minimum = 0.70
96-
// }
114+
excludes = [
115+
'**.*PureBasketBeApplication*',
116+
'**.*security*',
117+
'**.*dto*',
118+
'**.*config*',
119+
]
97120
}
98121

99-
100-
rule {
101-
// 규칙을 여러개 추가할 수 있습니다.
102-
}
103122
}
104123
}

lombok.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lombok.addLombokGeneratedAnnotation = true

src/main/java/com/example/purebasketbe/PureBasketBeApplication.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5-
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
5+
import org.springframework.cache.annotation.EnableCaching;
66
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
7+
import org.springframework.scheduling.annotation.EnableScheduling;
78

9+
@EnableCaching
10+
@EnableScheduling
811
@EnableJpaAuditing
9-
@SpringBootApplication(exclude = SecurityAutoConfiguration.class) // Spring Security 인증 기능 제외
12+
@SpringBootApplication
1013
public class PureBasketBeApplication {
1114

1215
public static void main(String[] args) {

src/main/java/com/example/purebasketbe/domain/cart/CartRepository.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,16 @@
1414
@Repository
1515
public interface CartRepository extends JpaRepository<Cart, Long> {
1616

17-
@Modifying
17+
@Query("select exists (select c.id from Cart c where c.product = :product and c.member = :member)")
18+
boolean existsProductByMember(Product product, Member member);
19+
20+
@Modifying(clearAutomatically = true)
1821
@Query("DELETE FROM Cart c WHERE c.member=:member AND c.product IN (:products)")
19-
void deleteByUserAndProductIn(Member member, List<Product> products);
22+
void deleteAllByMemberAndProductIn(Member member, List<Product> products);
2023

21-
@Query("SELECT c FROM Cart c " +
22-
"JOIN FETCH c.product " +
23-
"WHERE c.member = :member")
24+
@Query("SELECT c FROM Cart c JOIN FETCH c.product WHERE c.member = :member")
2425
List<Cart> findAllByMember(Member member);
2526

26-
void deleteAllByMemberAndProductIn(Member member, List<Product> productList);
27-
2827
Optional<Cart> findByProductIdAndMember(Long productId, Member member);
2928

3029
}

src/main/java/com/example/purebasketbe/domain/cart/CartService.java

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
import com.example.purebasketbe.global.exception.CustomException;
1414
import com.example.purebasketbe.global.exception.ErrorCode;
1515
import lombok.RequiredArgsConstructor;
16+
import lombok.extern.slf4j.Slf4j;
1617
import org.springframework.stereotype.Service;
1718
import org.springframework.transaction.annotation.Transactional;
1819

1920
import java.util.List;
2021

22+
@Slf4j
2123
@Service
2224
@RequiredArgsConstructor
2325
public class CartService {
@@ -30,18 +32,16 @@ public class CartService {
3032
@Transactional
3133
public void addToCart(Long productId, CartRequestDto requestDto, Member member) {
3234
Product product = findAndValidateProduct(productId);
35+
checkIfExist(product, member);
3336
Cart newCart = Cart.of(product, member, requestDto);
3437
cartRepository.save(newCart);
3538
}
3639

3740
@Transactional(readOnly = true)
3841
public List<CartResponseDto> getCartList(Member member) {
3942
return cartRepository.findAllByMember(member).stream()
40-
.map(cart -> {
41-
Product product = findAndValidateProduct(cart.getProduct().getId());
42-
Image image = findImage(product.getId());
43-
return CartResponseDto.of(product, image, cart);
44-
}).toList();
43+
.filter(cart -> !cart.getProduct().isDeleted())
44+
.map(CartResponseDto::from).toList();
4545
}
4646

4747
@Transactional
@@ -58,24 +58,26 @@ public void deleteCart(Long productId, Member member) {
5858

5959
@Transactional
6060
public void addRecipeRelatedProductsToCarts(Long recipeId, Member member) {
61-
Recipe recipe = recipeRepository.findById(recipeId).orElseThrow(() ->
62-
new CustomException(ErrorCode.RECIPE_NOT_FOUND)
63-
);
61+
Recipe recipe = getRecipeById(recipeId);
6462

6563
List<Product> productList = recipe.getProductList();
6664
cartRepository.deleteAllByMemberAndProductIn(member, productList);
67-
List<Cart> cartList = productList.stream().map(product -> Cart.of(product, member, null)).toList();
65+
List<Cart> cartList = productList.stream().map(product -> Cart.of(product, member)).toList();
6866
cartRepository.saveAll(cartList);
6967
}
7068

69+
7170
private Product findAndValidateProduct(Long productId) {
72-
Product product = productRepository.findById(productId).orElseThrow(
71+
return productRepository.findByIdAndDeleted(productId, false).orElseThrow(
7372
() -> new CustomException(ErrorCode.PRODUCT_NOT_FOUND)
7473
);
75-
if (product.getStock() <= 0 || product.isDeleted()) {
76-
throw new CustomException(ErrorCode.NOT_ENOUGH_PRODUCT);
74+
75+
}
76+
77+
private void checkIfExist(Product product, Member member) {
78+
if (cartRepository.existsProductByMember(product, member)) {
79+
throw new CustomException(ErrorCode.PRODUCT_ALREADY_ADDED);
7780
}
78-
return product;
7981
}
8082

8183
private Cart findAndValidateCart(Long productId, Member member) {
@@ -88,4 +90,10 @@ private Image findImage(Long productId) {
8890
return imageRepository.findAllByProductId(productId).stream().findFirst()
8991
.orElseThrow(() -> new CustomException(ErrorCode.INVALID_IMAGE));
9092
}
93+
94+
private Recipe getRecipeById(Long recipeId) {
95+
return recipeRepository.findById(recipeId).orElseThrow(() ->
96+
new CustomException(ErrorCode.RECIPE_NOT_FOUND)
97+
);
98+
}
9199
}
Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,41 @@
11
package com.example.purebasketbe.domain.cart.dto;
22

33
import com.example.purebasketbe.domain.cart.entity.Cart;
4-
import com.example.purebasketbe.domain.product.entity.Image;
4+
import com.example.purebasketbe.domain.product.entity.Event;
55
import com.example.purebasketbe.domain.product.entity.Product;
6-
import lombok.AccessLevel;
76
import lombok.Builder;
8-
import lombok.Getter;
9-
import lombok.NoArgsConstructor;
107

11-
@Getter
12-
@NoArgsConstructor(access = AccessLevel.PROTECTED)
13-
public class CartResponseDto {
8+
public record CartResponseDto(
9+
Long id,
10+
String name,
11+
Integer price,
12+
String category,
13+
String imageUrl,
14+
int amount,
1415

15-
private Long id;
16-
private String name;
17-
private Integer price;
18-
private String category;
19-
private String imageUrl;
20-
private int amount;
16+
Event event,
2117

18+
int discountRate
19+
20+
) {
2221
@Builder
23-
private CartResponseDto(Long id, String name, Integer price, String category, String imageUrl, int amount) {
24-
this.id = id;
25-
this.name = name;
26-
this.price = price;
27-
this.category = category;
28-
this.imageUrl = imageUrl;
29-
this.amount = amount;
22+
public CartResponseDto {
23+
3024
}
3125

32-
public static CartResponseDto of(Product product, Image image, Cart cart){
26+
27+
public static CartResponseDto from( Cart cart) {
28+
Product product = cart.getProduct();
3329
return CartResponseDto.builder()
3430
.id(product.getId())
3531
.name(product.getName())
3632
.price(product.getPrice())
3733
.category(product.getCategory())
38-
.imageUrl(image.getImgUrl())
34+
.imageUrl(product.getImages().get(0).getImgUrl())
35+
.event(product.getEvent())
36+
.discountRate(product.getDiscountRate())
3937
.amount(cart.getAmount())
4038
.build();
4139
}
40+
4241
}

src/main/java/com/example/purebasketbe/domain/cart/entity/Cart.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,17 @@ private Cart(int amount, Member member, Product product) {
3838
this.product = product;
3939
}
4040

41+
public static Cart of(Product product, Member member) {
42+
return Cart.builder()
43+
.amount(1)
44+
.member(member)
45+
.product(product)
46+
.build();
47+
}
48+
4149
public static Cart of(Product product, Member member, CartRequestDto requestDto) {
42-
int amount = requestDto == null ? 1 : requestDto.amount();
4350
return Cart.builder()
44-
.amount(amount)
51+
.amount(requestDto.amount())
4552
.member(member)
4653
.product(product)
4754
.build();

src/main/java/com/example/purebasketbe/domain/member/MemberRepository.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.example.purebasketbe.domain.member;
22

33
import com.example.purebasketbe.domain.member.entity.Member;
4-
import java.util.Optional;
54
import org.springframework.data.jpa.repository.JpaRepository;
65
import org.springframework.stereotype.Repository;
76

src/main/java/com/example/purebasketbe/domain/member/MemberService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
import com.example.purebasketbe.global.exception.ErrorCode;
77
import jakarta.transaction.Transactional;
88
import lombok.RequiredArgsConstructor;
9+
import lombok.extern.slf4j.Slf4j;
910
import org.springframework.security.crypto.password.PasswordEncoder;
1011
import org.springframework.stereotype.Service;
1112

13+
@Slf4j
1214
@Service
1315
@RequiredArgsConstructor
1416
public class MemberService {
@@ -25,6 +27,7 @@ public void registerMember(SignupRequestDto requestDto) {
2527
memberRepository.save(member);
2628
}
2729

30+
2831
private void checkIfEmailExist(String email) {
2932
if (memberRepository.existsByEmail(email)) {
3033
throw new CustomException(ErrorCode.EMAIL_ALREADY_EXISTS);

src/main/java/com/example/purebasketbe/domain/member/dto/LoginRequestDto.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
import jakarta.validation.constraints.Email;
44
import jakarta.validation.constraints.NotBlank;
55

6+
67
public record LoginRequestDto (
78
@NotBlank(message = "이메일을 입력해주세요")
89
@Email(message = "형식에 맞게 입력해주세요")
910
String email,
1011

1112
@NotBlank(message = "비밀번호를 입력해주세요")
1213
String password
13-
) { }
14+
) {
15+
}

src/main/java/com/example/purebasketbe/domain/member/dto/SignupRequestDto.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import jakarta.validation.constraints.NotBlank;
55
import jakarta.validation.constraints.Pattern;
66

7-
public record SignupRequestDto (
7+
public record SignupRequestDto(
88
@NotBlank(message = "이름을 입력해주세요")
99
String name,
1010
@NotBlank(message = "이메일을 입력해주세요")
@@ -19,4 +19,6 @@ public record SignupRequestDto (
1919
@NotBlank(message = "전화번호를 입력해주세요")
2020
@Pattern(regexp = "^[0-9]{10,11}$", message = "전화번호는 10~11자리의 숫자이어야 합니다")
2121
String phone
22-
){ }
22+
) {
23+
}
24+

0 commit comments

Comments
 (0)