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

부산대_ BE_ 이성훈 6주차 (2단계) #315

Open
wants to merge 37 commits into
base: nextrplue
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
1db5823
feat: Copied files from spring-gift-order repository
NextrPlue Jul 31, 2024
0deb1dd
feat: Copied files from spring-gift-order repository
NextrPlue Jul 31, 2024
745b635
feat: Copied files from spring-gift-order repository
NextrPlue Jul 31, 2024
bd5f69e
feat: Copied files from spring-gift-order repository
NextrPlue Jul 31, 2024
dd8db52
feat: Copied files from spring-gift-order repository
NextrPlue Jul 31, 2024
4cbfc5d
feat: Copied files from spring-gift-order repository
NextrPlue Jul 31, 2024
2544359
refactor(controller): convert WishlistController to RestController
NextrPlue Jul 31, 2024
798d80a
feat(entity): Add cascade delete to options in Product entity
NextrPlue Jul 31, 2024
d129085
feat(dto): Add JsonProperty
NextrPlue Jul 31, 2024
27afea4
feat(service): handle product options in ProductService
NextrPlue Jul 31, 2024
480bb30
feat(controller): handle product creation with options
NextrPlue Jul 31, 2024
8dd50fe
feaet(service): add exception handling for non-existent products
NextrPlue Jul 31, 2024
b6428ef
feat(controller): handle exceptions for non-existent products in Prod…
NextrPlue Jul 31, 2024
df37edd
feat(controller): Add exception handling for non-existent categories
NextrPlue Jul 31, 2024
10191cb
feat(service): handle exceptions for non-existent categories in Categ…
NextrPlue Jul 31, 2024
da38718
chore(service): Edit exception message
NextrPlue Jul 31, 2024
79b2e5e
chore(controller): Edit response status code
NextrPlue Jul 31, 2024
3cbfbfa
feat(service): handle exceptions for non-existent products in OptionS…
NextrPlue Jul 31, 2024
1218e33
feat(controller): Add exception handling for non-existent products
NextrPlue Jul 31, 2024
b446f5c
feat(dto): add WishRequest dto
NextrPlue Jul 31, 2024
5d3a65a
feat(dto): Add imageUrl filed to WishResponse
NextrPlue Jul 31, 2024
6c56070
feat(entity): Delete productNumber and related methods
NextrPlue Jul 31, 2024
a6a2c2a
chore(service): Edit exception messages
NextrPlue Jul 31, 2024
65cefc7
chore(controller): Edit response body message
NextrPlue Jul 31, 2024
5455896
feat(service): Update WishlistService to match API specifications
NextrPlue Jul 31, 2024
119599c
refactor(controller): update WishlistController to match API specific…
NextrPlue Jul 31, 2024
6dc34ef
fix(config): exclude DELETE requests from JWT token verification
NextrPlue Jul 31, 2024
a104462
refactor(controller): convert CategoryController to RestController
NextrPlue Jul 31, 2024
26d415f
feat(config): add initial category data loader
NextrPlue Jul 31, 2024
745659f
feat(entity): create Order entity
NextrPlue Aug 1, 2024
1007e9b
feat(dto): create OrderRequest DTO
NextrPlue Aug 1, 2024
fc25daa
feat(dto): create OrderResponse DTO
NextrPlue Aug 1, 2024
564eb7e
feat(controller): implement OrderController for order menagement
NextrPlue Aug 1, 2024
495c85c
feat(service): implement OrderService for order processing
NextrPlue Aug 1, 2024
a70e248
feat(repository): add OrderRepository for Order entity
NextrPlue Aug 1, 2024
521b6be
fix(config): Resolve CORS issues between client and server
NextrPlue Aug 1, 2024
852369f
fix(config): add exposed header 'Location'
NextrPlue Aug 2, 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ out/

### Mac OS ###
.DS_Store

### Application Properties ###
/src/main/resources/application-kakao.properties
7 changes: 7 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
implementation 'org.springframework.boot:spring-boot-starter-hateoas'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/gift/Application.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.boot.context.properties.ConfigurationPropertiesScan;

@ConfigurationPropertiesScan
@SpringBootApplication
public class Application {
public static void main(String[] args) {
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/gift/config/AppConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package gift.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;

@Configuration
public class AppConfig {
@Bean
public RestClient restClient() {
return RestClient.builder().build();
}
}
31 changes: 31 additions & 0 deletions src/main/java/gift/config/CategoryDataLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package gift.config;

import gift.dto.CategoryRequest;
import gift.service.CategoryService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CategoryDataLoader {

@Bean
public CommandLineRunner loadCategoryData(CategoryService categoryService) {
return args -> {
categoryService.save(new CategoryRequest("교환권", "RED", "http://example.com/coupon.jpg", "교환권 관련 카테고리"));
categoryService.save(new CategoryRequest("상품권", "INDIGO", "http://example.com/voucher.jpg", "상품권 관련 카테고리"));
categoryService.save(new CategoryRequest("뷰티", "YELLOW", "http://example.com/beauty.jpg", "뷰티 관련 카테고리"));
categoryService.save(new CategoryRequest("패션", "GREEN", "http://example.com/fashion.jpg", "패션 관련 카테고리"));
categoryService.save(new CategoryRequest("식품", "BLUE", "http://example.com/food.jpg", "식품 관련 카테고리"));
categoryService.save(new CategoryRequest("와인/양주/전통주", "NAVY", "http://example.com/alchol.jpg", "와인/양주/전통주 관련 카테고리"));
categoryService.save(new CategoryRequest("리빙/도서", "PURPLE", "http://example.com/book.jpg", "리빙/도서 관련 카테고리"));
categoryService.save(new CategoryRequest("레저/스포츠", "BROWN", "http://example.com/sports.jpg", "레저/스포츠 관련 카테고리"));
categoryService.save(new CategoryRequest("아티스트/캐릭터", "PINK", "http://example.com/artist.jpg", "아티스트/캐릭터 관련 카테고리"));
categoryService.save(new CategoryRequest("유아동/반려", "WHITE", "http://example.com/pet.jpg", "유아동/반려 관련 카테고리"));
categoryService.save(new CategoryRequest("디지털/가전", "BLACK", "http://example.com/digital.jpg", "디지털/가전 관련 카테고리"));
categoryService.save(new CategoryRequest("카카오프렌즈", "ORANGE", "http://example.com/friends.jpg", "카카오프렌즈 관련 카테고리"));
categoryService.save(new CategoryRequest("트렌드 선물", "CYAN", "http://example.com/trend.jpg", "트렌드 선물 관련 카테고리"));
categoryService.save(new CategoryRequest("백화점", "GRAY", "http://example.com/department.jpg", "백화점 관련 카테고리"));
};
}
}
35 changes: 35 additions & 0 deletions src/main/java/gift/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package gift.config;

import gift.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

private final JwtInterceptor jwtInterceptor;

@Autowired
public WebConfig(JwtInterceptor jwtInterceptor) {
this.jwtInterceptor = jwtInterceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/api/auth/**", "/h2-console/**", "/api/products/**", "/api/categories/**", "/api/options/**", "/api/wishes/**/{id}");
}

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.exposedHeaders("Location");
}
}
66 changes: 66 additions & 0 deletions src/main/java/gift/controller/CategoryController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package gift.controller;

import gift.dto.CategoryRequest;
import gift.dto.CategoryResponse;
import gift.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.spel.ast.OperatorBetween;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/categories")
public class CategoryController {

private final CategoryService categoryService;

@Autowired
public CategoryController(CategoryService categoryService) {
this.categoryService = categoryService;
}

@GetMapping
public ResponseEntity<?> getAllCategories() {
List<CategoryResponse> categories = categoryService.findAll();

Map<String, Object> response = new HashMap<>();
response.put("categories", categories);

return ResponseEntity.ok(response);
}

@GetMapping("/{id}")
public ResponseEntity<?> getCategoryById(@PathVariable Long id) {
try {
CategoryResponse category = categoryService.findById(id);

Map<String, Object> response = new HashMap<>();
response.put("category", category);

return ResponseEntity.ok(response);
} catch (IllegalArgumentException e) {
return ResponseEntity.status(404).body(e.getMessage());
}
}

@PostMapping
public ResponseEntity<?> addCategory(@RequestBody CategoryRequest categoryRequest) {
categoryService.save(categoryRequest);
return ResponseEntity.ok().build();
}

@DeleteMapping("/{id}")
public ResponseEntity<?> deleteCategory(@PathVariable Long id) {
try {
categoryService.delete(id);
return ResponseEntity.ok().build();
} catch (IllegalArgumentException e) {
return ResponseEntity.status(404).body(e.getMessage());
}
}
}
54 changes: 54 additions & 0 deletions src/main/java/gift/controller/MemberController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package gift.controller;

import gift.service.MemberService;
import gift.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/auth")
public class MemberController {

private final MemberService memberService;
private final JwtUtil jwtUtil;

@Value("${kakao.client-id}")
private String kakaoClientId;

@Value("${kakao.redirect-url}")
private String kakaoRedirectUri;

@Autowired
public MemberController(MemberService memberService, JwtUtil jwtUtil) {
this.memberService = memberService;
this.jwtUtil = jwtUtil;
}

@GetMapping("/kakao")
public ResponseEntity<Void> redirectToKakaoAuth() {
String kakaoAuthUrl = "https://kauth.kakao.com/oauth/authorize?response_type=code&client_id="
+ kakaoClientId + "&redirect_uri=" + kakaoRedirectUri;
HttpHeaders headers = new HttpHeaders();
headers.add("Location", kakaoAuthUrl);
return ResponseEntity.status(302).headers(headers).build();
}

@GetMapping("/kakao/callback")
public ResponseEntity<?> handleKakaoCallback(@RequestParam("code") String code) {
try {
String token = memberService.kakaoLogin(code);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + token);
headers.add("Content-Type", "application/json");
return ResponseEntity.ok().headers(headers).body("{\"token\": \"" + token + "\"}");
} catch (Exception e) {
return ResponseEntity.status(400).body("Authentication failed");
}
}
}
58 changes: 58 additions & 0 deletions src/main/java/gift/controller/OptionController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package gift.controller;

import gift.dto.OptionRequest;
import gift.dto.OptionResponse;
import gift.service.OptionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/options")
public class OptionController {

private final OptionService optionService;

@Autowired
public OptionController(OptionService optionService) {
this.optionService = optionService;
}

@GetMapping("/{productId}")
public ResponseEntity<?> getOptions(@PathVariable Long productId) {
try {
List<OptionResponse> options = optionService.findByProductId(productId);

Map<String, Object> response = new HashMap<>();
response.put("options", options);

return ResponseEntity.ok(response);
} catch (IllegalArgumentException e) {
return ResponseEntity.status(404).body(e.getMessage());
}
}

@PostMapping
public ResponseEntity<?> addOption(@RequestBody OptionRequest optionRequest) {
try {
optionService.save(optionRequest);
return ResponseEntity.ok().build();
} catch (IllegalArgumentException e) {
return ResponseEntity.status(404).body(e.getMessage());
}
}

@DeleteMapping("/{optionId}")
public ResponseEntity<?> deleteOption(@PathVariable Long optionId) {
try {
optionService.delete(optionId);
return ResponseEntity.ok().build();
} catch (IllegalArgumentException e) {
return ResponseEntity.status(404).body(e.getMessage());
}
}
}
39 changes: 39 additions & 0 deletions src/main/java/gift/controller/OrderController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package gift.controller;

import gift.dto.OrderRequest;
import gift.service.OrderService;
import gift.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/api/orders")
public class OrderController {

private final OrderService orderService;
private final JwtUtil jwtUtil;

@Autowired
public OrderController(OrderService orderService, JwtUtil jwtUtil) {
this.orderService = orderService;
this.jwtUtil = jwtUtil;
}

@PostMapping
public ResponseEntity<?> createOrder(@RequestBody OrderRequest orderRequest, @RequestHeader("Authorization") String token) {
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
} else {
return ResponseEntity.status(401).body("Missing or invalid Authorization header");
}

Claims claims = jwtUtil.extractClaims(token);
Long memberId = Long.parseLong(claims.getSubject());

orderService.createOrder(orderRequest, memberId);
return ResponseEntity.ok().build();
}
}
Loading