diff --git a/src/main/kotlin/team8/fruitable/controller/action/Cart.kt b/src/main/kotlin/team8/fruitable/controller/action/Cart.kt new file mode 100644 index 0000000..627ad84 --- /dev/null +++ b/src/main/kotlin/team8/fruitable/controller/action/Cart.kt @@ -0,0 +1,102 @@ +package team8.fruitable.controller.action + +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.CookieValue +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.servlet.mvc.support.RedirectAttributes +import team8.fruitable.controller.util.error +import team8.fruitable.datebase.entity.CartedItem +import team8.fruitable.datebase.entity.User +import team8.fruitable.datebase.repository.AccountRepository +import team8.fruitable.datebase.repository.CartRepository +import team8.fruitable.datebase.repository.ItemRepository + +@Controller +@RequestMapping("/action/cart") +class Cart( + private val cartRepository: CartRepository, + private val accountRepository: AccountRepository, + private val itemRepository: ItemRepository +) { + private fun getCurrentUser(token: String?): User? { + return token?.let(accountRepository::findByToken) + } + + @RequestMapping("/add/{id}") + fun add( + attributes: RedirectAttributes, + @CookieValue("TOKEN", required = false) token: String?, + @PathVariable("id") id: Long, + @RequestParam("redirect", required = false) redirect: String? + ): String { + val user = this.getCurrentUser(token) ?: return error(attributes, "添加商品至购物车", "未登录账户", "/login") + val item = itemRepository.findById(id) + .orElse(null) ?: return error(attributes, "添加商品至购物车", "商品不存在", "/cart") + cartRepository.save( + cartRepository.findByUserAndItem(user, item)?.let { + it.number += 1; it + } ?: CartedItem(user, item)) + redirect?.let { return "redirect:/${it}" } + return "redirect:/items" + } + + @RequestMapping("/add/{id}/{number}") + fun addByNumber( + attributes: RedirectAttributes, + @CookieValue("TOKEN", required = false) token: String?, + @PathVariable("id") id: Long, + @PathVariable("number") number: Int, + @RequestParam("redirect", required = false) redirect: String? + ): String { + val user = this.getCurrentUser(token) ?: return error(attributes, "添加商品至购物车", "账户未登录", "/login") + val item = itemRepository.findById(id) + .orElse(null) ?: return error(attributes, "添加商品至购物车", "商品不存在", "/cart") + cartRepository.save( + cartRepository.findByUserAndItem(user, item)?.let { + it.number += number; it + } ?: CartedItem(user, item, number)) + redirect?.let { return "redirect:/${it}" } + return "redirect:/items" + } + + @RequestMapping("/remove/{id}") + fun remove( + attributes: RedirectAttributes, + @CookieValue("TOKEN", required = false) token: String?, + @PathVariable("id") id: Long, + @RequestParam("redirect", required = false) redirect: String? + ): String { + val user = this.getCurrentUser(token) ?: return error(attributes, "将商品从购物车移除", "账户未登录", "/login") + val item = itemRepository.findById(id) + .orElse(null) ?: return error(attributes, "将商品从购物车移除", "商品不存在", "/cart") + cartRepository.findByUserAndItem(user, item)?.let { + cartRepository.delete(it) + } ?: return error(attributes, "将商品从购物车移除", "在购物车中未找到此商品", "/cart") + redirect?.let { return "redirect:/${it}" } + return "redirect:/items" + } + + @RequestMapping("/remove/{id}/{number}") + fun removeByNumber( + attributes: RedirectAttributes, + @CookieValue("TOKEN", required = false) token: String?, + @PathVariable("id") id: Long, + @PathVariable("number") number: Int, + @RequestParam("redirect", required = false) redirect: String? + ): String { + val user = this.getCurrentUser(token) ?: return error(attributes, "将商品从购物车移除", "账户未登录", "/login") + val item = itemRepository.findById(id) + .orElse(null) ?: return error(attributes, "将商品从购物车移除", "商品不存在", "/cart") + cartRepository.findByUserAndItem(user, item)?.let { + it.number -= number + if (it.number <= 0) + cartRepository.delete(it) + else + cartRepository.save(it) + } ?: return error(attributes, "将商品从购物车移除", "在购物车中未找到此商品", "/cart") + redirect?.let { return "redirect:/${it}" } + return "redirect:/items" + } +} diff --git a/src/main/kotlin/team8/fruitable/controller/action/Order.kt b/src/main/kotlin/team8/fruitable/controller/action/Order.kt new file mode 100644 index 0000000..4198fe1 --- /dev/null +++ b/src/main/kotlin/team8/fruitable/controller/action/Order.kt @@ -0,0 +1,4 @@ +package team8.fruitable.controller.action + +class Order { +} diff --git a/src/main/kotlin/team8/fruitable/datebase/entity/CartedItem.kt b/src/main/kotlin/team8/fruitable/datebase/entity/CartedItem.kt new file mode 100644 index 0000000..9447777 --- /dev/null +++ b/src/main/kotlin/team8/fruitable/datebase/entity/CartedItem.kt @@ -0,0 +1,32 @@ +package team8.fruitable.datebase.entity + +import jakarta.persistence.* + +@Entity +@Table(name = "carts") +class CartedItem( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + var id: Long? = null, + + @ManyToOne + @JoinColumn(name = "user_id") + var user: User? = null, + + @ManyToOne + @JoinColumn(name = "item_id") + var item: Item? = null, + + @Column(name = "number", nullable = false) + var number: Int = 1 +) { + constructor(user: User, item: Item) : this() { + this.user = user + this.item = item + } + + constructor(user: User, item: Item, number: Int?) : this(user, item) { + number?.let { this.number = if (number >= 1) number else 1 } + } +} diff --git a/src/main/kotlin/team8/fruitable/datebase/entity/Item.kt b/src/main/kotlin/team8/fruitable/datebase/entity/Item.kt index 6444617..dc41e14 100644 --- a/src/main/kotlin/team8/fruitable/datebase/entity/Item.kt +++ b/src/main/kotlin/team8/fruitable/datebase/entity/Item.kt @@ -33,9 +33,13 @@ class Item( @Column(name = "is_removed", nullable = false) var isRemoved: Boolean? = false, - @ManyToOne - @JoinColumn(name = "carts") - var carted: User? = null, + @ManyToMany(cascade = [CascadeType.ALL], fetch = FetchType.LAZY) + @JoinTable( + name = "carts", + joinColumns = [JoinColumn(name = "item_id", nullable = false)], + inverseJoinColumns = [JoinColumn(name = "user_id", nullable = false)] + ) + var carted: MutableList = mutableListOf(), @ManyToMany(cascade = [CascadeType.ALL], fetch = FetchType.LAZY) @JoinTable( @@ -48,13 +52,10 @@ class Item( @ManyToMany(cascade = [CascadeType.ALL], fetch = FetchType.LAZY) @JoinTable( name = "items_to_tags", - joinColumns = [JoinColumn(name = "item_id")], - inverseJoinColumns = [JoinColumn(name = "tag_id")] + joinColumns = [JoinColumn(name = "item_id", nullable = false)], + inverseJoinColumns = [JoinColumn(name = "tag_id", nullable = false)] ) - var tags: MutableList = mutableListOf(), - - @OneToOne(mappedBy = "item") - var recommend: Recommend? = null, + var tags: MutableList = mutableListOf() ) { constructor(name: String, price: Double) : this() { this.name = name diff --git a/src/main/kotlin/team8/fruitable/datebase/entity/Order.kt b/src/main/kotlin/team8/fruitable/datebase/entity/Order.kt index 0fe9918..942c49e 100644 --- a/src/main/kotlin/team8/fruitable/datebase/entity/Order.kt +++ b/src/main/kotlin/team8/fruitable/datebase/entity/Order.kt @@ -12,7 +12,6 @@ class Order( var id: Long? = null, @ManyToOne(optional = false) - @JoinColumn(name = "userid") var user: User? = null, @Column(name = "time_create", nullable = false) diff --git a/src/main/kotlin/team8/fruitable/datebase/entity/Recommend.kt b/src/main/kotlin/team8/fruitable/datebase/entity/Recommend.kt index 880402f..1d82423 100644 --- a/src/main/kotlin/team8/fruitable/datebase/entity/Recommend.kt +++ b/src/main/kotlin/team8/fruitable/datebase/entity/Recommend.kt @@ -11,7 +11,7 @@ class Recommend ( var id: Long? = null, @OneToOne - @JoinColumn(name = "item") + @JoinColumn(name = "item", nullable = false) var item: Item? = null, @Column(name="description", length=32, nullable = false) diff --git a/src/main/kotlin/team8/fruitable/datebase/entity/User.kt b/src/main/kotlin/team8/fruitable/datebase/entity/User.kt index 12ac835..964f895 100644 --- a/src/main/kotlin/team8/fruitable/datebase/entity/User.kt +++ b/src/main/kotlin/team8/fruitable/datebase/entity/User.kt @@ -47,10 +47,16 @@ class User( @Column(name = "is_admin", nullable = false) var isAdmin: Boolean = false, - @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY, mappedBy = "carted") + @ManyToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY) + @JoinTable( + name = "carts", + joinColumns = [JoinColumn(name = "user_id", nullable = false)], + inverseJoinColumns = [JoinColumn(name = "item_id", nullable = false)] + ) var carts: MutableList = mutableListOf(), - @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY, mappedBy = "user") + @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") var orders: MutableList = mutableListOf() ) { constructor(name: String, password: String) : this() { diff --git a/src/main/kotlin/team8/fruitable/datebase/repository/CartRepository.kt b/src/main/kotlin/team8/fruitable/datebase/repository/CartRepository.kt new file mode 100644 index 0000000..6e099c1 --- /dev/null +++ b/src/main/kotlin/team8/fruitable/datebase/repository/CartRepository.kt @@ -0,0 +1,10 @@ +package team8.fruitable.datebase.repository + +import org.springframework.data.repository.CrudRepository +import team8.fruitable.datebase.entity.CartedItem +import team8.fruitable.datebase.entity.Item +import team8.fruitable.datebase.entity.User + +interface CartRepository : CrudRepository { + fun findByUserAndItem(user: User, item: Item): CartedItem? +} diff --git a/src/main/resources/static/images/pay_type/GooglePay.svg b/src/main/resources/static/images/pay_type/GooglePay.svg index 2037405..170b19d 100644 --- a/src/main/resources/static/images/pay_type/GooglePay.svg +++ b/src/main/resources/static/images/pay_type/GooglePay.svg @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/static/images/pay_type/Paypal.svg b/src/main/resources/static/images/pay_type/Paypal.svg index 34ccc95..e0cdb7c 100644 --- a/src/main/resources/static/images/pay_type/Paypal.svg +++ b/src/main/resources/static/images/pay_type/Paypal.svg @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/static/images/pay_type/UnionPay.svg b/src/main/resources/static/images/pay_type/UnionPay.svg index 0f1f747..e252bbd 100644 --- a/src/main/resources/static/images/pay_type/UnionPay.svg +++ b/src/main/resources/static/images/pay_type/UnionPay.svg @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/static/images/pay_type/WeChatPay.svg b/src/main/resources/static/images/pay_type/WeChatPay.svg index 9692e3c..9c83f1e 100644 --- a/src/main/resources/static/images/pay_type/WeChatPay.svg +++ b/src/main/resources/static/images/pay_type/WeChatPay.svg @@ -1,5 +1,5 @@ - + 编组 diff --git a/src/main/resources/templates/index.mustache b/src/main/resources/templates/index.mustache index 27e5830..f3b6772 100644 --- a/src/main/resources/templates/index.mustache +++ b/src/main/resources/templates/index.mustache @@ -63,4 +63,4 @@ {{>footer}} - \ No newline at end of file + diff --git a/src/main/resources/templates/item.mustache b/src/main/resources/templates/item.mustache index 465681f..4a8e253 100644 --- a/src/main/resources/templates/item.mustache +++ b/src/main/resources/templates/item.mustache @@ -2,7 +2,7 @@ - 商品 - 在线果蔬商城 + {{item.name}} - 在线果蔬商城 diff --git a/src/main/resources/templates/items.mustache b/src/main/resources/templates/items.mustache index e69de29..8d42958 100644 --- a/src/main/resources/templates/items.mustache +++ b/src/main/resources/templates/items.mustache @@ -0,0 +1,36 @@ + + + + + 商品 - 在线果蔬商城 + + + + + + + + + + + + + + + + + + + + + +{{>header}} + + +
+
+ +{{>footer}} + + +