diff --git a/README.md b/README.md new file mode 100644 index 0000000..2cdfd5c --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ + + +# Springboot-MetaMall-Project + +MetaMall은 사용자가 상품을 찾아보고, 구매하고, 관리할 수 있는 전자상거래 토이 프로젝트 입니다. + +## 기능 + +**사용자 인증** + +* 사용자 등록 및 로그인 기능 + +* 고객과 판매자를 위한 역할 기반 접근 제어 + +**상품 관리** + +* 상품 등록, 수정, 삭제, 목록 보기 + +**주문 관리** + +* 주문 등록, 취소, 목록 보기 + +**에러 처리** + +* 모든 에러 로그기록 + + +![](https://velog.velcdn.com/images/carrot1st/post/53351617-cd76-4dad-ae26-e0d63b3dbd4c/image.png) + +![](https://velog.velcdn.com/images/carrot1st/post/1b0f4d04-08b4-4b60-ae26-0c8fa6ce8c3d/image.png) + +![](https://velog.velcdn.com/images/carrot1st/post/e2086d03-a188-4e6d-ae60-2ed16927edd0/image.png) + +![](https://velog.velcdn.com/images/carrot1st/post/d99b20c5-21d8-4a56-8c46-fac9a538aa6d/image.png) + +![](https://velog.velcdn.com/images/carrot1st/post/6aae1c23-0607-48ba-be34-742688639d68/image.png) + +![](https://velog.velcdn.com/images/carrot1st/post/ab1f263a-4e11-4358-a933-43b221ec4f16/image.png) + +![](https://velog.velcdn.com/images/carrot1st/post/530ddb3e-9476-4a99-92ae-6dfe492625ee/image.png) + +![](https://velog.velcdn.com/images/carrot1st/post/ec4c2541-4151-4d35-9e74-0a52090a90d7/image.png) + +![](https://velog.velcdn.com/images/carrot1st/post/5e6124f7-4c77-4f39-8708-d86536ee1a95/image.png) + +![](https://velog.velcdn.com/images/carrot1st/post/3c897c96-4d5a-46f3-9a4e-511805692a6b/image.png) + + diff --git a/build.gradle b/build.gradle index 4943187..0b957f8 100644 --- a/build.gradle +++ b/build.gradle @@ -22,11 +22,13 @@ dependencies { 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' - compileOnly 'org.projectlombok:lombok' + implementation 'org.springframework.boot:spring-boot-starter-validation' + compileOnly 'org.projectlombok:lombok:1.18.26' developmentOnly 'org.springframework.boot:spring-boot-devtools' - runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.h2database:h2:2.1.214' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' } tasks.named('test') { diff --git a/src/main/java/shop/mtcoding/metamall/MetamallApplication.java b/src/main/java/shop/mtcoding/metamall/MetamallApplication.java index 487bb62..e42c3b9 100644 --- a/src/main/java/shop/mtcoding/metamall/MetamallApplication.java +++ b/src/main/java/shop/mtcoding/metamall/MetamallApplication.java @@ -8,6 +8,7 @@ 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.product.Product; import shop.mtcoding.metamall.model.product.ProductRepository; import shop.mtcoding.metamall.model.user.User; import shop.mtcoding.metamall.model.user.UserRepository; @@ -20,8 +21,17 @@ CommandLineRunner initData(UserRepository userRepository, ProductRepository prod return (args)->{ // 여기에서 save 하면 됨. // bulk Collector는 saveAll 하면 됨. - User ssar = User.builder().username("ssar").password("1234").email("ssar@nate.com").role("USER").build(); + User ssar = User.builder().username("user").password("1234").email("ssar@nate.com").role("USER").build(); userRepository.save(ssar); + + User mook = User.builder().username("seller").password("1234").email("ssar@nate.com").role("SELLER").build(); + userRepository.save(mook); + + Product product = Product.builder().name("Apple").price(1000).qty(10).build(); + productRepository.save(product); + + Product product2 = Product.builder().name("Kiwi").price(2000).qty(20).build(); + productRepository.save(product2); }; } diff --git a/src/main/java/shop/mtcoding/metamall/config/FilterRegisterConfig.java b/src/main/java/shop/mtcoding/metamall/config/FilterRegisterConfig.java index f5ea4db..42d411f 100644 --- a/src/main/java/shop/mtcoding/metamall/config/FilterRegisterConfig.java +++ b/src/main/java/shop/mtcoding/metamall/config/FilterRegisterConfig.java @@ -8,11 +8,16 @@ @Configuration public class FilterRegisterConfig { + @Bean - public FilterRegistrationBean jwtVerifyFilterAdd() { + public FilterRegistrationBean jwtVerifyFilterAddForItem() { FilterRegistrationBean registration = new FilterRegistrationBean<>(); registration.setFilter(new JwtVerifyFilter()); - registration.addUrlPatterns("/user/*"); + registration.addUrlPatterns("/validate-token"); + registration.addUrlPatterns("/item/*"); + registration.addUrlPatterns("/items"); + registration.addUrlPatterns("/order/*"); + registration.addUrlPatterns("/orders/*"); registration.setOrder(1); return registration; } diff --git a/src/main/java/shop/mtcoding/metamall/controller/HomeController.java b/src/main/java/shop/mtcoding/metamall/controller/HomeController.java new file mode 100644 index 0000000..4f3b90e --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/controller/HomeController.java @@ -0,0 +1,45 @@ +package shop.mtcoding.metamall.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class HomeController +{ + @RequestMapping("/") + public String home() + { + return "home"; + } + + @GetMapping("/login") + public String login() { + return "login"; + } + + @GetMapping("/register") + public String register() { + return "register"; + } + + @GetMapping("/productmanagement") + public String productmanagement() + { + return "productmanagement"; + } + + @GetMapping("/ordermanagement") + public String ordermanagement() + { + return "ordermanagement"; + } + + @PostMapping("/validate-token") + public ResponseEntity validateToken() + { + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/shop/mtcoding/metamall/controller/OrderController.java b/src/main/java/shop/mtcoding/metamall/controller/OrderController.java new file mode 100644 index 0000000..fc827f1 --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/controller/OrderController.java @@ -0,0 +1,276 @@ +package shop.mtcoding.metamall.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import shop.mtcoding.metamall.core.session.LoginUser; +import shop.mtcoding.metamall.dto.ResponseDto; +import shop.mtcoding.metamall.dto.order.OrderSheetDto; +import shop.mtcoding.metamall.dto.product.OrderProductRequest; +import shop.mtcoding.metamall.model.log.error.ErrLogService; +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.ordersheet.OrderStatus; +import shop.mtcoding.metamall.model.product.Product; +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.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Controller +public class OrderController +{ + private final UserRepository userRepository; + private final OrderSheetRepository orderSheetRepository; + private final ProductRepository productRepository; + private final OrderProductRepository orderProductRepository; + private final ErrLogService err; + + @ResponseBody + @Transactional + @PostMapping("/order/create") + public ResponseEntity placeOrder(@RequestBody List orderProductRequests, HttpServletRequest request) { + HttpSession session = request.getSession(); + LoginUser loginUser = (LoginUser) session.getAttribute("loginUser"); + + if (!loginUser.getRole().equals("USER")) { + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(), "고객 권한이 필요합니다."), "")); + //return ResponseEntity.status(403).body("고객 권한이 필요합니다."); + } + + Optional userOptional = userRepository.findById(loginUser.getId()); + + if(userOptional.isPresent() == false) + { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(), "사용자 정보를 찾을 수 없습니다."), "")); + //throw new RuntimeException("사용자 정보를 찾을 수 없습니다"); + } + + if(orderProductRequests.isEmpty()) + { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(), "주문 내용이 없습니다."), "")); + } + + User user = userOptional.get(); + + OrderSheet orderSheet = OrderSheet.builder().user(user).orderStatus(OrderStatus.ORDER).build(); + + int totalPrice = 0; + for (OrderProductRequest orderProductRequest : orderProductRequests) + { + Optional OpProduct = productRepository.findById(orderProductRequest.getProductId()); + + if(false == OpProduct.isPresent()) + { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(), "상품 정보를 찾을 수 없습니다."), "")); + } + + Product product = OpProduct.get(); + + int count = orderProductRequest.getCount(); + int orderPrice = product.getPrice() * count; + + try + { + product.removeStock(count);//영속성에 의한 처리됨 + } + catch (Exception e) + { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(), "재고가 부족합니다"), "")); + } + + OrderProduct orderProduct = OrderProduct.builder() + .product(product) + .count(count) + .orderPrice(orderPrice) + .orderSheet(orderSheet) + .orderStatus(OrderStatus.ORDER) + .build(); + + orderProductRepository.save(orderProduct); + orderSheet.getOrderProductList().add(orderProduct); + + totalPrice += orderPrice; + } + orderSheet.setTotalPrice(totalPrice); + + OrderSheet savedOrderSheet = orderSheetRepository.save(orderSheet); + + ResponseDto responseDto = new ResponseDto<>().data(savedOrderSheet); + + return ResponseEntity.ok(responseDto); + } + + @ResponseBody + @GetMapping("/orders/user") + public ResponseEntity getAllOrdersOfUser(HttpServletRequest request) + { + HttpSession session = request.getSession(); + LoginUser loginUser = (LoginUser) session.getAttribute("loginUser"); + + if (!loginUser.getRole().equals("USER")) { + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"고객 권한이 필요합니다."), "")); + + //throw new Exception403("고객 권한이 필요합니다."); + } + + List findSheets = orderSheetRepository.findByUserIdAndStatusNot(loginUser.getId(), OrderStatus.CANCEL); + + // OrderSheet에서 OrderSheetDto로 데이터를 옮기기 + List orderSheetDtos = findSheets.stream() + .map(orderSheet -> new OrderSheetDto(orderSheet)) + .collect(Collectors.toList()); + + ResponseDto responseDto = new ResponseDto<>().data(orderSheetDtos ); + return ResponseEntity.ok().body(responseDto); + } + + @ResponseBody + @GetMapping("/orders/seller") + public ResponseEntity getAllOrdersOfSeller(HttpServletRequest request) + { + HttpSession session = request.getSession(); + LoginUser loginUser = (LoginUser) session.getAttribute("loginUser"); + + if (!loginUser.getRole().equals("SELLER")) { + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"판매자 권한이 필요합니다."), "")); + + //throw new Exception403("판매자 권한이 필요합니다."); + } + + List findSheets = orderSheetRepository.findByStatusNot(OrderStatus.CANCEL); + + // OrderSheet에서 OrderSheetDto로 데이터를 옮기기 + List orderSheetDtos = findSheets.stream() + .map(orderSheet -> new OrderSheetDto(orderSheet)) + .collect(Collectors.toList()); + + ResponseDto responseDto = new ResponseDto<>().data(orderSheetDtos); + return ResponseEntity.ok().body(responseDto); + } + + @ResponseBody + @Transactional + @DeleteMapping("/order/user/cancel/{orderId}") + public ResponseEntity cancelOrderOfUser(@PathVariable("orderId") Long orderId, HttpServletRequest request) + { + HttpSession session = request.getSession(); + LoginUser loginUser = (LoginUser) session.getAttribute("loginUser"); + + if (!loginUser.getRole().equals("USER")) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"고객 권한이 필요합니다."), "")); + //throw new Exception403("고객 권한이 필요합니다."); + } + + Optional orderSheetOptional = orderSheetRepository.findById(orderId); + + if (!orderSheetOptional.isPresent()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"주문 정보를 찾을 수 없습니다."), "")); + //throw new Exception404("주문 정보를 찾을 수 없습니다."); + } + + OrderSheet orderSheet = orderSheetOptional.get(); + orderSheet.setStatus(OrderStatus.CANCEL); + + if(loginUser.getId() != orderSheet.getUser().getId()) + { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"유저와 주문자가 불일치 합니다."), "")); + //throw new Exception404("유저와 주문자가 불일치 합니다."); + } + + + for (OrderProduct orderProduct : orderSheet.getOrderProductList()) { + orderProduct.setStatus(OrderStatus.CANCEL); + Product product = orderProduct.getProduct(); + product.addStock(orderProduct.getCount()); + productRepository.save(product); + } + + //OrderSheet updatedOrderSheet = orderSheetRepository.save(orderSheet); + + ResponseDto responseDto = new ResponseDto<>().data(orderSheet); + return ResponseEntity.ok(responseDto); + } + + @ResponseBody + @Transactional + @DeleteMapping("/order/seller/cancel/{orderId}") + public ResponseEntity cancelOrderOfSeller(@PathVariable("orderId") Long orderId, HttpServletRequest request) + { + HttpSession session = request.getSession(); + LoginUser loginUser = (LoginUser) session.getAttribute("loginUser"); + + if (!loginUser.getRole().equals("SELLER")) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"판매자 권한이 필요합니다."), "")); + //throw new Exception403("판매자 권한이 필요합니다."); + } + + Optional orderSheetOptional = orderSheetRepository.findById(orderId); + + if (!orderSheetOptional.isPresent()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"주문 정보를 찾을 수 없습니다."), "")); + //throw new Exception404("주문 정보를 찾을 수 없습니다."); + } + + OrderSheet orderSheet = orderSheetOptional.get(); + orderSheet.setStatus(OrderStatus.CANCEL); + + //판매자는 어떤 주문이든 취소가능 + + for (OrderProduct orderProduct : orderSheet.getOrderProductList()) { + orderProduct.setStatus(OrderStatus.CANCEL); + Product product = orderProduct.getProduct(); + product.addStock(orderProduct.getCount()); + productRepository.save(product); + } + + //OrderSheet updatedOrderSheet = orderSheetRepository.save(orderSheet); + + ResponseDto responseDto = new ResponseDto<>().data(orderSheet); + return ResponseEntity.ok(responseDto); + } + + @GetMapping("/customerplaceorder") + public String customerPlaceOrder() + { + return "customerplaceorder"; + } + + @GetMapping("/customerorderlist") + public String customerOrderList() + { + return "customerorderlist"; + } + + @GetMapping("/sellerorderlist") + public String sellerOrderList() + { + return "sellerorderlist"; + } +} diff --git a/src/main/java/shop/mtcoding/metamall/controller/ProductController.java b/src/main/java/shop/mtcoding/metamall/controller/ProductController.java new file mode 100644 index 0000000..d1a39c0 --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/controller/ProductController.java @@ -0,0 +1,168 @@ +package shop.mtcoding.metamall.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import shop.mtcoding.metamall.core.exception.Exception401; +import shop.mtcoding.metamall.core.exception.Exception403; +import shop.mtcoding.metamall.core.exception.Exception404; +import shop.mtcoding.metamall.core.jwt.JwtProvider; +import shop.mtcoding.metamall.core.session.LoginUser; +import shop.mtcoding.metamall.dto.ResponseDto; +import shop.mtcoding.metamall.model.log.error.ErrLogService; +import shop.mtcoding.metamall.model.product.Product; +import shop.mtcoding.metamall.model.product.ProductRepository; +import shop.mtcoding.metamall.model.user.User; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.util.List; +import java.util.Optional; + +@RequiredArgsConstructor +@Controller +public class ProductController +{ + private final ProductRepository productRepository; + + private final ErrLogService err; + + @ResponseBody + @Transactional + @PostMapping("/item/register") + public ResponseEntity register(@RequestBody Product product, HttpServletRequest request) + { + HttpSession session = request.getSession(); + LoginUser loginUser = (LoginUser) session.getAttribute("loginUser"); + + if (!loginUser.getRole().equals("SELLER")) { + //throw new Exception403("판매자만 상품을 등록할 수 있습니다."); + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"판매자만 상품을 등록할 수 있습니다"), "")); + } + + Product registeredProduct = productRepository.save(product); + + ResponseDto responseDto = new ResponseDto<>().data(registeredProduct); + + return ResponseEntity.ok().body(responseDto); + } + + @ResponseBody + @GetMapping("/items") + public ResponseEntity getAllItems(HttpServletRequest request) { + + List products = productRepository.findAll(); + + ResponseDto responseDto = new ResponseDto<>().data(products); + return ResponseEntity.ok().body(responseDto); + } + + @ResponseBody + @GetMapping("/item/{itemId}") + public ResponseEntity getItemDetail(@PathVariable("itemId") Long itemId, HttpServletRequest request) { + + HttpSession session = request.getSession(); + LoginUser loginUser = (LoginUser) session.getAttribute("loginUser"); + + Optional productOptional = productRepository.findById(itemId); + + if (!productOptional.isPresent()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"상품을 찾을 수 없습니다"), "")); + // throw new Exception404("상품을 찾을 수 없습니다"); + } + + Product product = productOptional.get(); + ResponseDto responseDto = new ResponseDto<>().data(product); + return ResponseEntity.ok().body(responseDto); + } + + @ResponseBody + @Transactional + @PutMapping("/item/{itemId}") + public ResponseEntity updateItem(@PathVariable("itemId") Long itemId, + @RequestBody Product updatedProduct, + HttpServletRequest request) + { + HttpSession session = request.getSession(); + LoginUser loginUser = (LoginUser) session.getAttribute("loginUser"); + if (!loginUser.getRole().equals("SELLER")) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"판매자만 상품을 수정 할 수 있습니다"), "")); + } + + Optional productOptional = productRepository.findById(itemId); + + if (!productOptional.isPresent()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"상품을 찾을 수 없습니다"), "")); + } + + Product product = productOptional.get(); + + // 상품 정보 수정 + product.setName(updatedProduct.getName()); + product.setPrice(updatedProduct.getPrice()); + product.setQty(updatedProduct.getQty()); + + // 수정된 상품 정보 저장 + Product savedProduct = productRepository.save(product); + ResponseDto responseDto = new ResponseDto<>().data(savedProduct); + return ResponseEntity.ok().body(responseDto); + } + + @ResponseBody + @Transactional + @DeleteMapping("/item/{itemId}") + public ResponseEntity deleteItem(@PathVariable("itemId") Long itemId, HttpServletRequest request) { + HttpSession session = request.getSession(); + LoginUser loginUser = (LoginUser) session.getAttribute("loginUser"); + if (!loginUser.getRole().equals("SELLER")) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"판매자만 상품을 삭제할 수 있습니다."), "")); + //throw new Exception403("판매자만 상품을 삭제할 수 있습니다."); + } + + Optional productOptional = productRepository.findById(itemId); + + if (!productOptional.isPresent()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, err.log(loginUser.getId(),"상품을 찾을 수 없습니다"), "")); + //throw new Exception404("상품을 찾을 수 없습니다"); + } + + Product product = productOptional.get(); + productRepository.delete(product); + + return ResponseEntity.ok().body("ok"); + } + + @GetMapping("/addproduct") + public String addProduct() + { + return "addproduct"; + } + + @GetMapping("/editproduct") + public String editProduct() + { + return "editproduct"; + } + + @GetMapping("/deleteproduct") + public String deleteProduct() + { + return "deleteproduct"; + } + + @GetMapping("/productlist") + public String productList() + { + return "productlist"; + } +} diff --git a/src/main/java/shop/mtcoding/metamall/controller/UserController.java b/src/main/java/shop/mtcoding/metamall/controller/UserController.java index ddfee94..f363078 100644 --- a/src/main/java/shop/mtcoding/metamall/controller/UserController.java +++ b/src/main/java/shop/mtcoding/metamall/controller/UserController.java @@ -1,14 +1,16 @@ package shop.mtcoding.metamall.controller; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import shop.mtcoding.metamall.core.exception.Exception400; import shop.mtcoding.metamall.core.exception.Exception401; import shop.mtcoding.metamall.core.jwt.JwtProvider; import shop.mtcoding.metamall.dto.ResponseDto; import shop.mtcoding.metamall.dto.user.UserRequest; -import shop.mtcoding.metamall.dto.user.UserResponse; +import shop.mtcoding.metamall.dto.user.UserRegister; import shop.mtcoding.metamall.model.log.login.LoginLog; import shop.mtcoding.metamall.model.log.login.LoginLogRepository; import shop.mtcoding.metamall.model.user.User; @@ -27,37 +29,67 @@ public class UserController { private final LoginLogRepository loginLogRepository; private final HttpSession session; - @PostMapping("/login") + @PostMapping("/user/login") public ResponseEntity login(@RequestBody UserRequest.LoginDto loginDto, HttpServletRequest request) { Optional userOP = userRepository.findByUsername(loginDto.getUsername()); - if (userOP.isPresent()) { - // 1. 유저 정보 꺼내기 - User loginUser = userOP.get(); - - // 2. 패스워드 검증하기 - if(!loginUser.getPassword().equals(loginDto.getPassword())){ - throw new Exception401("인증되지 않았습니다"); - } - - // 3. JWT 생성하기 - String jwt = JwtProvider.create(userOP.get()); - - // 4. 최종 로그인 날짜 기록 (더티체킹 - update 쿼리 발생) - loginUser.setUpdatedAt(LocalDateTime.now()); - - // 5. 로그 테이블 기록 - LoginLog loginLog = LoginLog.builder() - .userId(loginUser.getId()) - .userAgent(request.getHeader("User-Agent")) - .clientIP(request.getRemoteAddr()) - .build(); - loginLogRepository.save(loginLog); - - // 6. 응답 DTO 생성 - ResponseDto responseDto = new ResponseDto<>().data(loginUser); - return ResponseEntity.ok().header(JwtProvider.HEADER, jwt).body(responseDto); - } else { - throw new Exception400("유저네임 혹은 아이디가 잘못되었습니다"); + if (false == userOP.isPresent()) + { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, "존재하지 않는 ID 입니다", "")); } + + // 1. 유저 정보 꺼내기 + User loginUser = userOP.get(); + + // 2. 패스워드 검증하기 + if(!loginUser.getPassword().equals(loginDto.getPassword())) + { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, "유저네임 혹은 패스워드가 잘못되었습니다", "")); + } + + // 3. JWT 생성하기 + String jwt = JwtProvider.create(userOP.get()); + + // 4. 최종 로그인 날짜 기록 (더티체킹 - update 쿼리 발생) + loginUser.setUpdatedAt(LocalDateTime.now()); + + // 5. 로그 테이블 기록 + LoginLog loginLog = LoginLog.builder() + .userId(loginUser.getId()) + .userAgent(request.getHeader("User-Agent")) + .clientIP(request.getRemoteAddr()) + .build(); + loginLogRepository.save(loginLog); + + // 6. 응답 DTO 생성 + ResponseDto responseDto = new ResponseDto<>().data(loginUser); + return ResponseEntity.ok().header(JwtProvider.HEADER, jwt).body(responseDto); + + } + + @Transactional + @PostMapping("/user/register") + public ResponseEntity register(@RequestBody UserRegister userRegister) + { + Optional existingUser = userRepository.findByUsername(userRegister.getUsername()); + if (existingUser.isPresent()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseDto<>().fail(HttpStatus.BAD_REQUEST, "등록정보가 있습니다.", "")); + //throw new Exception401("등록정보가 있습니다"); + } + + // If the user doesn't exist, create a new one + User newUser = new User(); + newUser.setUsername(userRegister.getUsername()); + newUser.setPassword(userRegister.getPassword()); + newUser.setEmail(userRegister.getEmail()); + + newUser.setCreatedAt(LocalDateTime.now()); + + User registeredUser = userRepository.save(newUser); + ResponseDto responseDto = new ResponseDto<>().data(registeredUser); + + return ResponseEntity.ok().body(responseDto); } } diff --git a/src/main/java/shop/mtcoding/metamall/core/exception/Exception409.java b/src/main/java/shop/mtcoding/metamall/core/exception/Exception409.java new file mode 100644 index 0000000..7c653e0 --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/core/exception/Exception409.java @@ -0,0 +1,25 @@ +package shop.mtcoding.metamall.core.exception; + + +import lombok.Getter; +import org.springframework.http.HttpStatus; +import shop.mtcoding.metamall.dto.ResponseDto; + + +// 인증 안됨 +@Getter +public class Exception409 extends RuntimeException { + public Exception409(String message) { + super(message); + } + + public ResponseDto body(){ + ResponseDto responseDto = new ResponseDto<>(); + responseDto.fail(HttpStatus.CONFLICT, "conflict", getMessage()); + return responseDto; + } + + public HttpStatus status(){ + return HttpStatus.CONFLICT; + } +} \ No newline at end of file diff --git a/src/main/java/shop/mtcoding/metamall/core/filter/JwtVerifyFilter.java b/src/main/java/shop/mtcoding/metamall/core/filter/JwtVerifyFilter.java index 870bf93..d9fabcf 100644 --- a/src/main/java/shop/mtcoding/metamall/core/filter/JwtVerifyFilter.java +++ b/src/main/java/shop/mtcoding/metamall/core/filter/JwtVerifyFilter.java @@ -31,7 +31,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha String jwt = prefixJwt.replace(JwtProvider.TOKEN_PREFIX, ""); try { DecodedJWT decodedJWT = JwtProvider.verify(jwt); - int id = decodedJWT.getClaim("id").asInt(); + Long id = decodedJWT.getClaim("id").asLong(); String role = decodedJWT.getClaim("role").asString(); // 세션을 사용하는 이유는 권한처리를 하기 위해서이다. @@ -44,6 +44,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha }catch (TokenExpiredException tee){ error(resp, tee); } + } private void error(HttpServletResponse resp, Exception e) throws IOException { diff --git a/src/main/java/shop/mtcoding/metamall/core/session/LoginUser.java b/src/main/java/shop/mtcoding/metamall/core/session/LoginUser.java index 59f402c..a38bf5c 100644 --- a/src/main/java/shop/mtcoding/metamall/core/session/LoginUser.java +++ b/src/main/java/shop/mtcoding/metamall/core/session/LoginUser.java @@ -5,11 +5,11 @@ @Getter public class LoginUser { - private Integer id; + private Long id; private String role; @Builder - public LoginUser(Integer id, String role) { + public LoginUser(Long id, String role) { this.id = id; this.role = role; } diff --git a/src/main/java/shop/mtcoding/metamall/dto/order/OrderSheetDto.java b/src/main/java/shop/mtcoding/metamall/dto/order/OrderSheetDto.java new file mode 100644 index 0000000..b742272 --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/dto/order/OrderSheetDto.java @@ -0,0 +1,42 @@ +package shop.mtcoding.metamall.dto.order; + +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import shop.mtcoding.metamall.dto.product.OrderProductDto; +import shop.mtcoding.metamall.model.ordersheet.OrderSheet; +import shop.mtcoding.metamall.model.ordersheet.OrderStatus; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +@NoArgsConstructor +@Setter +@Getter +public class OrderSheetDto { + + private Long id; + private String username; + private Integer totalPrice; + private LocalDateTime createdAt; + private OrderStatus status; + private List orderProducts; + + @Builder + public OrderSheetDto(OrderSheet orderSheet) { + this.id = orderSheet.getId(); + this.username = orderSheet.getUser().getUsername(); + this.totalPrice = orderSheet.getTotalPrice(); + this.createdAt = orderSheet.getCreatedAt(); + this.status = orderSheet.getStatus(); + this.orderProducts = orderSheet.getOrderProductList().stream() + .map(orderProduct -> new OrderProductDto( + orderProduct.getProduct().getId(), + orderProduct.getProduct().getName(), + orderProduct.getCount())) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/shop/mtcoding/metamall/dto/product/OrderProductDto.java b/src/main/java/shop/mtcoding/metamall/dto/product/OrderProductDto.java new file mode 100644 index 0000000..efae78c --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/dto/product/OrderProductDto.java @@ -0,0 +1,24 @@ +package shop.mtcoding.metamall.dto.product; + +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@Setter +@Getter +public class OrderProductDto { + + private Long productId; + private String productName; + private Integer count; + + @Builder + public OrderProductDto(Long id, String name, Integer count) + { + this.productId = id; + this.productName = name; + this.count = count; + } +} diff --git a/src/main/java/shop/mtcoding/metamall/dto/product/OrderProductRequest.java b/src/main/java/shop/mtcoding/metamall/dto/product/OrderProductRequest.java new file mode 100644 index 0000000..b862b9c --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/dto/product/OrderProductRequest.java @@ -0,0 +1,12 @@ +package shop.mtcoding.metamall.dto.product; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class OrderProductRequest +{ + private Long productId; + private Integer count; +} diff --git a/src/main/java/shop/mtcoding/metamall/dto/user/UserRegister.java b/src/main/java/shop/mtcoding/metamall/dto/user/UserRegister.java new file mode 100644 index 0000000..6efe626 --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/dto/user/UserRegister.java @@ -0,0 +1,22 @@ +package shop.mtcoding.metamall.dto.user; + +import lombok.Getter; +import lombok.Setter; +import org.hibernate.validator.constraints.Range; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotEmpty; + +@Getter +@Setter +public class UserRegister +{ + @NotEmpty + private String username; + + @NotEmpty + private String password; + + @Email + private String email; +} diff --git a/src/main/java/shop/mtcoding/metamall/model/log/error/ErrLogService.java b/src/main/java/shop/mtcoding/metamall/model/log/error/ErrLogService.java new file mode 100644 index 0000000..7722cda --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/model/log/error/ErrLogService.java @@ -0,0 +1,20 @@ +package shop.mtcoding.metamall.model.log.error; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class ErrLogService { + + private final ErrorLogRepository errorLogRepository; + + public String log(Long userId, String message) { + + ErrorLog errorLog = ErrorLog.builder() + .msg(message) + .userId(userId) + .build(); + return errorLogRepository.save(errorLog).getMsg(); + } +} diff --git a/src/main/java/shop/mtcoding/metamall/model/orderproduct/OrderProduct.java b/src/main/java/shop/mtcoding/metamall/model/orderproduct/OrderProduct.java index 165905e..dd916ef 100644 --- a/src/main/java/shop/mtcoding/metamall/model/orderproduct/OrderProduct.java +++ b/src/main/java/shop/mtcoding/metamall/model/orderproduct/OrderProduct.java @@ -1,10 +1,12 @@ package shop.mtcoding.metamall.model.orderproduct; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import shop.mtcoding.metamall.model.ordersheet.OrderSheet; +import shop.mtcoding.metamall.model.ordersheet.OrderStatus; import shop.mtcoding.metamall.model.product.Product; import javax.persistence.*; @@ -15,20 +17,25 @@ @Getter @Table(name = "order_product_tb") @Entity +@JsonIgnoreProperties({"orderSheet"}) public class OrderProduct { // 주문 상품 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne + + @ManyToOne(fetch = FetchType.LAZY) private Product product; private Integer count; // 상품 주문 개수 private Integer orderPrice; // 상품 주문 금액 private LocalDateTime createdAt; private LocalDateTime updatedAt; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) private OrderSheet orderSheet; + @Enumerated(EnumType.STRING) + private OrderStatus status; + @PrePersist protected void onCreate() { this.createdAt = LocalDateTime.now(); @@ -40,7 +47,7 @@ protected void onUpdate() { } @Builder - public OrderProduct(Long id, Product product, Integer count, Integer orderPrice, LocalDateTime createdAt, LocalDateTime updatedAt, OrderSheet orderSheet) { + public OrderProduct(Long id, Product product, Integer count, Integer orderPrice, LocalDateTime createdAt, LocalDateTime updatedAt, OrderSheet orderSheet, OrderStatus orderStatus) { this.id = id; this.product = product; this.count = count; @@ -48,5 +55,6 @@ public OrderProduct(Long id, Product product, Integer count, Integer orderPrice, this.createdAt = createdAt; this.updatedAt = updatedAt; this.orderSheet = orderSheet; + this.status = orderStatus; } } diff --git a/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderSheet.java b/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderSheet.java index 7638710..54d07ef 100644 --- a/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderSheet.java +++ b/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderSheet.java @@ -1,11 +1,12 @@ package shop.mtcoding.metamall.model.ordersheet; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import shop.mtcoding.metamall.model.orderproduct.OrderProduct; -import shop.mtcoding.metamall.model.product.Product; import shop.mtcoding.metamall.model.user.User; import javax.persistence.*; @@ -18,18 +19,24 @@ @Getter @Table(name = "order_sheet_tb") @Entity +@JsonIgnoreProperties({"orderProductList"}) public class OrderSheet { // 주문서 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne + @JsonIgnore + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") private User user; // 주문자 - @OneToMany(mappedBy = "orderSheet") + @OneToMany(mappedBy = "orderSheet", cascade = CascadeType.ALL) private List orderProductList = new ArrayList<>(); // 총 주문 상품 리스트 private Integer totalPrice; // 총 주문 금액 (총 주문 상품 리스트의 orderPrice 합) private LocalDateTime createdAt; private LocalDateTime updatedAt; + @Enumerated(EnumType.STRING) + private OrderStatus status; + @PrePersist protected void onCreate() { this.createdAt = LocalDateTime.now(); @@ -39,15 +46,15 @@ protected void onCreate() { protected void onUpdate() { this.updatedAt = LocalDateTime.now(); } - - // 연관관계 메서드 구현 필요 + @Builder - public OrderSheet(Long id, User user, Integer totalPrice, LocalDateTime createdAt, LocalDateTime updatedAt) { + public OrderSheet(Long id, User user, Integer totalPrice, LocalDateTime createdAt, LocalDateTime updatedAt, OrderStatus orderStatus) { this.id = id; this.user = user; this.totalPrice = totalPrice; this.createdAt = createdAt; this.updatedAt = updatedAt; + this.status = orderStatus; } } diff --git a/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderSheetRepository.java b/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderSheetRepository.java index 5d59249..9609d15 100644 --- a/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderSheetRepository.java +++ b/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderSheetRepository.java @@ -2,5 +2,11 @@ import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + public interface OrderSheetRepository extends JpaRepository { + List findByUserIdAndStatusNot(Long userId, OrderStatus status); + + List findByStatusNot(OrderStatus status); + } diff --git a/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderStatus.java b/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderStatus.java new file mode 100644 index 0000000..da75b6a --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/model/ordersheet/OrderStatus.java @@ -0,0 +1,8 @@ +package shop.mtcoding.metamall.model.ordersheet; + +public enum +OrderStatus +{ + ORDER, + CANCEL +} diff --git a/src/main/java/shop/mtcoding/metamall/model/product/Product.java b/src/main/java/shop/mtcoding/metamall/model/product/Product.java index bc8c618..5d4c080 100644 --- a/src/main/java/shop/mtcoding/metamall/model/product/Product.java +++ b/src/main/java/shop/mtcoding/metamall/model/product/Product.java @@ -33,6 +33,20 @@ protected void onUpdate() { this.updatedAt = LocalDateTime.now(); } + public void addStock(int quantity) + { + this.qty += quantity; + } + + public void removeStock(int quantity) + { + int restStock = this.qty - quantity; + if(restStock < 0) + throw new RuntimeException("재고가 부족합니다"); + + this.qty = restStock; + } + @Builder public Product(Long id, String name, Integer price, Integer qty, LocalDateTime createdAt, LocalDateTime updatedAt) { this.id = id; diff --git a/src/main/java/shop/mtcoding/metamall/model/user/User.java b/src/main/java/shop/mtcoding/metamall/model/user/User.java index c929ce5..1f38727 100644 --- a/src/main/java/shop/mtcoding/metamall/model/user/User.java +++ b/src/main/java/shop/mtcoding/metamall/model/user/User.java @@ -1,5 +1,6 @@ package shop.mtcoding.metamall.model.user; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/src/main/java/shop/mtcoding/metamall/model/user/UserRepository.java b/src/main/java/shop/mtcoding/metamall/model/user/UserRepository.java index 293a101..2f642f9 100644 --- a/src/main/java/shop/mtcoding/metamall/model/user/UserRepository.java +++ b/src/main/java/shop/mtcoding/metamall/model/user/UserRepository.java @@ -6,7 +6,7 @@ import java.util.Optional; -public interface UserRepository extends JpaRepository { +public interface UserRepository extends JpaRepository { @Query("select u from User u where u.username = :username") Optional findByUsername(@Param("username") String username); diff --git a/src/main/java/shop/mtcoding/metamall/service/UserService.java b/src/main/java/shop/mtcoding/metamall/service/UserService.java new file mode 100644 index 0000000..4cd662c --- /dev/null +++ b/src/main/java/shop/mtcoding/metamall/service/UserService.java @@ -0,0 +1,25 @@ +package shop.mtcoding.metamall.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import shop.mtcoding.metamall.model.user.User; +import shop.mtcoding.metamall.model.user.UserRepository; + +import java.util.List; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class UserService +{ + private final UserRepository userRepository; + + //회원가입 + @Transactional + public Long join(User user) + { + return user.getId(); + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1d9bd50..a09a752 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -13,6 +13,8 @@ spring: h2: console: enabled: true + path: /h2-console + jpa: hibernate: ddl-auto: create diff --git a/src/main/resources/templates/addproduct.html b/src/main/resources/templates/addproduct.html new file mode 100644 index 0000000..7f22929 --- /dev/null +++ b/src/main/resources/templates/addproduct.html @@ -0,0 +1,93 @@ + + + + 상품 등록 + + + + + +
+ + + + + + + + + + + +
+ +
+ +
+ + diff --git a/src/main/resources/templates/customerorderlist.html b/src/main/resources/templates/customerorderlist.html new file mode 100644 index 0000000..5390a57 --- /dev/null +++ b/src/main/resources/templates/customerorderlist.html @@ -0,0 +1,139 @@ + + + + 주문 목록 보기 (고객 전용) + + + + + +

주문 목록 보기 (고객 전용)

+ + + + + + + + + + + + + + +
선택주문 번호주문자주문 상품총 금액주문 날짜주문 상태
+ +
+ + +
+ + + diff --git a/src/main/resources/templates/customerplaceorder.html b/src/main/resources/templates/customerplaceorder.html new file mode 100644 index 0000000..6b08a5a --- /dev/null +++ b/src/main/resources/templates/customerplaceorder.html @@ -0,0 +1,161 @@ + + + + 상품 목록 + + + + > + + +

주문 하기

+ + + + + + + + + + + + +
선택상품 이름상품 가격상품 재고수량
+ +
+ + +
+ + + diff --git a/src/main/resources/templates/deleteproduct.html b/src/main/resources/templates/deleteproduct.html new file mode 100644 index 0000000..98c52c6 --- /dev/null +++ b/src/main/resources/templates/deleteproduct.html @@ -0,0 +1,136 @@ + + + + 상품 삭제 + + + + + +

상품 삭제

+ + + + + + + + + + + +
상품 선택상품 이름상품 가격상품 재고
+ + + +
+ +
+ + + diff --git a/src/main/resources/templates/editproduct.html b/src/main/resources/templates/editproduct.html new file mode 100644 index 0000000..9c3fdfb --- /dev/null +++ b/src/main/resources/templates/editproduct.html @@ -0,0 +1,168 @@ + + + + 상품 수정 + + + + + +

상품 수정

+ + + + + + + + + + + +
상품 선택상품 이름상품 가격상품 재고
+ +

상품 수정

+ + + + + + + +
+ +
+ +
+ +
+ +
+ + + + diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html new file mode 100644 index 0000000..5d6fd36 --- /dev/null +++ b/src/main/resources/templates/home.html @@ -0,0 +1,94 @@ + + + + 홈화면 + + + +

HOME

+ + + + + + + diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..3fa9eb9 --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,109 @@ + + + + 로그인 + + + + + + +

로그인 폼

+
+ + + + + + + + +
+
+ + + diff --git a/src/main/resources/templates/ordermanagement.html b/src/main/resources/templates/ordermanagement.html new file mode 100644 index 0000000..a2bb354 --- /dev/null +++ b/src/main/resources/templates/ordermanagement.html @@ -0,0 +1,40 @@ + + + + + + + Order Management + + + +
+ + + + +
+ + diff --git a/src/main/resources/templates/productlist.html b/src/main/resources/templates/productlist.html new file mode 100644 index 0000000..3b3c698 --- /dev/null +++ b/src/main/resources/templates/productlist.html @@ -0,0 +1,98 @@ + + + + 상품 목록 + + + + + +

상품 관리

+ + + + + + + + + + +
상품 이름상품 가격상품 재고
+ +
+ +
+ + + diff --git a/src/main/resources/templates/productmanagement.html b/src/main/resources/templates/productmanagement.html new file mode 100644 index 0000000..e72beb2 --- /dev/null +++ b/src/main/resources/templates/productmanagement.html @@ -0,0 +1,41 @@ + + + + + + + 상품관리 + + + +
+ + + + + +
+ + diff --git a/src/main/resources/templates/register.html b/src/main/resources/templates/register.html new file mode 100644 index 0000000..e2034d0 --- /dev/null +++ b/src/main/resources/templates/register.html @@ -0,0 +1,105 @@ + + + + 회원가입 + + + +

회원가입 폼

+
+ + + + + + + + + + +
+ + + + + + + diff --git a/src/main/resources/templates/sellerorderlist.html b/src/main/resources/templates/sellerorderlist.html new file mode 100644 index 0000000..2bf3e42 --- /dev/null +++ b/src/main/resources/templates/sellerorderlist.html @@ -0,0 +1,139 @@ + + + + 주문 목록 보기 (판매자 전용) + + + + + +

주문 목록 보기 (판매자 전용)

+ + + + + + + + + + + + + + +
선택주문 번호주문자주문 상품총 금액주문 날짜주문 상태
+ +
+ + +
+ + +