Skip to content

Commit

Permalink
Release v1.0.0
Browse files Browse the repository at this point in the history
Release v1.0.0
  • Loading branch information
hjunyoung authored Jan 10, 2024
2 parents 9f72fa4 + 00b89de commit 7c71c69
Show file tree
Hide file tree
Showing 59 changed files with 2,356 additions and 406 deletions.
8 changes: 7 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@ COPY ${JAR_FILE} app.jar
# jar 파일 실행
# 생성된 이미지를 컨테이너로 실행하는 시점에 app.jar 실행
# Duser.timezone : 타임 존 지정
ENTRYPOINT ["java", "-jar", "-Duser.timezone=Asia/Seoul", "/app.jar"]
ENTRYPOINT ["java", "-jar",\
"-Duser.timezone=Asia/Seoul",\
"-Dspring.profiles.active=dev",\
"-javaagent:./pinpoint/pinpoint-bootstrap-2.5.3.jar",\
"-Dpinpoint.agentId=purebasket01","-Dpinpoint.applicationName=purebasket",\
"-Dpinpoint.config=./pinpoint/pinpoint-root.config",\
"/app.jar"]
49 changes: 34 additions & 15 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ dependencies {
//redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

// Kafka
implementation 'org.springframework.kafka:spring-kafka'

// aws
implementation 'io.awspring.cloud:spring-cloud-aws-starter:3.0.0'
implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3:3.0.0'
Expand All @@ -42,6 +45,19 @@ dependencies {
implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'

// prometheus grafana
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-core'
implementation 'io.micrometer:micrometer-registry-prometheus'

// elk es 8.11.1
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
implementation 'net.logstash.logback:logstash-logback-encoder:7.4'
implementation 'com.github.danielwegener:logback-kafka-appender:0.2.0-RC2'

// email service
implementation 'org.springframework.boot:spring-boot-starter-mail'

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
Expand All @@ -60,25 +76,32 @@ tasks.named('test') {
}

test {
useJUnitPlatform()
useJUnitPlatform() // JUnit5
finalizedBy jacocoTestReport // report is always generated after tests run
}

jacoco {
// JaCoCo 버전
toolVersion = '0.8.9'
reportsDirectory = layout.buildDirectory.dir('customJacocoReportDir')

}

jacocoTestReport {
dependsOn test // tests are required to run before generating the report
reports {
xml.required = false
csv.required = false
html.outputLocation = layout.buildDirectory.dir('jacocoHtml')
html.destination file('build/reports/testReport.html')
finalizedBy 'jacocoTestCoverageVerification'
}

afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: [
'**/PureBasketBeApplication',
'**/security/*',
'**/*dto*',
'**/config/*'
])
}))
}
}

Expand All @@ -88,17 +111,13 @@ jacocoTestCoverageVerification {
enabled = true
element = 'CLASS'

// 라인 커버리지 제한을 70%로 설정
// limit {
// counter = 'LINE'
// value = 'COVEREDRATIO'
// minimum = 0.70
// }
excludes = [
'**.*PureBasketBeApplication*',
'**.*security*',
'**.*dto*',
'**.*config*',
]
}


rule {
// 규칙을 여러개 추가할 수 있습니다.
}
}
}
1 change: 1 addition & 0 deletions lombok.config
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lombok.addLombokGeneratedAnnotation = true
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableCaching
@EnableScheduling
@EnableJpaAuditing
@SpringBootApplication(exclude = SecurityAutoConfiguration.class) // Spring Security 인증 기능 제외
@SpringBootApplication
public class PureBasketBeApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,16 @@
@Repository
public interface CartRepository extends JpaRepository<Cart, Long> {

@Modifying
@Query("select exists (select c.id from Cart c where c.product = :product and c.member = :member)")
boolean existsProductByMember(Product product, Member member);

@Modifying(clearAutomatically = true)
@Query("DELETE FROM Cart c WHERE c.member=:member AND c.product IN (:products)")
void deleteByUserAndProductIn(Member member, List<Product> products);
void deleteAllByMemberAndProductIn(Member member, List<Product> products);

@Query("SELECT c FROM Cart c " +
"JOIN FETCH c.product " +
"WHERE c.member = :member")
@Query("SELECT c FROM Cart c JOIN FETCH c.product WHERE c.member = :member")
List<Cart> findAllByMember(Member member);

void deleteAllByMemberAndProductIn(Member member, List<Product> productList);

Optional<Cart> findByProductIdAndMember(Long productId, Member member);

}
34 changes: 21 additions & 13 deletions src/main/java/com/example/purebasketbe/domain/cart/CartService.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
import com.example.purebasketbe.global.exception.CustomException;
import com.example.purebasketbe.global.exception.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class CartService {
Expand All @@ -30,18 +32,16 @@ public class CartService {
@Transactional
public void addToCart(Long productId, CartRequestDto requestDto, Member member) {
Product product = findAndValidateProduct(productId);
checkIfExist(product, member);
Cart newCart = Cart.of(product, member, requestDto);
cartRepository.save(newCart);
}

@Transactional(readOnly = true)
public List<CartResponseDto> getCartList(Member member) {
return cartRepository.findAllByMember(member).stream()
.map(cart -> {
Product product = findAndValidateProduct(cart.getProduct().getId());
Image image = findImage(product.getId());
return CartResponseDto.of(product, image, cart);
}).toList();
.filter(cart -> !cart.getProduct().isDeleted())
.map(CartResponseDto::from).toList();
}

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

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

List<Product> productList = recipe.getProductList();
cartRepository.deleteAllByMemberAndProductIn(member, productList);
List<Cart> cartList = productList.stream().map(product -> Cart.of(product, member, null)).toList();
List<Cart> cartList = productList.stream().map(product -> Cart.of(product, member)).toList();
cartRepository.saveAll(cartList);
}


private Product findAndValidateProduct(Long productId) {
Product product = productRepository.findById(productId).orElseThrow(
return productRepository.findByIdAndDeleted(productId, false).orElseThrow(
() -> new CustomException(ErrorCode.PRODUCT_NOT_FOUND)
);
if (product.getStock() <= 0 || product.isDeleted()) {
throw new CustomException(ErrorCode.NOT_ENOUGH_PRODUCT);

}

private void checkIfExist(Product product, Member member) {
if (cartRepository.existsProductByMember(product, member)) {
throw new CustomException(ErrorCode.PRODUCT_ALREADY_ADDED);
}
return product;
}

private Cart findAndValidateCart(Long productId, Member member) {
Expand All @@ -88,4 +90,10 @@ private Image findImage(Long productId) {
return imageRepository.findAllByProductId(productId).stream().findFirst()
.orElseThrow(() -> new CustomException(ErrorCode.INVALID_IMAGE));
}

private Recipe getRecipeById(Long recipeId) {
return recipeRepository.findById(recipeId).orElseThrow(() ->
new CustomException(ErrorCode.RECIPE_NOT_FOUND)
);
}
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,41 @@
package com.example.purebasketbe.domain.cart.dto;

import com.example.purebasketbe.domain.cart.entity.Cart;
import com.example.purebasketbe.domain.product.entity.Image;
import com.example.purebasketbe.domain.product.entity.Event;
import com.example.purebasketbe.domain.product.entity.Product;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class CartResponseDto {
public record CartResponseDto(
Long id,
String name,
Integer price,
String category,
String imageUrl,
int amount,

private Long id;
private String name;
private Integer price;
private String category;
private String imageUrl;
private int amount;
Event event,

int discountRate

) {
@Builder
private CartResponseDto(Long id, String name, Integer price, String category, String imageUrl, int amount) {
this.id = id;
this.name = name;
this.price = price;
this.category = category;
this.imageUrl = imageUrl;
this.amount = amount;
public CartResponseDto {

}

public static CartResponseDto of(Product product, Image image, Cart cart){

public static CartResponseDto from( Cart cart) {
Product product = cart.getProduct();
return CartResponseDto.builder()
.id(product.getId())
.name(product.getName())
.price(product.getPrice())
.category(product.getCategory())
.imageUrl(image.getImgUrl())
.imageUrl(product.getImages().get(0).getImgUrl())
.event(product.getEvent())
.discountRate(product.getDiscountRate())
.amount(cart.getAmount())
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,17 @@ private Cart(int amount, Member member, Product product) {
this.product = product;
}

public static Cart of(Product product, Member member) {
return Cart.builder()
.amount(1)
.member(member)
.product(product)
.build();
}

public static Cart of(Product product, Member member, CartRequestDto requestDto) {
int amount = requestDto == null ? 1 : requestDto.amount();
return Cart.builder()
.amount(amount)
.amount(requestDto.amount())
.member(member)
.product(product)
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.example.purebasketbe.domain.member;

import com.example.purebasketbe.domain.member.entity.Member;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import com.example.purebasketbe.global.exception.ErrorCode;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@RequiredArgsConstructor
public class MemberService {
Expand All @@ -25,6 +27,7 @@ public void registerMember(SignupRequestDto requestDto) {
memberRepository.save(member);
}


private void checkIfEmailExist(String email) {
if (memberRepository.existsByEmail(email)) {
throw new CustomException(ErrorCode.EMAIL_ALREADY_EXISTS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;


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

@NotBlank(message = "비밀번호를 입력해주세요")
String password
) { }
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;

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

Loading

0 comments on commit 7c71c69

Please sign in to comment.