diff --git a/backend/src/main/java/wap/dingdong/backend/BackendApplication.java b/backend/src/main/java/wap/dingdong/backend/BackendApplication.java index 7851159..d9557d2 100644 --- a/backend/src/main/java/wap/dingdong/backend/BackendApplication.java +++ b/backend/src/main/java/wap/dingdong/backend/BackendApplication.java @@ -3,10 +3,12 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import wap.dingdong.backend.config.AppProperties; @SpringBootApplication @EnableConfigurationProperties(AppProperties.class) +@EnableJpaAuditing public class BackendApplication { public static void main(String[] args) { diff --git a/backend/src/main/java/wap/dingdong/backend/config/SecurityConfig.java b/backend/src/main/java/wap/dingdong/backend/config/SecurityConfig.java index 56d2b22..785f935 100644 --- a/backend/src/main/java/wap/dingdong/backend/config/SecurityConfig.java +++ b/backend/src/main/java/wap/dingdong/backend/config/SecurityConfig.java @@ -90,7 +90,7 @@ protected SecurityFilterChain filterChain (HttpSecurity http) throws Exception { .authenticationEntryPoint(new RestAuthenticationEntryPoint()) .and() .authorizeRequests() - .requestMatchers("/", + .requestMatchers( //로그인 검증 모두 해제 ("/**") "/error", "/favicon.ico", "/**.png", @@ -99,7 +99,7 @@ protected SecurityFilterChain filterChain (HttpSecurity http) throws Exception { "/**.jpg", "/**.html", "/**.css", - "/**.js") + "/**.js", "/**") .permitAll() .requestMatchers("/auth/**", "/oauth2/**") .permitAll() diff --git a/backend/src/main/java/wap/dingdong/backend/controller/AuthController.java b/backend/src/main/java/wap/dingdong/backend/controller/AuthController.java index 1b7694f..7ea7440 100644 --- a/backend/src/main/java/wap/dingdong/backend/controller/AuthController.java +++ b/backend/src/main/java/wap/dingdong/backend/controller/AuthController.java @@ -14,8 +14,8 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import wap.dingdong.backend.exception.BadRequestException; -import wap.dingdong.backend.model.AuthProvider; -import wap.dingdong.backend.model.User; +import wap.dingdong.backend.domain.AuthProvider; +import wap.dingdong.backend.domain.User; import wap.dingdong.backend.payload.ApiResponse; import wap.dingdong.backend.payload.AuthResponse; import wap.dingdong.backend.payload.LoginRequest; diff --git a/backend/src/main/java/wap/dingdong/backend/controller/HelloController.java b/backend/src/main/java/wap/dingdong/backend/controller/HelloController.java new file mode 100644 index 0000000..f94d2d3 --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/controller/HelloController.java @@ -0,0 +1,14 @@ +package wap.dingdong.backend.controller; + + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HelloController { + + @GetMapping("/demo/hello") + public String HelloWorld(){ + return "Hello World!! \n"; + } +} \ No newline at end of file diff --git a/backend/src/main/java/wap/dingdong/backend/controller/ProductController.java b/backend/src/main/java/wap/dingdong/backend/controller/ProductController.java new file mode 100644 index 0000000..d4d0d14 --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/controller/ProductController.java @@ -0,0 +1,42 @@ +package wap.dingdong.backend.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import wap.dingdong.backend.payload.request.ProductCreateRequest; +import wap.dingdong.backend.payload.response.ProductInfoResponse; +import wap.dingdong.backend.payload.response.ProductsResponse; +import wap.dingdong.backend.service.ProductService; + +import java.util.List; + +@RequiredArgsConstructor +@RestController +public class ProductController { + + private final ProductService productService; + + //상품 등록 + @PostMapping("/product") + public ResponseEntity createProduct(@RequestBody ProductCreateRequest request) { + productService.save(request); + return new ResponseEntity<>(HttpStatus.OK); + } + + // 전체 상품 조회 + //ProductInfoResponse는 하나의 개별 상품의 정보를 담는 DTO (상품상세 DTO와 비슷) + //ProductsResponse는 전체 상품 목록을 담는 DTO, + // 여러 개의 ProductInfoResponse 객체를 리스트 형태로 가짐 + @GetMapping("/product/list") + public ResponseEntity findAllProducts() { + List products = productService.getAllProducts(); + ProductsResponse response = new ProductsResponse(products); + return new ResponseEntity<>(response, HttpStatus.OK); + } + + +} diff --git a/backend/src/main/java/wap/dingdong/backend/controller/UserController.java b/backend/src/main/java/wap/dingdong/backend/controller/UserController.java index 966c748..66194b0 100644 --- a/backend/src/main/java/wap/dingdong/backend/controller/UserController.java +++ b/backend/src/main/java/wap/dingdong/backend/controller/UserController.java @@ -4,7 +4,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import wap.dingdong.backend.exception.ResourceNotFoundException; -import wap.dingdong.backend.model.User; +import wap.dingdong.backend.domain.User; import wap.dingdong.backend.repository.UserRepository; import wap.dingdong.backend.security.CurrentUser; import wap.dingdong.backend.security.UserPrincipal; @@ -15,7 +15,7 @@ public class UserController { @Autowired private UserRepository userRepository; - @GetMapping("/user/me") // + @GetMapping("/user/me") //@CurrentUser : 프론트에서 주는 토큰을 가지고 객체를 만들어줌 public User getCurrentUser(@CurrentUser UserPrincipal userPrincipal) { return userRepository.findById(userPrincipal.getId()) diff --git a/backend/src/main/java/wap/dingdong/backend/domain/AuthProvider.java b/backend/src/main/java/wap/dingdong/backend/domain/AuthProvider.java new file mode 100644 index 0000000..5e48fdf --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/AuthProvider.java @@ -0,0 +1,6 @@ +package wap.dingdong.backend.domain; + +public enum AuthProvider { + local, + kakao +} diff --git a/backend/src/main/java/wap/dingdong/backend/domain/Buy.java b/backend/src/main/java/wap/dingdong/backend/domain/Buy.java new file mode 100644 index 0000000..a22e22e --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/Buy.java @@ -0,0 +1,39 @@ +package wap.dingdong.backend.domain; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class Buy { + + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "buy_id") + private Long id; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; + + @OneToOne(mappedBy = "buy", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private Wish wish; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @CreatedDate + private LocalDateTime createdAt; + +} diff --git a/backend/src/main/java/wap/dingdong/backend/domain/Comment.java b/backend/src/main/java/wap/dingdong/backend/domain/Comment.java new file mode 100644 index 0000000..462c258 --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/Comment.java @@ -0,0 +1,39 @@ +package wap.dingdong.backend.domain; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class Comment { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "comment_id") + private Long id; + + private String contents; + + @CreatedDate + private LocalDateTime createdAt; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + +} diff --git a/backend/src/main/java/wap/dingdong/backend/domain/Image.java b/backend/src/main/java/wap/dingdong/backend/domain/Image.java new file mode 100644 index 0000000..b047165 --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/Image.java @@ -0,0 +1,26 @@ +package wap.dingdong.backend.domain; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class Image { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "image_id") + private Long id; + + private String imageUrl; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; +} diff --git a/backend/src/main/java/wap/dingdong/backend/domain/Location.java b/backend/src/main/java/wap/dingdong/backend/domain/Location.java new file mode 100644 index 0000000..6d9a5ba --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/Location.java @@ -0,0 +1,29 @@ +package wap.dingdong.backend.domain; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class Location { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "location_id") + private Long id; + + private String location; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; + + + +} diff --git a/backend/src/main/java/wap/dingdong/backend/domain/Product.java b/backend/src/main/java/wap/dingdong/backend/domain/Product.java new file mode 100644 index 0000000..6c476e6 --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/Product.java @@ -0,0 +1,60 @@ +package wap.dingdong.backend.domain; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter @Setter +@AllArgsConstructor @NoArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class Product { + + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "product_id") + private Long id; + + private String title; + private Long price; + private String contents; + + @Enumerated(EnumType.STRING) + private ProductStatus status = ProductStatus.ON_SALE; //기본값 ON_SALE + + @Enumerated(EnumType.STRING) + private ProductLike productLike = ProductLike.UNLIKE; //기본값 UNLIKE + + @CreatedDate + private LocalDateTime createdAt; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @OneToOne(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private Buy buy; + + @OneToOne(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private Sell sell; + + @OneToOne(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private Wish wish; + + @OneToMany(mappedBy = "product",cascade = CascadeType.ALL) + private List images = new ArrayList<>(); + + @OneToMany(mappedBy = "product", cascade = CascadeType.ALL) + private List locations = new ArrayList<>(); + + @OneToMany(mappedBy = "product", cascade = CascadeType.ALL) + private List comments = new ArrayList<>(); + +} diff --git a/backend/src/main/java/wap/dingdong/backend/domain/ProductLike.java b/backend/src/main/java/wap/dingdong/backend/domain/ProductLike.java new file mode 100644 index 0000000..f7b68eb --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/ProductLike.java @@ -0,0 +1,5 @@ +package wap.dingdong.backend.domain; + +public enum ProductLike { + LIKE, UNLIKE +} diff --git a/backend/src/main/java/wap/dingdong/backend/domain/ProductStatus.java b/backend/src/main/java/wap/dingdong/backend/domain/ProductStatus.java new file mode 100644 index 0000000..f4eed4b --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/ProductStatus.java @@ -0,0 +1,5 @@ +package wap.dingdong.backend.domain; + +public enum ProductStatus { + ON_SALE, SOLD_OUT +} diff --git a/backend/src/main/java/wap/dingdong/backend/domain/Sell.java b/backend/src/main/java/wap/dingdong/backend/domain/Sell.java new file mode 100644 index 0000000..ecc7a3e --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/Sell.java @@ -0,0 +1,38 @@ +package wap.dingdong.backend.domain; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +import java.time.LocalDateTime; + +@Entity +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@EnableJpaAuditing +@EntityListeners(AuditingEntityListener.class) +public class Sell { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "sell_id") + private Long id; + + @CreatedDate + private LocalDateTime createdAt; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; +} diff --git a/backend/src/main/java/wap/dingdong/backend/domain/User.java b/backend/src/main/java/wap/dingdong/backend/domain/User.java new file mode 100644 index 0000000..567e3a6 --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/User.java @@ -0,0 +1,63 @@ +package wap.dingdong.backend.domain; +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + + +@Entity +@Getter @Setter +@AllArgsConstructor @NoArgsConstructor +@Table(name = "user", uniqueConstraints = {@UniqueConstraint(columnNames = "email")}) +public class User { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_id") + private Long id; + + @Column(nullable = false) + private String name; + + @Email + @Column(nullable = false) + private String email; + + private String imageUrl; + + @Column(nullable = false) + private Boolean emailVerified = false; + + @JsonIgnore + private String password; + + @NotNull + @Enumerated(EnumType.STRING) + private AuthProvider provider; + + private String providerId; + + //연관관계 매핑 + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) + List products = new ArrayList<>(); + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) + List wishes = new ArrayList<>(); + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) + List comments = new ArrayList<>(); + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) + List sells = new ArrayList<>(); + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) + List buys = new ArrayList<>(); + + +} diff --git a/backend/src/main/java/wap/dingdong/backend/domain/Wish.java b/backend/src/main/java/wap/dingdong/backend/domain/Wish.java new file mode 100644 index 0000000..fd3af6e --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/domain/Wish.java @@ -0,0 +1,41 @@ +package wap.dingdong.backend.domain; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class Wish { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "wish_id") + private Long id; + + @CreatedDate + private LocalDateTime createdAt; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "buy_id") + private Buy buy; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + +} diff --git a/backend/src/main/java/wap/dingdong/backend/model/AuthProvider.java b/backend/src/main/java/wap/dingdong/backend/model/AuthProvider.java deleted file mode 100644 index f10ba41..0000000 --- a/backend/src/main/java/wap/dingdong/backend/model/AuthProvider.java +++ /dev/null @@ -1,10 +0,0 @@ -package wap.dingdong.backend.model; - -public enum AuthProvider { - local, - facebook, - google, - github, - kakao, - naver -} diff --git a/backend/src/main/java/wap/dingdong/backend/model/User.java b/backend/src/main/java/wap/dingdong/backend/model/User.java deleted file mode 100644 index 0e6c9fe..0000000 --- a/backend/src/main/java/wap/dingdong/backend/model/User.java +++ /dev/null @@ -1,38 +0,0 @@ -package wap.dingdong.backend.model; -import com.fasterxml.jackson.annotation.JsonIgnore; -import jakarta.persistence.*; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - - -@Entity -@Getter @Setter -@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = "email")}) -public class User { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false) - private String name; - - @Email - @Column(nullable = false) - private String email; - - private String imageUrl; - - @Column(nullable = false) - private Boolean emailVerified = false; - - @JsonIgnore - private String password; - - @NotNull - @Enumerated(EnumType.STRING) - private AuthProvider provider; - - private String providerId; -} diff --git a/backend/src/main/java/wap/dingdong/backend/payload/request/ProductCreateRequest.java b/backend/src/main/java/wap/dingdong/backend/payload/request/ProductCreateRequest.java new file mode 100644 index 0000000..e1e1de2 --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/payload/request/ProductCreateRequest.java @@ -0,0 +1,21 @@ +package wap.dingdong.backend.payload.request; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter @Setter +@NoArgsConstructor +@AllArgsConstructor +public class ProductCreateRequest { + + private String title; + private Long price; + private String contents; + private List locations; + private List images; + +} diff --git a/backend/src/main/java/wap/dingdong/backend/payload/response/ProductInfoResponse.java b/backend/src/main/java/wap/dingdong/backend/payload/response/ProductInfoResponse.java new file mode 100644 index 0000000..90c3f8e --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/payload/response/ProductInfoResponse.java @@ -0,0 +1,23 @@ +package wap.dingdong.backend.payload.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter @Setter +public class ProductInfoResponse { + + private Long productId; + private String title; + private Long price; + private String contents; + private List locations; + private List images; + private String productLike; + private String createdAt; +} diff --git a/backend/src/main/java/wap/dingdong/backend/payload/response/ProductsResponse.java b/backend/src/main/java/wap/dingdong/backend/payload/response/ProductsResponse.java new file mode 100644 index 0000000..a2e2ff9 --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/payload/response/ProductsResponse.java @@ -0,0 +1,18 @@ +package wap.dingdong.backend.payload.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter @Setter +@AllArgsConstructor +@NoArgsConstructor +public class ProductsResponse { + + private List productsResponse; + +} + diff --git a/backend/src/main/java/wap/dingdong/backend/repository/ProductRepository.java b/backend/src/main/java/wap/dingdong/backend/repository/ProductRepository.java new file mode 100644 index 0000000..7b35e0e --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/repository/ProductRepository.java @@ -0,0 +1,7 @@ +package wap.dingdong.backend.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import wap.dingdong.backend.domain.Product; + +public interface ProductRepository extends JpaRepository { +} diff --git a/backend/src/main/java/wap/dingdong/backend/repository/UserRepository.java b/backend/src/main/java/wap/dingdong/backend/repository/UserRepository.java index 6fa191d..293e44a 100644 --- a/backend/src/main/java/wap/dingdong/backend/repository/UserRepository.java +++ b/backend/src/main/java/wap/dingdong/backend/repository/UserRepository.java @@ -2,7 +2,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import wap.dingdong.backend.model.User; +import wap.dingdong.backend.domain.User; import java.util.Optional; diff --git a/backend/src/main/java/wap/dingdong/backend/security/CustomUserDetailsService.java b/backend/src/main/java/wap/dingdong/backend/security/CustomUserDetailsService.java index 35e2244..3e40e54 100644 --- a/backend/src/main/java/wap/dingdong/backend/security/CustomUserDetailsService.java +++ b/backend/src/main/java/wap/dingdong/backend/security/CustomUserDetailsService.java @@ -8,7 +8,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import wap.dingdong.backend.exception.ResourceNotFoundException; -import wap.dingdong.backend.model.User; +import wap.dingdong.backend.domain.User; import wap.dingdong.backend.repository.UserRepository; /** diff --git a/backend/src/main/java/wap/dingdong/backend/security/UserPrincipal.java b/backend/src/main/java/wap/dingdong/backend/security/UserPrincipal.java index 5b84291..829c8cc 100644 --- a/backend/src/main/java/wap/dingdong/backend/security/UserPrincipal.java +++ b/backend/src/main/java/wap/dingdong/backend/security/UserPrincipal.java @@ -4,7 +4,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.core.user.OAuth2User; -import wap.dingdong.backend.model.User; +import wap.dingdong.backend.domain.User; import java.util.Collection; import java.util.Collections; diff --git a/backend/src/main/java/wap/dingdong/backend/security/oauth2/CustomOAuth2UserService.java b/backend/src/main/java/wap/dingdong/backend/security/oauth2/CustomOAuth2UserService.java index 26ebce9..26d257a 100644 --- a/backend/src/main/java/wap/dingdong/backend/security/oauth2/CustomOAuth2UserService.java +++ b/backend/src/main/java/wap/dingdong/backend/security/oauth2/CustomOAuth2UserService.java @@ -10,8 +10,8 @@ import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import wap.dingdong.backend.exception.OAuth2AuthenticationProcessingException; -import wap.dingdong.backend.model.AuthProvider; -import wap.dingdong.backend.model.User; +import wap.dingdong.backend.domain.AuthProvider; +import wap.dingdong.backend.domain.User; import wap.dingdong.backend.repository.UserRepository; import wap.dingdong.backend.security.UserPrincipal; import wap.dingdong.backend.security.oauth2.user.OAuth2UserInfo; diff --git a/backend/src/main/java/wap/dingdong/backend/security/oauth2/user/OAuth2UserInfoFactory.java b/backend/src/main/java/wap/dingdong/backend/security/oauth2/user/OAuth2UserInfoFactory.java index 371d297..ad91b60 100644 --- a/backend/src/main/java/wap/dingdong/backend/security/oauth2/user/OAuth2UserInfoFactory.java +++ b/backend/src/main/java/wap/dingdong/backend/security/oauth2/user/OAuth2UserInfoFactory.java @@ -2,7 +2,7 @@ import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import wap.dingdong.backend.exception.OAuth2AuthenticationProcessingException; -import wap.dingdong.backend.model.AuthProvider; +import wap.dingdong.backend.domain.AuthProvider; import java.util.HashMap; import java.util.LinkedHashMap; diff --git a/backend/src/main/java/wap/dingdong/backend/service/ProductService.java b/backend/src/main/java/wap/dingdong/backend/service/ProductService.java new file mode 100644 index 0000000..db2abc4 --- /dev/null +++ b/backend/src/main/java/wap/dingdong/backend/service/ProductService.java @@ -0,0 +1,101 @@ +package wap.dingdong.backend.service; + + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import wap.dingdong.backend.domain.Image; +import wap.dingdong.backend.domain.Location; +import wap.dingdong.backend.domain.Product; +import wap.dingdong.backend.payload.request.ProductCreateRequest; +import wap.dingdong.backend.payload.response.ProductInfoResponse; +import wap.dingdong.backend.repository.ProductRepository; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class ProductService { + + private final ProductRepository productRepository; + +/* + 상품 등록 + */ + @Transactional + public void save(ProductCreateRequest request) { + // 도메인객체를 생성 후 요청 DTO를 이용하여 상품 엔티티 생성 + Product product = new Product(); + + product.setTitle(request.getTitle()); + product.setPrice(request.getPrice()); + product.setContents(request.getContents()); + + // ProductLocationDTO와 ImageDTO는 별도의 DTO 객체이므로 각각의 필드 값을 가져와서 새로운 List에 복사해야함 + // 새로운 List를 생성하여 값을 복사하는 방식으로 + + // 지역 정보 추가 + for (String location : request.getLocations()) { + Location loc = new Location(); + loc.setLocation(location); + loc.setProduct(product); + product.getLocations().add(loc); + } + + // 이미지 정보 추가 + for (String imageUrl : request.getImages()) { + Image image = new Image(); + image.setImageUrl(imageUrl); + image.setProduct(product); + product.getImages().add(image); + } + + // 상품 저장 + productRepository.save(product); + } + +//=========================================================================================== + +/* + 모든 상품 조회 (메인페이지 상품 목록) + */ + +//ProductInfoResponse는 하나의 개별 상품의 정보를 담는 DTO (상품상세 DTO와 비슷) +//ProductsResponse는 전체 상품 목록을 담는 DTO, +// 여러 개의 ProductInfoResponse 객체를 리스트 형태로 가짐 + + public List getAllProducts() { + List products = productRepository.findAll(); + return ProductMapper.toProductInfoResponseList(products); + } + + public static class ProductMapper { + + public static ProductInfoResponse toProductInfoResponse(Product product) { + ProductInfoResponse response = new ProductInfoResponse(); + response.setProductId(product.getId()); + response.setTitle(product.getTitle()); + response.setPrice(product.getPrice()); + response.setContents(product.getContents()); + response.setLocations(product.getLocations().stream() + .map(Location::getLocation) + .collect(Collectors.toList())); + response.setImages(product.getImages().stream() + .map(Image::getImageUrl) + .collect(Collectors.toList())); + response.setProductLike(product.getProductLike().name()); + response.setCreatedAt(product.getCreatedAt().toString()); // 형식에 맞게 수정 필요 + return response; + } + + public static List toProductInfoResponseList(List products) { + return products.stream() + .map(ProductMapper::toProductInfoResponse) + .collect(Collectors.toList()); + } + +//====================================================================================================== + + } +} diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties deleted file mode 100644 index 7985e95..0000000 --- a/backend/src/main/resources/application.properties +++ /dev/null @@ -1,26 +0,0 @@ -spring.application.name=backend -spring.datasource.url=jdbc:mysql://localhost:3306/wag?createDatabaseIfNotExist=true -spring.datasource.username=root -spring.datasource.password=1248 -spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver - -spring.jpa.show-sql=true -spring.jpa.hibernate.ddl-auto=update - -app.auth.tokenSecret=04ca023b39512e46d0c2cf4b48d5aac61d34302994c87ed4eff225dcf3b0a218739f3897051a057f9b846a69ea2927a587044164b7bae5e1306219d50b588cb1 -app.auth.tokenExpirationMsec = 864000000 -app.cors.allowedOrigins=http://localhost:3000,http://localhost:8080 -app.oauth2.authorizedRedirectUris=http://localhost:3000/oauth2/redirect,myandroidapp://oauth2/redirect,myiosapp://oauth2/redirect - -#KakaoTalk OAuth -spring.security.oauth2.client.registration.kakao.client-id=c82a058a88d9423c24fa5586a1323932 -spring.security.oauth2.client.registration.kakao.client-secret=5df68c1bf344a6ae3342d567a639a3b2 -spring.security.oauth2.client.provider.kakao.authorization-uri=https://kauth.kakao.com/oauth/authorize -spring.security.oauth2.client.registration.kakao.scope=profile_nickname,profile_image,account_email -spring.security.oauth2.client.registration.kakao.client-name=kakao-login -spring.security.oauth2.client.registration.kakao.authorization-grant-type=authorization_code -spring.security.oauth2.client.registration.kakao.redirect-uri=http://localhost:8080/oauth2/callback/kakao -spring.security.oauth2.client.registration.kakao.client-authentication-method=POST -spring.security.oauth2.client.provider.kakao.token-uri=https://kauth.kakao.com/oauth/token -spring.security.oauth2.client.provider.kakao.user-info-uri=https://kapi.kakao.com/v2/user/me -spring.security.oauth2.client.provider.kakao.user-name-attribute=id diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b239c89..e374d64 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,7 +12,10 @@ "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.6.8", + "bootstrap": "^5.3.3", + "http-proxy-middleware": "^3.0.0", "react": "^18.2.0", + "react-bootstrap": "^2.10.2", "react-bootstrap-validation": "^0.1.11", "react-dom": "^18.2.0", "react-grid-layout": "^1.4.4", @@ -6148,6 +6151,24 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -9741,26 +9762,19 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz", + "integrity": "sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw==", "dependencies": { - "@types/http-proxy": "^1.17.8", + "@types/http-proxy": "^1.17.10", + "debug": "^4.3.4", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "micromatch": "^4.0.5" }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/https-proxy-agent": { @@ -18274,6 +18288,29 @@ "ajv": "^8.8.2" } }, + "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 07fb8ff..878586d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -2,12 +2,16 @@ "name": "dingdong_front", "version": "0.1.0", "private": true, + "proxy": "http://localhost:8080", "dependencies": { "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.6.8", + "bootstrap": "^5.3.3", + "http-proxy-middleware": "^3.0.0", "react": "^18.2.0", + "react-bootstrap": "^2.10.2", "react-bootstrap-validation": "^0.1.11", "react-dom": "^18.2.0", "react-grid-layout": "^1.4.4", diff --git a/frontend/src/App.js b/frontend/src/App.js index c6b11c7..1523ff9 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,12 +1,39 @@ -import React from 'react'; -import {useState} from "react" +import React, { useState, useEffect } from 'react'; +import { Route, Routes } from "react-router-dom"; import './App.css'; +import axios from 'axios'; import Header from './Header'; -import ProductList from'./ProductList'; -import Mypage from'./Mypage'; -import Productreg from'./Productreg'; -import { Route, Routes,useNavigate } from "react-router-dom"; +import ProductList from './ProductList'; +import Mypage from './Mypage'; +import Productreg from './Productreg'; + function App() { + + // message 초기값을 ""으로 설정. + const [message, setMessage] = useState(""); + + // // useEffect(함수,배열) : 컴포넌트가 화면에 나타났을(마운트)때 자동 실행. + // useEffect( () => { + + // // fetch(url,options) : HTTP 요청 함수 + // fetch('/demo/hello') + // .then(response => response.text()) + // .then(message => { + // setMessage(message); + // }); + // },[]) + + useEffect(() => { + // axios.get(url, config)를 사용하여 GET 요청을 보냅니다. + axios.get('/demo/hello') + .then(response => { + setMessage(response.data); // 응답 데이터는 response.data에 있습니다. + }) + .catch(error => { + console.error('Error fetching data:', error); + }); + }, []); + return (
@@ -20,4 +47,4 @@ function App() { ); } -export default App; +export default App; \ No newline at end of file diff --git a/frontend/src/Productreg.js b/frontend/src/Productreg.js index 7628a93..4cf4453 100644 --- a/frontend/src/Productreg.js +++ b/frontend/src/Productreg.js @@ -1,4 +1,3 @@ - import Container from 'react-bootstrap/Container'; import Col from 'react-bootstrap/Col'; import Form from 'react-bootstrap/Form'; @@ -6,7 +5,6 @@ import Row from 'react-bootstrap/Row'; import Image from 'react-bootstrap/Image'; import React from "react"; import {useState} from "react"; - import axios from 'axios'; const OPTIONS = [ diff --git a/frontend/src/setProxy.js b/frontend/src/setProxy.js new file mode 100644 index 0000000..4465ded --- /dev/null +++ b/frontend/src/setProxy.js @@ -0,0 +1,11 @@ +const { createProxyMiddleware } = require('http-proxy-middleware'); + +module.exports = function(app) { + app.use( + '/api', + createProxyMiddleware({ + target: 'http://localhost:8080', + changeOrigin: true, + }) + ); +}; \ No newline at end of file