Skip to content
Open
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
74 changes: 74 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Springboot-MetaMall-Project


# 기능정리
* 회원가입 (POST)
* 로그인 (POST)
* JWT 토큰 응답
* 상품등록 (POST)
* 인증 필요, 판매자 권한
* 상품목록보기 (GET)
* 인증 필요, 권한 없음
* 상품상세보기 (GET)
* 인증 필요, 권한 없음
* 상품수정하기 (PUT)
* 인증 필요, 판매자 권한
* 상품삭제하기 (DELETE)
* 인증 필요, 판매자 권한
* 주문하기 (POST) - OrderProduct를 생성하여, OrderSheet에 추가하세요
* 인증 필요, 고객 권한
* 고객입장 - 주문목록보기 (GET)
* 인증 필요, 고객 권한, 본인의 주문목록만 볼 수 있어야 함
* 판매자입장 - 주문목록보기 (GET)
* 인증 필요, 판매자 권한, 모든 주문목록을 볼 수 있음
* 고객입장 - 주문취소하기 (DELETE) - Casecade 옵션을 활용하세요. (양방향 매핑)
* 인증 필요, 고객 권한, 본인의 주문만 취소할 수 있다.
* 판매자입장 - 주문취소하기 (DELETE) - Casecade 옵션을 활용하세요. (양방향 매핑)
* 인증 필요, 판매자 권한


# REST API

* 회원가입
POST http://localhost:8081/join
```
{
"username": "ssar",
"password": "1234",
"email": "[email protected]",
"role": "ADMIN"
}
```

* 로그인
POST http://localhost:8081/login
```
{
"username": "ssar",
"password": "1234"
}
```
* 상품 등록
POST http://localhost:8081/save
```
{
"name": "computer",
"price": 30000,
"quantity": 100,
"role": "SELLER"
}
```
* 상품 전체 조회
GET http://localhost:8081/listAll

* 상품 개별 조회
GET http://localhost:8081/product/1

* 상품 개별 수정
PUT http://localhost:8081/product/1

* 상품 삭제
DELETE http://localhost:8081/product/1

# 느낀점
* 전체 적인 이해도가 부족하여 문제가 발생 시 해결이 잘 되지 않음
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ repositories {
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation group: 'com.auth0', name: 'java-jwt', version: '4.3.0'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
Expand Down
14 changes: 8 additions & 6 deletions src/main/java/shop/mtcoding/metamall/MetamallApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import shop.mtcoding.metamall.model.orderproduct.OrderProduct;
import shop.mtcoding.metamall.model.orderproduct.OrderProductRepository;
import shop.mtcoding.metamall.model.ordersheet.OrderSheet;
import shop.mtcoding.metamall.model.ordersheet.OrderSheetRepository;
import shop.mtcoding.metamall.model.order.product.OrderProductRepository;
import shop.mtcoding.metamall.model.order.sheet.OrderSheetRepository;
import shop.mtcoding.metamall.model.product.ProductRepository;
import shop.mtcoding.metamall.model.user.User;
import shop.mtcoding.metamall.model.user.UserRepository;

import java.util.Arrays;

@SpringBootApplication
public class MetamallApplication {

Expand All @@ -20,8 +20,10 @@ CommandLineRunner initData(UserRepository userRepository, ProductRepository prod
return (args)->{
// 여기에서 save 하면 됨.
// bulk Collector는 saveAll 하면 됨.
User ssar = User.builder().username("ssar").password("1234").email("[email protected]").role("USER").build();
userRepository.save(ssar);
User ssar = User.builder().username("ssar").password("1234").email("[email protected]").status(true).role("USER").build();
User seller = User.builder().username("seller").password("1234").email("[email protected]").status(true).role("SELLER").build();
User admin = User.builder().username("admin").password("1234").email("[email protected]").status(true).role("ADMIN").build();
userRepository.saveAll(Arrays.asList(ssar, seller, admin));
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package shop.mtcoding.metamall.config;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import shop.mtcoding.metamall.core.filter.MyJwtVerifyFilter;


@Configuration
public class MyFilterRegisterConfig {
@Bean
public FilterRegistrationBean<?> jwtVerifyFilterAdd() {
FilterRegistrationBean<MyJwtVerifyFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new MyJwtVerifyFilter());
registration.addUrlPatterns("/user/*");
registration.addUrlPatterns("/products/*");
registration.addUrlPatterns("/orders/*");
registration.addUrlPatterns("/admin/*");
registration.addUrlPatterns("/seller/*");
registration.setOrder(1);
return registration;
}
}
49 changes: 49 additions & 0 deletions src/main/java/shop/mtcoding/metamall/config/MyWebMvcConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package shop.mtcoding.metamall.config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import shop.mtcoding.metamall.core.interceptor.MyAdminInterceptor;
import shop.mtcoding.metamall.core.interceptor.MySellerInterceptor;
import shop.mtcoding.metamall.core.resolver.MySessionArgumentResolver;

import java.util.List;

@RequiredArgsConstructor
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {

private final MyAdminInterceptor adminInterceptor;
private final MySellerInterceptor sellerInterceptor;
private final MySessionArgumentResolver mySessionArgumentResolver;

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*") // GET, POST, PUT, DELETE (Javascript 요청 허용)
.allowedOriginPatterns("*") // 모든 IP 주소 허용 (프론트 앤드 IP만 허용하게 변경해야함. * 안됨)
.allowCredentials(true)
.exposedHeaders("Authorization"); // 옛날에는 디폴트로 브라우저에 노출되어 있었는데 지금은 아님
}


// AOP는 매개변수 값 확인해서 권한 비교해야할 때 사용
// Interceptor는 세션 권한으로 체크할 때 사용
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(adminInterceptor)
.addPathPatterns("/admin/**");

registry.addInterceptor(sellerInterceptor)
.addPathPatterns("/seller/**");
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(mySessionArgumentResolver);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package shop.mtcoding.metamall.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import shop.mtcoding.metamall.core.session.SessionUser;
import shop.mtcoding.metamall.dto.order.OrderProductRequest;
import shop.mtcoding.metamall.model.product.ProductRepository;
import shop.mtcoding.metamall.model.user.User;
import shop.mtcoding.metamall.model.user.UserRepository;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Optional;


@RequiredArgsConstructor
@RequestMapping("/order")
public class OrderController {

private final ProductRepository productRepository;
private final UserRepository userRepository;
private final HttpSession session;

// 상품 주문하기
@PostMapping("/save/{id}")
public ResponseEntity<?> save(
@PathVariable Long id,
@RequestBody OrderProductRequest.OrderDto orderDto, HttpServletRequest request) {

Optional<User> userOP = userRepository.findById(id);
SessionUser sessionUser = (SessionUser)session.getAttribute("sessionUser");

return null;
}

// 주문 목록 보기 - 사용자
@GetMapping("/list")
public ResponseEntity<?> orderList() {
/*
List<OrderProduct> orderList = orderProductRepository.findAll();

if(orderList.isEmpty())
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("주문 물품이 존재하지 않습니다");

ResponseDto<List<OrderProduct>> responseDto = new ResponseDto<>();
responseDto.satData(orderList);

return ResponseEntity.ok().body(responseDto);

*/
return null;
}
}
131 changes: 131 additions & 0 deletions src/main/java/shop/mtcoding/metamall/controller/ProductController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package shop.mtcoding.metamall.controller;

import lombok.RequiredArgsConstructor;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import shop.mtcoding.metamall.dto.ResponseDTO;
import shop.mtcoding.metamall.dto.product.ProductRequest;
import shop.mtcoding.metamall.model.product.Product;
import shop.mtcoding.metamall.model.product.ProductRepository;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@RequiredArgsConstructor
@RestController
@RequestMapping("/product")
public class ProductController {

private final ProductRepository productRepository;

// 상품 등록
@PostMapping("/save")
public ResponseEntity<?> save(
@RequestBody ProductRequest.ProductDto productDto,
HttpServletRequest request) {

Product product = Product.builder()
.name(productDto.getName())
.price(productDto.getPrice())
.qty(productDto.getQuantity())
.build();

productRepository.save(product);
ResponseDTO<?> responseDto = new ResponseDTO<>().data(product);

return ResponseEntity.ok().body(responseDto);
}

// 상품 전체 조회
@GetMapping("/listAll")
public ResponseEntity<?> productList() {

List<Product> productList = productRepository.findAll();

if(productList.isEmpty())
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("물품이 존재하지 않습니다");

ResponseDTO<?> responseDto = new ResponseDTO<>().data(productList);

return ResponseEntity.ok().body(responseDto);
}

// 상품 개별 조회
@GetMapping("/{id}")
public ResponseEntity<?> findById(@PathVariable Long id) {

Optional<Product> productOP = productRepository.findById(id);

if(productOP.isPresent()) {
ResponseDTO<?> responseDto = new ResponseDTO<>().data(productOP);
return ResponseEntity.ok().body(responseDto);
}

ResponseDTO<?> responseDto =
new ResponseDTO<>().fail(
HttpStatus.BAD_REQUEST,
"Product Not Found",
"존재하지 않는 물품입니다");

return ResponseEntity.ok().body(responseDto);
}

// 상품 개별 수정
@PutMapping("/{id}")
public ResponseEntity<?> modify(
@PathVariable Long id,
@RequestBody ProductRequest.ProductDto productDto) {

Optional<Product> productOP = productRepository.findById(id);

if(productOP.isPresent()) {

//roduct product = productOP.get();

Product product = Product.builder()
.name(productDto.getName())
.price(productDto.getPrice())
.qty(productDto.getQuantity())
.build();

Product savedProduct = productRepository.save(product);
productRepository.flush();

ResponseDTO<?> responseDto = new ResponseDTO<>().data(savedProduct);
return ResponseEntity.ok().body(responseDto);
}

ResponseDTO<?> responseDto =
new ResponseDTO<>().fail(
HttpStatus.BAD_REQUEST,
"Product Not Found",
"존재하지 않는 물품입니다");

return ResponseEntity.ok().body(responseDto);
}

// 상품 개별 삭제
@DeleteMapping("/{id}")
public ResponseEntity<?> delete(
@PathVariable Long id,
@RequestBody ProductRequest.ProductDto productDto) {

Optional<Product> productOP = productRepository.findById(id);

if (productOP.isPresent()) {
productRepository.deleteById(id);
return ResponseEntity.ok().body("삭제 완료 되었습니다");
}

ResponseDTO<?> responseDto =
new ResponseDTO<>().fail(
HttpStatus.BAD_REQUEST,
"Product Not Found",
"존재하지 않는 물품입니다");

return ResponseEntity.ok().body(responseDto);
}
}
Loading