├── flea_market_project ├── .gitignore ├── src │ ├── main │ │ ├── java │ │ │ ├── model │ │ │ │ ├── bean │ │ │ │ │ ├── Notification.java │ │ │ │ │ ├── ChatSession.java │ │ │ │ │ ├── UserSummary.java │ │ │ │ │ ├── ProductPic.java │ │ │ │ │ ├── Social.java │ │ │ │ │ ├── BulletinMsg.java │ │ │ │ │ ├── ProductSummary.java │ │ │ │ │ ├── ProductComment.java │ │ │ │ │ ├── ChatMsg.java │ │ │ │ │ ├── UserDetail.java │ │ │ │ │ └── ProductDetail.java │ │ │ │ └── dao │ │ │ │ │ ├── repo │ │ │ │ │ ├── SocialRepo.java │ │ │ │ │ ├── ProductPicRepo.java │ │ │ │ │ ├── BulletinMsgRepo.java │ │ │ │ │ ├── NotificationRepo.java │ │ │ │ │ ├── UserRepo.java │ │ │ │ │ ├── ChatMsgRepo.java │ │ │ │ │ ├── ProductCommentRepo.java │ │ │ │ │ ├── TokenRepo.java │ │ │ │ │ ├── ProductRepo.java │ │ │ │ │ └── ChatRepo.java │ │ │ │ │ └── entity │ │ │ │ │ ├── TokenEntity.java │ │ │ │ │ ├── ProductPicEntity.java │ │ │ │ │ ├── SocialEntity.java │ │ │ │ │ ├── BulletinMsgEntity.java │ │ │ │ │ ├── ChatSessionEntity.java │ │ │ │ │ ├── NotificationEntity.java │ │ │ │ │ ├── ProductCommentEntity.java │ │ │ │ │ ├── ChatMsgEntity.java │ │ │ │ │ ├── ProductEntity.java │ │ │ │ │ └── UserEntity.java │ │ │ ├── service │ │ │ │ ├── PictureService.java │ │ │ │ ├── SystemService.java │ │ │ │ ├── NotificationService.java │ │ │ │ ├── AdminService.java │ │ │ │ ├── ChatService.java │ │ │ │ ├── UserService.java │ │ │ │ ├── impl │ │ │ │ │ ├── PictureServiceImpl.java │ │ │ │ │ ├── SystemServiceImpl.java │ │ │ │ │ ├── AdminServiceImpl.java │ │ │ │ │ ├── ChatServiceImpl.java │ │ │ │ │ ├── UserServiceImpl.java │ │ │ │ │ └── ProductServiceImpl.java │ │ │ │ └── ProductService.java │ │ │ ├── webController │ │ │ │ ├── Utils.java │ │ │ │ └── api │ │ │ │ │ ├── Chat.java │ │ │ │ │ ├── Picture.java │ │ │ │ │ ├── Admin.java │ │ │ │ │ ├── User.java │ │ │ │ │ └── Product.java │ │ │ └── application │ │ │ │ ├── MainApplication.java │ │ │ │ └── Config.java │ │ └── resources │ │ │ ├── data.sql │ │ │ ├── application.properties │ │ │ └── spring-config.xml │ └── test │ │ ├── resources │ │ └── application.properties │ │ └── java │ │ └── application │ │ └── test │ │ ├── AdminServiceTest.java │ │ ├── ChatServiceTest.java │ │ ├── UserServiceTest.java │ │ └── ProductServiceTest.java └── pom.xml ├── .gitignore ├── flea_market.txt └── data_define.txt /flea_market_project/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /**/.idea 2 | /**/*.kate-swp 3 | /**/*.class 4 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/Notification.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Notification { 7 | } 8 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/PictureService.java: -------------------------------------------------------------------------------- 1 | package service; 2 | 3 | import org.springframework.lang.Nullable; 4 | 5 | public interface PictureService { 6 | String storePic(byte[] f); 7 | 8 | @Nullable 9 | byte[] getPic(String picUid); 10 | } 11 | -------------------------------------------------------------------------------- /flea_market_project/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | insert into t_user (c_admin, c_avatar_url, c_ban_until, c_join_time, c_nickname, c_password, c_username) 2 | values (true, 'initAdminAvatar', '1970-01-01', '1970-01-01', 'initAdmin', 'initAdmin', 'initAdmin') 3 | on duplicate key update c_admin=true ; -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/repo/SocialRepo.java: -------------------------------------------------------------------------------- 1 | package model.dao.repo; 2 | 3 | import model.dao.entity.SocialEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface SocialRepo extends JpaRepository { 9 | } 10 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/repo/ProductPicRepo.java: -------------------------------------------------------------------------------- 1 | package model.dao.repo; 2 | 3 | import model.dao.entity.ProductPicEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface ProductPicRepo extends JpaRepository { 9 | } 10 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/repo/BulletinMsgRepo.java: -------------------------------------------------------------------------------- 1 | package model.dao.repo; 2 | 3 | import model.dao.entity.BulletinMsgEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface BulletinMsgRepo extends JpaRepository { 9 | } 10 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/repo/NotificationRepo.java: -------------------------------------------------------------------------------- 1 | package model.dao.repo; 2 | 3 | import model.dao.entity.NotificationEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface NotificationRepo extends JpaRepository { 9 | } 10 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/repo/UserRepo.java: -------------------------------------------------------------------------------- 1 | package model.dao.repo; 2 | 3 | import model.dao.entity.UserEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface UserRepo extends JpaRepository { 11 | List findByUsernameEquals(String username); 12 | } 13 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/ChatSession.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import model.dao.entity.ChatSessionEntity; 6 | import org.springframework.beans.BeanUtils; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | public class ChatSession { 11 | 12 | private Long chatSessionId; 13 | 14 | public ChatSession(ChatSessionEntity chat) { 15 | BeanUtils.copyProperties(chat, this); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/SystemService.java: -------------------------------------------------------------------------------- 1 | package service; 2 | 3 | import model.dao.entity.UserEntity; 4 | import org.springframework.lang.Nullable; 5 | 6 | public interface SystemService { 7 | 8 | @Nullable 9 | UserEntity token2User(String token); 10 | 11 | @Nullable 12 | String authorizeToken(Long userId); 13 | 14 | Boolean invokeToken(String token); 15 | 16 | @Nullable 17 | UserEntity findUserByUsername(String username); 18 | } 19 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/UserSummary.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import model.dao.entity.UserEntity; 6 | import org.springframework.beans.BeanUtils; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | public class UserSummary { 11 | 12 | String username; 13 | 14 | String nickname; 15 | 16 | String avatarUrl; 17 | 18 | public UserSummary(UserEntity user) { 19 | BeanUtils.copyProperties(user, this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/repo/ChatMsgRepo.java: -------------------------------------------------------------------------------- 1 | package model.dao.repo; 2 | 3 | import model.dao.entity.ChatSessionEntity; 4 | import model.dao.entity.ChatMsgEntity; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | @Repository 11 | public interface ChatMsgRepo extends JpaRepository { 12 | List findByChatSessionEquals(ChatSessionEntity chatSession); 13 | } 14 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/ProductPic.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import model.dao.entity.ProductPicEntity; 6 | import org.springframework.beans.BeanUtils; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | public class ProductPic { 11 | 12 | private String productPicUrl; 13 | 14 | private Long productPicId; 15 | 16 | public ProductPic(ProductPicEntity productPicEntity) { 17 | BeanUtils.copyProperties(productPicEntity, this); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/Social.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import model.dao.entity.SocialEntity; 6 | import org.springframework.beans.BeanUtils; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | public class Social { 11 | 12 | private Long socialId; 13 | 14 | private String socialType; 15 | 16 | private String socialUrl; 17 | 18 | public Social(SocialEntity socialEntity) { 19 | BeanUtils.copyProperties(socialEntity, this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/repo/ProductCommentRepo.java: -------------------------------------------------------------------------------- 1 | package model.dao.repo; 2 | 3 | import model.dao.entity.ProductCommentEntity; 4 | import model.dao.entity.ProductEntity; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | @Repository 11 | public interface ProductCommentRepo extends JpaRepository { 12 | List findByProductEquals(ProductEntity product); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/NotificationService.java: -------------------------------------------------------------------------------- 1 | package service; 2 | 3 | import model.bean.BulletinMsg; 4 | import model.bean.Notification; 5 | import org.springframework.lang.Nullable; 6 | 7 | import java.util.List; 8 | 9 | public interface NotificationService { 10 | 11 | @Nullable 12 | List getNotifications(String token); 13 | 14 | Boolean addNotification(String username, String notificationContent); 15 | 16 | Boolean readNotification(String token, Long notificationId); 17 | 18 | List getBulletinMsg(); 19 | } 20 | -------------------------------------------------------------------------------- /flea_market_project/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | 3 | spring.datasource.driver-class-name=org.mariadb.jdbc.Driver 4 | spring.datasource.url=jdbc:mariadb://localhost:3306/flea_market 5 | spring.datasource.username=flea_market 6 | spring.datasource.password=flea 7 | spring.datasource.initialization-mode=always 8 | spring.datasource.data=classpath:data.sql 9 | 10 | spring.servlet.multipart.max-file-size=10MB 11 | spring.servlet.multipart.max-request-size=10MB 12 | 13 | spring.jpa.open-in-view=true 14 | spring.jpa.show-sql=false 15 | spring.jpa.hibernate.ddl-auto=update 16 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/repo/TokenRepo.java: -------------------------------------------------------------------------------- 1 | package model.dao.repo; 2 | 3 | import model.dao.entity.TokenEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | @Repository 11 | public interface TokenRepo extends JpaRepository { 12 | // @Query("SELECT t FROM TokenEntity t WHERE t.token = :token") 13 | // List findByToken(String token); 14 | 15 | List findByTokenEquals(String token); 16 | } 17 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/BulletinMsg.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import model.dao.entity.BulletinMsgEntity; 6 | import org.springframework.beans.BeanUtils; 7 | 8 | import java.util.Date; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | public class BulletinMsg { 13 | 14 | Long bulletinId; 15 | 16 | UserSummary user; 17 | 18 | Date publishTime; 19 | 20 | String content; 21 | 22 | public BulletinMsg(BulletinMsgEntity msg) { 23 | BeanUtils.copyProperties(msg, this); 24 | this.user = new UserSummary(msg.getUser()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/ProductSummary.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import model.dao.entity.ProductEntity; 6 | import org.springframework.beans.BeanUtils; 7 | 8 | import java.util.Date; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | public class ProductSummary { 13 | 14 | Long productId; 15 | 16 | String productName; 17 | 18 | Date publishTime; 19 | 20 | UserSummary seller; 21 | 22 | public ProductSummary(ProductEntity product) { 23 | BeanUtils.copyProperties(product, this); 24 | this.setSeller(new UserSummary(product.getSeller())); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/entity/TokenEntity.java: -------------------------------------------------------------------------------- 1 | package model.dao.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.util.Date; 7 | 8 | @Data 9 | @Entity 10 | @Table(name = "t_login_token") 11 | public class TokenEntity { 12 | @Id 13 | @Column(name = "c_token_id") 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | Long tokenId; 16 | 17 | @Column(name = "c_token", length = 36, unique = true, nullable = false) 18 | String token; 19 | 20 | Date expireTime; 21 | 22 | @ManyToOne(cascade = CascadeType.MERGE) 23 | @JoinColumn(name = "c_user_id") 24 | UserEntity user; 25 | } 26 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/ProductComment.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import model.dao.entity.ProductCommentEntity; 6 | import org.springframework.beans.BeanUtils; 7 | 8 | import java.util.Date; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | public class ProductComment { 13 | 14 | private Long commentId; 15 | 16 | private String content; 17 | 18 | private Date commentTime; 19 | 20 | private UserSummary user; 21 | 22 | public ProductComment(ProductCommentEntity p) { 23 | BeanUtils.copyProperties(p, this); 24 | this.user = new UserSummary(p.getUser()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /flea_market.txt: -------------------------------------------------------------------------------- 1 | 登陆界面 2 | 3 | 用户信息界面 4 | 昵称 5 | 用户名 6 | 修改密码(自己可见) 7 | 注册时间 8 | 是否封禁 9 | 社交方式和社交url 10 | (设置管理员)(超级管理员可见) 11 | -获取用户信息(用户名->用户对象) 12 | 13 | 14 | 集市界面 15 | 产品简略信息 16 | 产品发布名称 17 | 产品发布用户名 18 | 产品发布时间 19 | 产品评论数 20 | 获取最近售卖产品,List<产品简略信息> 21 | 22 | 单一产品 23 | 产品详细信息 24 | 产品发布名称 25 | 产品发布用户 26 | 产品发布详情 27 | 产品发布时间 28 | 动作区域 29 | 请求购买 30 | 下架产品 31 | 批准审核 32 | 33 | 评论区域 34 | 无reply_to属性评论 35 | 评论内容 36 | 评论时间 37 | 评论人 38 | 评论人头像 39 | 查看回复 40 | | 41 | ---回复内容 42 | 回复用户昵称 43 | 回复用户头像 44 | 45 | 私信界面 46 | 私信对方 47 | 私信消息 48 | 私信时间 49 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/entity/ProductPicEntity.java: -------------------------------------------------------------------------------- 1 | package model.dao.entity; 2 | 3 | import lombok.Data; 4 | import org.hibernate.annotations.GeneratorType; 5 | 6 | import javax.persistence.*; 7 | 8 | @Data 9 | @Entity 10 | @Table(name = "t_product_pic") 11 | public class ProductPicEntity { 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.IDENTITY) 14 | @Column(name = "c_product_pic_id") 15 | Long productPicId; 16 | 17 | @ManyToOne(cascade = CascadeType.MERGE) 18 | @JoinColumn(name = "c_product_id", nullable = false) 19 | ProductEntity product; 20 | 21 | @Column(name = "c_product_pic_url", nullable = false) 22 | String productPicUrl; 23 | } 24 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/entity/SocialEntity.java: -------------------------------------------------------------------------------- 1 | package model.dao.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | 7 | @Data 8 | @Table(name = "t_social") 9 | @Entity 10 | public class SocialEntity { 11 | @ManyToOne(cascade = CascadeType.MERGE) 12 | @JoinColumn(name = "c_user_id", nullable = false) 13 | UserEntity user; 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | @Column(name = "c_social_id") 18 | Long socialId; 19 | 20 | @Column(name = "c_social_type", nullable = false) 21 | String socialType; 22 | 23 | @Column(name = "c_social_url", nullable = false) 24 | String socialUrl; 25 | } 26 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/AdminService.java: -------------------------------------------------------------------------------- 1 | package service; 2 | 3 | import model.bean.ProductSummary; 4 | import org.springframework.lang.Nullable; 5 | 6 | import java.util.List; 7 | 8 | public interface AdminService { 9 | // User operate 10 | 11 | Boolean grantUser(String token, String username); 12 | 13 | Boolean banUser(String token, String username, Integer day); 14 | 15 | // Product operate 16 | 17 | @Nullable 18 | List getCensoringProducts(String token); 19 | 20 | Boolean censorProduct(String token, Long productId, Boolean pass); 21 | 22 | // Bulletin operate 23 | 24 | Boolean publishBulletin(String token, String bulletinMsg); 25 | } 26 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/entity/BulletinMsgEntity.java: -------------------------------------------------------------------------------- 1 | package model.dao.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.util.Date; 7 | 8 | @Data 9 | @Entity 10 | @Table(name = "t_bulletin_msg") 11 | public class BulletinMsgEntity { 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.IDENTITY) 14 | @Column(name = "c_bulletin_msg_id") 15 | Long bulletinId; 16 | 17 | @ManyToOne(cascade = CascadeType.MERGE) 18 | @JoinColumn(name = "c_user_id", nullable = false) 19 | UserEntity user; 20 | 21 | @Column(name = "c_publish_time", nullable = false) 22 | Date publishTime; 23 | 24 | @Lob 25 | @Column(name = "c_content", nullable = false) 26 | String content; 27 | } 28 | -------------------------------------------------------------------------------- /flea_market_project/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | #server.port=8080 2 | # 3 | #spring.datasource.driver-class-name=org.h2.Driver 4 | #spring.datasource.url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1 5 | # 6 | #spring.jpa.open-in-view=true 7 | #spring.jpa.show-sql=false 8 | #spring.jpa.hibernate.ddl-auto=create 9 | 10 | 11 | server.port=8080 12 | 13 | spring.datasource.driver-class-name=org.mariadb.jdbc.Driver 14 | spring.datasource.url=jdbc:mariadb://localhost:3306/flea_market 15 | spring.datasource.username=flea_market 16 | spring.datasource.password=flea 17 | spring.datasource.initialization-mode=always 18 | spring.datasource.data=classpath:data.sql 19 | 20 | spring.jpa.open-in-view=true 21 | spring.jpa.show-sql=false 22 | spring.jpa.hibernate.ddl-auto=create 23 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/entity/ChatSessionEntity.java: -------------------------------------------------------------------------------- 1 | package model.dao.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | import javax.persistence.*; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | @Getter 12 | @Setter 13 | @Entity 14 | @Table(name = "t_chat_session") 15 | public class ChatSessionEntity { 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | @Column(name = "c_chat_session_id") 19 | Long chatSessionId; 20 | 21 | @JsonIgnore 22 | @ManyToMany(mappedBy = "chatSessionList") 23 | Set userList; 24 | 25 | public ChatSessionEntity() { 26 | this.userList = new HashSet<>(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/ChatService.java: -------------------------------------------------------------------------------- 1 | package service; 2 | 3 | import model.bean.ChatMsg; 4 | import model.bean.ChatSession; 5 | import org.springframework.lang.Nullable; 6 | 7 | import java.util.List; 8 | 9 | public interface ChatService { 10 | 11 | // create chat session if not exist. 12 | // or get the exist session 13 | @Nullable 14 | Long startChatSession(String token, String username); 15 | 16 | @Nullable 17 | List getChatSessions(String token); 18 | 19 | // check if chat session owned by user. 20 | Boolean sendMsg(String token, Long chatSessionId, String Content); 21 | 22 | // check if chat session owned by user. 23 | @Nullable 24 | List getMsg(String token, Long chatSessionId); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/ChatMsg.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import model.dao.entity.ChatMsgEntity; 6 | 7 | import java.util.Date; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | public class ChatMsg { 12 | 13 | private Long chatMsgId; 14 | 15 | private Long chatSessionId; 16 | 17 | private Date messageTime; 18 | 19 | private String content; 20 | 21 | private UserSummary sender; 22 | 23 | public ChatMsg(ChatMsgEntity chatMsg) { 24 | this.chatMsgId = chatMsg.getChatMsgId(); 25 | this.chatSessionId = chatMsg.getChatSession().getChatSessionId(); 26 | this.messageTime = chatMsg.getMessageTime(); 27 | this.sender = new UserSummary(chatMsg.getSender()); 28 | this.content = chatMsg.getContent(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/entity/NotificationEntity.java: -------------------------------------------------------------------------------- 1 | package model.dao.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.util.Date; 7 | 8 | @Data 9 | @Entity 10 | @Table(name = "t_notification") 11 | public class NotificationEntity { 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.IDENTITY) 14 | @Column(name = "c_notification_id") 15 | Long notificationId; 16 | 17 | @ManyToOne(cascade = CascadeType.MERGE) 18 | @JoinColumn(name = "c_user_id", nullable = false) 19 | UserEntity user; 20 | 21 | // have read 22 | @Column(name = "c_read") 23 | Boolean read; 24 | 25 | @Column(name = "c_notification_time", nullable = false) 26 | Date notificationTime; 27 | 28 | @Column(name = "c_notification_content") 29 | String notificationContent; 30 | } 31 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/entity/ProductCommentEntity.java: -------------------------------------------------------------------------------- 1 | package model.dao.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.util.Date; 7 | 8 | @Data 9 | @Entity 10 | @Table(name = "t_comment") 11 | public class ProductCommentEntity { 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.IDENTITY) 14 | @Column(name = "c_comment_id") 15 | Long commentId; 16 | 17 | @ManyToOne(cascade = CascadeType.MERGE) 18 | @JoinColumn(name = "c_product_id", nullable = false) 19 | ProductEntity product; 20 | 21 | @ManyToOne(cascade = CascadeType.MERGE) 22 | @JoinColumn(name = "c_user_id", nullable = false) 23 | UserEntity user; 24 | 25 | @Column(name = "c_content", nullable = false) 26 | String content; 27 | 28 | @Column(name = "c_comment_time", nullable = false) 29 | Date commentTime; 30 | } 31 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/repo/ProductRepo.java: -------------------------------------------------------------------------------- 1 | package model.dao.repo; 2 | 3 | import model.dao.entity.ProductEntity; 4 | import model.dao.entity.UserEntity; 5 | import org.springframework.data.domain.Sort; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.stereotype.Repository; 8 | 9 | import java.util.List; 10 | 11 | @Repository 12 | public interface ProductRepo extends JpaRepository { 13 | 14 | Sort sortByReleaseDesc = Sort.by(Sort.Direction.DESC, "publishTime"); 15 | 16 | List findByProductStatusEquals(String status, Sort sort); 17 | 18 | List findBySellerEquals(UserEntity seller, Sort sort); 19 | 20 | List findByBuyerEquals(UserEntity buyer, Sort sort); 21 | 22 | List findTopByProductStatusEquals(String status); 23 | } 24 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/entity/ChatMsgEntity.java: -------------------------------------------------------------------------------- 1 | package model.dao.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.util.Date; 7 | 8 | @Data 9 | @Entity 10 | @Table(name = "t_chat_msg") 11 | public class ChatMsgEntity { 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.IDENTITY) 14 | @Column(name = "c_chat_msg_id") 15 | Long chatMsgId; 16 | 17 | @ManyToOne(cascade = CascadeType.MERGE) 18 | @JoinColumn(name = "c_chat_id", nullable = false) 19 | ChatSessionEntity chatSession; 20 | 21 | @ManyToOne(cascade = CascadeType.MERGE) 22 | @JoinColumn(name = "c_sender_id", nullable = false) 23 | UserEntity sender; 24 | 25 | @Column(name = "c_chat_msg_time", nullable = false) 26 | Date messageTime; 27 | 28 | @Column(name = "c_chat_msg_content", nullable = false) 29 | String content; 30 | } 31 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/repo/ChatRepo.java: -------------------------------------------------------------------------------- 1 | package model.dao.repo; 2 | 3 | import model.dao.entity.ChatSessionEntity; 4 | import model.dao.entity.UserEntity; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Query; 7 | import org.springframework.data.repository.query.Param; 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.util.List; 11 | 12 | @Repository 13 | public interface ChatRepo extends JpaRepository { 14 | @Query("select c from ChatSessionEntity c where :user1 in (select user from c.userList user) and :user2 in (select user from c.userList user) order by size(c.userList)") 15 | List findByChatMember(@Param("user1") UserEntity user1, @Param("user2") UserEntity user2); 16 | 17 | @Query("select c from ChatSessionEntity c where :user in (select user from c.userList user) order by size(c.userList)") 18 | List findByChatMember(@Param("user") UserEntity user); 19 | } 20 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/UserDetail.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import model.dao.entity.SocialEntity; 6 | import model.dao.entity.UserEntity; 7 | import org.springframework.beans.BeanUtils; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Date; 11 | import java.util.List; 12 | 13 | @Data 14 | @NoArgsConstructor 15 | public class UserDetail { 16 | 17 | String username; 18 | 19 | String nickname; 20 | 21 | String avatarUrl; 22 | 23 | Date banUntil; 24 | 25 | Date JoinTime; 26 | 27 | Boolean admin; 28 | 29 | private List socialList; 30 | 31 | public UserDetail(UserEntity userEntity) { 32 | BeanUtils.copyProperties(userEntity, this); 33 | 34 | List sle = userEntity.getSocialList(); 35 | List sl = new ArrayList<>(sle.size()); 36 | for (SocialEntity socialEntity : sle) { 37 | sl.add(new Social(socialEntity)); 38 | } 39 | this.setSocialList(sl); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/webController/Utils.java: -------------------------------------------------------------------------------- 1 | package webController; 2 | 3 | 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.json.JsonMapper; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.lang.Nullable; 8 | 9 | /** 10 | * response body should like the follow. 11 | * data is serialized bean if success is true, 12 | * or else data is error message. 13 | * { 14 | * "success": true, 15 | * "data": null 16 | * } 17 | */ 18 | @Slf4j 19 | public class Utils { 20 | @Nullable 21 | public static String format(Boolean succeed, Object data) { 22 | JsonMapper mapper = new JsonMapper(); 23 | try { 24 | String dataJson = mapper.writeValueAsString(data); 25 | if (succeed) { 26 | return "{\"success\": true, \"data\": " + dataJson + "}"; 27 | } else { 28 | return "{\"success\": false, \"data\": " + dataJson + "}"; 29 | } 30 | } catch (JsonProcessingException e) { 31 | log.error("format json response failed", e); 32 | return null; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/UserService.java: -------------------------------------------------------------------------------- 1 | package service; 2 | 3 | import model.bean.UserDetail; 4 | import org.springframework.lang.Nullable; 5 | 6 | public interface UserService { 7 | // register a new user. 8 | // default join time will be now, ban_util will be 1970, 9 | // avatar_url will be 0 length string, admin is false 10 | Boolean register(String username, String nickname, String password); 11 | 12 | // return String of token to store in cookie if success, null if fail. 13 | @Nullable 14 | String authorize(String username, String password); 15 | 16 | // expire this token 17 | Boolean logout(String token); 18 | 19 | Boolean modifyPassword(String token, String password); 20 | 21 | Boolean modifyNickname(String token, String nickname); 22 | 23 | Boolean modifyAvatar(String token, String avatarUrl); 24 | 25 | @Nullable 26 | Long addSocial(String token, String socialType, String socialUrl); 27 | 28 | Boolean removeSocial(String token, Long socialId); 29 | 30 | @Nullable 31 | UserDetail getMyDetail(String token); 32 | 33 | @Nullable 34 | UserDetail getUserDetail(String username); 35 | } 36 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/application/MainApplication.java: -------------------------------------------------------------------------------- 1 | package application; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.autoconfigure.domain.EntityScan; 7 | import org.springframework.boot.web.servlet.ServletComponentScan; 8 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 9 | import org.springframework.context.ConfigurableApplicationContext; 10 | import org.springframework.context.annotation.ComponentScan; 11 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 12 | 13 | @EntityScan(basePackages = {"model.dao.entity"}) 14 | @EnableJpaRepositories(basePackages = {"model.dao.repo"}) 15 | @ComponentScan(basePackages = {"service", "webController.api", "application"}) 16 | @ServletComponentScan(basePackages = {"webController.filter"}) 17 | @SpringBootApplication 18 | @Slf4j 19 | public class MainApplication extends SpringBootServletInitializer { 20 | 21 | public static void main(String[] args) { 22 | ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/bean/ProductDetail.java: -------------------------------------------------------------------------------- 1 | package model.bean; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import model.dao.entity.ProductEntity; 6 | import model.dao.entity.ProductPicEntity; 7 | import org.springframework.beans.BeanUtils; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Date; 11 | import java.util.List; 12 | 13 | @Data 14 | @NoArgsConstructor 15 | public class ProductDetail { 16 | 17 | private Long productId; 18 | 19 | private String productName; 20 | 21 | private String productDetail; 22 | 23 | private String productStatus; 24 | 25 | private Double expectedPrice; 26 | 27 | private Date publishTime; 28 | 29 | private UserDetail seller; 30 | 31 | private UserDetail buyer; 32 | 33 | private Date clinchTime; 34 | 35 | private List pics; 36 | 37 | public ProductDetail(ProductEntity productEntity) { 38 | BeanUtils.copyProperties(productEntity, this); 39 | 40 | List productPicList = productEntity.getProductPicList(); 41 | this.pics = new ArrayList<>(productPicList.size()); 42 | for (ProductPicEntity productPicEntity : productPicList) { 43 | this.pics.add(new ProductPic(productPicEntity)); 44 | } 45 | 46 | this.seller = new UserDetail(productEntity.getSeller()); 47 | 48 | if (productEntity.getBuyer() != null) { 49 | this.buyer = new UserDetail(productEntity.getBuyer()); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /flea_market_project/src/main/resources/spring-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/entity/ProductEntity.java: -------------------------------------------------------------------------------- 1 | package model.dao.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.util.Date; 7 | import java.util.List; 8 | 9 | @Data 10 | @Entity 11 | @Table(name = "t_product") 12 | public class ProductEntity { 13 | @Id 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | @Column(name = "c_product_id") 16 | Long productId; 17 | 18 | @ManyToOne(cascade = CascadeType.MERGE) 19 | @JoinColumn(name = "c_buyer_id") 20 | UserEntity buyer; 21 | 22 | @ManyToOne(cascade = CascadeType.MERGE) 23 | @JoinColumn(name = "c_seller_id", nullable = false) 24 | UserEntity seller; 25 | 26 | // censoring, selling, ordered, confirmed_seller, confirmed_buyer, withdrawn 27 | @Column(name = "c_product_status", nullable = false) 28 | String productStatus; 29 | 30 | @Column(name = "c_expected_price", nullable = false) 31 | Double expectedPrice; 32 | 33 | @Column(name = "c_publish_time", nullable = false) 34 | Date publishTime; 35 | 36 | @Column(name = "c_product_name", nullable = false) 37 | String productName; 38 | 39 | @Lob 40 | @Column(name = "c_product_detail", nullable = false) 41 | String productDetail; 42 | 43 | @Column(name = "c_clinch_time") 44 | Date clinchTime; 45 | 46 | @OneToMany(mappedBy = "product", cascade = CascadeType.ALL) 47 | List productPicList; 48 | 49 | @OneToMany(mappedBy = "product", cascade = CascadeType.ALL) 50 | List commentList; 51 | } 52 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/impl/PictureServiceImpl.java: -------------------------------------------------------------------------------- 1 | package service.impl; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.data.redis.core.ValueOperations; 8 | import org.springframework.lang.Nullable; 9 | import org.springframework.stereotype.Service; 10 | import service.PictureService; 11 | 12 | import java.util.UUID; 13 | 14 | @Slf4j 15 | @Service 16 | public class PictureServiceImpl implements PictureService { 17 | 18 | RedisTemplate redisTemplate; 19 | 20 | @Autowired 21 | public PictureServiceImpl(@Qualifier(value = "redisTemplate") RedisTemplate redisTemplate) { 22 | this.redisTemplate = redisTemplate; 23 | } 24 | 25 | @Override 26 | public String storePic(byte[] fileByte) { 27 | String picUid = UUID.randomUUID().toString(); 28 | ValueOperations ops = redisTemplate.opsForValue(); 29 | ops.set(picUid, fileByte); 30 | log.info("pic {} saved", picUid); 31 | return picUid; 32 | } 33 | 34 | @Override 35 | @Nullable 36 | public byte[] getPic(String picUid) { 37 | ValueOperations ops = redisTemplate.opsForValue(); 38 | byte[] fileByte = ops.get(picUid); 39 | if (fileByte == null) { 40 | log.warn("getting not existed pic {}", picUid); 41 | return null; 42 | } else { 43 | log.info("got pic {}", picUid); 44 | return fileByte; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/application/Config.java: -------------------------------------------------------------------------------- 1 | package application; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.redis.connection.RedisStandaloneConfiguration; 7 | import org.springframework.data.redis.connection.jedis.JedisClientConfiguration; 8 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 9 | import org.springframework.data.redis.core.RedisTemplate; 10 | 11 | import java.time.Duration; 12 | 13 | @Configuration 14 | @Slf4j 15 | public class Config { 16 | @Bean(name = "redisTemplate") 17 | RedisTemplate redisTemplate() { 18 | RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration(); 19 | redisConfiguration.setHostName("localhost"); 20 | redisConfiguration.setPort(6379); 21 | redisConfiguration.setDatabase(0); 22 | redisConfiguration.setPassword("flea_market"); 23 | 24 | JedisClientConfiguration jedisConfiguration = JedisClientConfiguration.builder() 25 | .usePooling() 26 | .and() 27 | .connectTimeout(Duration.ofSeconds(300L)) 28 | .build(); 29 | 30 | // JedisConnectionFactory factory = new JedisConnectionFactory(configuration); 31 | // factory. 32 | 33 | // 37 | 38 | JedisConnectionFactory factory = new JedisConnectionFactory(redisConfiguration, jedisConfiguration); 39 | 40 | RedisTemplate template = new RedisTemplate<>(); 41 | template.setConnectionFactory(factory); 42 | return template; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/model/dao/entity/UserEntity.java: -------------------------------------------------------------------------------- 1 | package model.dao.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.util.Date; 7 | import java.util.List; 8 | import java.util.Set; 9 | 10 | @Data 11 | @Entity 12 | @Table(name = "t_user") 13 | public class UserEntity { 14 | @Column(name = "c_avatar_url") 15 | String avatarUrl; 16 | 17 | @Column(name = "c_ban_until") 18 | Date banUntil; 19 | 20 | @Column(name = "c_join_time", nullable = false) 21 | Date joinTime; 22 | 23 | @Column(name = "c_admin", nullable = false) 24 | Boolean admin; 25 | 26 | @Id 27 | @GeneratedValue(strategy = GenerationType.IDENTITY) 28 | @Column(name = "c_user_id") 29 | Long userId; 30 | 31 | @Column(name = "c_username", length = 32, nullable = false, unique = true) 32 | String username; 33 | 34 | @Column(name = "c_nickname", length = 64, nullable = false) 35 | String nickname; 36 | 37 | // todo: encrypt password 38 | @Column(name = "c_password") 39 | String password; 40 | 41 | @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) 42 | List socialList; 43 | 44 | @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) 45 | List notificationList; 46 | 47 | @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) 48 | List bulletinMsgList; 49 | 50 | @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) 51 | List commentList; 52 | 53 | @OneToMany(mappedBy = "sender", cascade = CascadeType.ALL) 54 | List chatMsgList; 55 | 56 | @ManyToMany 57 | @JoinTable(name = "t_relation_user_chat", 58 | joinColumns = @JoinColumn(name = "c_user_id"), 59 | inverseJoinColumns = @JoinColumn(name = "c_chat_id")) 60 | Set chatSessionList; 61 | 62 | @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) 63 | List tokenList; 64 | } 65 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/webController/api/Chat.java: -------------------------------------------------------------------------------- 1 | package webController.api; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.ChatMsg; 5 | import model.bean.ChatSession; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import service.ChatService; 11 | import webController.Utils; 12 | 13 | import java.util.List; 14 | 15 | @Slf4j 16 | @RestController 17 | public class Chat { 18 | 19 | private ChatService chatService; 20 | 21 | @Autowired 22 | public Chat(ChatService chatService) { 23 | this.chatService = chatService; 24 | } 25 | 26 | @RequestMapping(path = "/api/chat/startChatSession", method = RequestMethod.POST, produces = {"application/json"}) 27 | String startChatSession(String token, String username) { 28 | Long sessionId = chatService.startChatSession(token, username); 29 | return Utils.format(sessionId != null, sessionId); 30 | } 31 | 32 | @RequestMapping(path = "/api/chat/getChatSessions", method = RequestMethod.POST, produces = {"application/json"}) 33 | String getChatSessions(String token) { 34 | List sessions = chatService.getChatSessions(token); 35 | return Utils.format(sessions != null, sessions); 36 | } 37 | 38 | @RequestMapping(path = "/api/chat/sendMsg", method = RequestMethod.POST, produces = {"application/json"}) 39 | String sendMsg(String token, Long chatSessionId, String content) { 40 | Boolean res = chatService.sendMsg(token, chatSessionId, content); 41 | return Utils.format(res, null); 42 | } 43 | 44 | @RequestMapping(path = "/api/chat/getMsg", method = RequestMethod.POST, produces = {"application/json"}) 45 | String getMsg(String token, Long chatSessionId) { 46 | List msgs = chatService.getMsg(token, chatSessionId); 47 | return Utils.format(msgs != null, msgs); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/webController/api/Picture.java: -------------------------------------------------------------------------------- 1 | package webController.api; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.http.MediaType; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import org.springframework.web.multipart.MultipartFile; 11 | import service.PictureService; 12 | import webController.Utils; 13 | 14 | import java.io.IOException; 15 | 16 | @Slf4j 17 | @RestController 18 | public class Picture { 19 | private PictureService pictureService; 20 | 21 | @Autowired 22 | public Picture(PictureService pictureService) { 23 | this.pictureService = pictureService; 24 | } 25 | 26 | @RequestMapping(value = "/api/picture/upload", method = RequestMethod.POST, produces = {"application/json"}) 27 | public String storePic(MultipartFile pic) { 28 | if (pic == null || pic.isEmpty()) { 29 | log.warn("store picture but multipart file is empty"); 30 | return Utils.format(false, "file uploaded is empty"); 31 | } 32 | 33 | try { 34 | byte[] picBytes = pic.getBytes(); 35 | String picUid = pictureService.storePic(picBytes); 36 | log.info("picture '{}' stored.", picUid); 37 | return Utils.format(true, picUid); 38 | } catch (IOException e) { 39 | log.warn("IOException occurred: '{}'", e.toString()); 40 | return Utils.format(false, "Server internal error while upload picture"); 41 | } 42 | } 43 | 44 | @RequestMapping(value = "/api/picture/download") 45 | public ResponseEntity getPic(String picUid) { 46 | byte[] picByte = pictureService.getPic(picUid); 47 | if (picByte == null) { 48 | log.warn("no such pic '{}'", picUid); 49 | return ResponseEntity.badRequest().body(null); 50 | } 51 | 52 | log.info("picture '{}' gotten", picUid); 53 | return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(picByte); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /data_define.txt: -------------------------------------------------------------------------------- 1 | # 操作逻辑 2 | 3 | ## 用户 4 | 5 | - 注册(提供登陆用户名(不可修改)、昵称(可修改默认同用户名)、密码、联系方式(邮箱、手机号、社交工具(不提供验证)) 6 | - 登陆 7 | - 修改信息(头像、签名) 8 | - 查看记录(注册日期、历史发布、历时购买、历史总交易量) 9 | - 隐藏、删除历史记录 10 | - 封禁状态 11 | - **关注**用户 12 | - 通知(评论回复、产品评论) 13 | 14 | ### 发布者 15 | 16 | - 发布名称 17 | - 发布详情(可选) 18 | - 发布物品图片(可选) 19 | - 修改发布信息 20 | - 期望价格(可选) 21 | - 接受购买 22 | - 取消订购 23 | - 确认交易结束(发布方) 24 | - 接受私聊 25 | 26 | ### 购买者 27 | 28 | - 浏览社区(发布名称、发布详情简略、发布图片、发布人昵称、发布人头像) 29 | - 查看发布详情(名称、详情、发布人、**评论**) 30 | - 请求购买 31 | - 取消订购 32 | - 确认交易结束(购买方) 33 | - 发起私聊 34 | 35 | ## 管理员 36 | 37 | - 通过发布 38 | - 拒绝发布 39 | - 封禁用户 40 | - 浏览社区 41 | - 发起私聊 42 | - 发布**公告** 43 | 44 | ## 发布 45 | 46 | - 名称 47 | - 图片 48 | - 详情 49 | - 发布人 50 | - 购买人(可匿名) 51 | - 评论 52 | - 是否已审核 53 | - 历史修改记录 54 | 55 | # 系统逻辑 56 | 57 | ## 数据库 58 | 59 | **t_user** 60 | 61 | - user_id(primary key) 62 | - username(unique) 63 | - nickname 64 | - password 65 | - avatar_url 66 | - ban_until 67 | - join_time 68 | - admin 69 | 70 | **t_notification** 71 | 72 | - user_id(foreign key to t_user.user_id) 73 | - readed 74 | - notification_time 75 | - notification_type(translation_finished, comment_to_me, comment_to_product) 76 | - notification_dest(product_id, comment_id) 77 | 78 | **t_social** 79 | 80 | - user_id(foreign key to t_user) 81 | - social_method 82 | - social_url 83 | 84 | **t_bulletin_board** 85 | 86 | - publish_time 87 | - user_id(foreign key to t_user.user_id) 88 | - content 89 | 90 | **t_product** 91 | 92 | - owner(foreign key to t_user.user_id) 93 | - buyer(foreign key to t_user.user_id) 94 | - product_id(primary key) 95 | - product_status(censoring, selling, ordered, confirmed_seller, confirmed_buyer, withdrawn) 96 | - product_name 97 | - product_details 98 | - publish_time 99 | - expected_price(nullable) 100 | - clinsh_time 101 | - visualable_to_other 102 | - deleted 103 | 104 | **t_product_pics** 105 | 106 | - product_id(foreign key to t_product) 107 | - pic_url 108 | 109 | **t_comments** 110 | 111 | - comment_id 112 | - comment_time 113 | - reply_to(foreign key to t_comments.comment_id, nullable) 114 | - product_id(foreign key to t_product.product_id) 115 | - user_id(foreign key to t_user.user_id) 116 | 117 | 118 | **t_chat** 119 | 120 | - chat_id 121 | - chat_user_1 122 | - chat_user_2 123 | 124 | **t_chat_msg** 125 | 126 | - chat_msg_id 127 | - user_id 128 | - chat_msg_content 129 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package service; 2 | 3 | import model.bean.ProductComment; 4 | import model.bean.ProductDetail; 5 | import model.bean.ProductSummary; 6 | import org.springframework.lang.Nullable; 7 | 8 | import java.util.List; 9 | 10 | public interface ProductService { 11 | 12 | String PRODUCT_CENSORING = "censoring"; 13 | String PRODUCT_EDITING = "editing"; 14 | String PRODUCT_NOT_APPROVED = "not_approved"; 15 | String PRODUCT_SELLING = "selling"; 16 | String PRODUCT_ORDERED = "ordered"; 17 | String PRODUCT_CONFIRM_BUYER = "confirm_buyer"; 18 | String PRODUCT_CONFIRM_SELLER = "confirm_seller"; 19 | String PRODUCT_CLINCH = "clinch"; 20 | 21 | // sort by time, from new to old, only selling product 22 | List getProductList(); 23 | 24 | @Nullable 25 | List getBoughtProductList(String token); 26 | 27 | @Nullable 28 | List getMyProductList(String token); 29 | 30 | 31 | @Nullable 32 | ProductDetail getProductDetail(Long productId); 33 | 34 | // create product, status is editing. return productId 35 | @Nullable 36 | Long newProduct(String token); 37 | 38 | // delete product status if status is selling,censoring or not_approved 39 | Boolean deleteProduct(String token, Long productId); 40 | 41 | // switch product status to editing from selling,censoring,not_approved 42 | Boolean editProduct(String token, Long productId); 43 | 44 | // switch product status to censoring 45 | Boolean editFinish(String token, Long productId); 46 | 47 | Boolean editExpectedPrice(String token, Long productId, Double price); 48 | 49 | Boolean editProductName(String token, Long productId, String productName); 50 | 51 | Boolean editProductDetail(String token, Long productId, String productDetail); 52 | 53 | // add picture to product, return picture id 54 | @Nullable 55 | Long editAddPic(String token, Long productId, String picUrl); 56 | 57 | // drop picture from product. 58 | Boolean editDeletePic(String token, Long productId, Long picId); 59 | 60 | // // check owner ship of product 61 | // Boolean modifyProduct(String token, ProductDetail product); 62 | 63 | Boolean orderProduct(String token, Long productId); 64 | 65 | Boolean cancelOrder(String token, Long productId); 66 | 67 | // verify owner and buyer in method 68 | Boolean confirmOrder(String token , Long productId); 69 | 70 | 71 | Boolean comment(String token, Long productId, String content); 72 | 73 | @Nullable 74 | List getComments(Long productId); 75 | } 76 | -------------------------------------------------------------------------------- /flea_market_project/src/test/java/application/test/AdminServiceTest.java: -------------------------------------------------------------------------------- 1 | package application.test; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.UserDetail; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | import service.AdminService; 11 | import service.UserService; 12 | 13 | import java.util.Date; 14 | 15 | @Slf4j 16 | @RunWith(SpringRunner.class) 17 | @SpringBootTest 18 | public class AdminServiceTest { 19 | private UserService userService; 20 | private AdminService adminService; 21 | 22 | @Autowired 23 | public void setUserService(UserService userService) { 24 | this.userService = userService; 25 | } 26 | 27 | @Autowired 28 | public void setAdminService(AdminService adminService) { 29 | this.adminService = adminService; 30 | } 31 | 32 | @Test 33 | public void grantTest() { 34 | userService.register("user2grant", "user2grant", "password"); 35 | String adminToken = userService.authorize("initAdmin", "initAdmin"); 36 | assert adminToken != null; 37 | 38 | UserDetail userDetailOld = userService.getUserDetail("user2grant"); 39 | assert userDetailOld != null; 40 | assert !userDetailOld.getAdmin(); 41 | 42 | assert adminService.grantUser(adminToken, "user2grant"); 43 | 44 | UserDetail userDetail = userService.getUserDetail("user2grant"); 45 | assert userDetail != null; 46 | assert userDetail.getAdmin(); 47 | } 48 | 49 | @Test 50 | public void banTest() { 51 | userService.register("user2ban", "user2ban", "password"); 52 | String userToken = userService.authorize("user2ban", "password"); 53 | String adminToken = userService.authorize("initAdmin", "initAdmin"); 54 | assert userToken != null; 55 | assert adminToken != null; 56 | 57 | UserDetail userDetailOld = userService.getUserDetail("user2ban"); 58 | assert userDetailOld != null; 59 | assert !userDetailOld.getBanUntil().after(new Date()); 60 | 61 | assert adminService.banUser(adminToken, "user2ban", 3); 62 | 63 | UserDetail userDetail = userService.getUserDetail("user2ban"); 64 | assert userDetail != null; 65 | assert userDetail.getBanUntil().after(new Date()); 66 | 67 | assert userService.authorize("user2ban", "password") == null; 68 | assert !userService.modifyAvatar(userToken, "update avatar after banned"); 69 | } 70 | 71 | // todo: test product part 72 | 73 | } 74 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/webController/api/Admin.java: -------------------------------------------------------------------------------- 1 | package webController.api; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.ProductSummary; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import service.AdminService; 10 | import webController.Utils; 11 | 12 | import java.util.List; 13 | 14 | @Slf4j 15 | @RestController 16 | public class Admin { 17 | 18 | private AdminService adminService; 19 | 20 | @Autowired 21 | public Admin(AdminService adminService) { 22 | this.adminService = adminService; 23 | } 24 | 25 | // Boolean grantUser(String token, String username); 26 | 27 | @RequestMapping(path = "/api/admin/grantUser", method = RequestMethod.POST, produces = {"application/json"}) 28 | String grantUser(String token, String username) { 29 | Boolean res = adminService.grantUser(token, username); 30 | return Utils.format(res, null); 31 | } 32 | 33 | // Boolean banUser(String token, String username, Integer day); 34 | @RequestMapping(path = "/api/admin/banUser", method = RequestMethod.POST, produces = {"application/json"}) 35 | String banUser(String token, String username, Integer day) { 36 | Boolean res = adminService.banUser(token, username, day); 37 | return Utils.format(res, null); 38 | } 39 | 40 | // @Nullable 41 | // List getCensoringProducts(String token); 42 | 43 | // todo: test 44 | @RequestMapping(path = "/api/admin/getCensoringProducts", method = RequestMethod.POST, produces = {"application/json"}) 45 | String getCensoringProducts(String token) { 46 | List products = adminService.getCensoringProducts(token); 47 | return Utils.format(products != null, products); 48 | } 49 | 50 | // Boolean censorProduct(String token, Long productId, Boolean pass); 51 | 52 | @RequestMapping(path = "/api/admin/censorProduct", method = RequestMethod.POST, produces = {"application/json"}) 53 | String censorProduct(String token, Long productId, Boolean pass) { 54 | Boolean res = adminService.censorProduct(token, productId, pass); 55 | return Utils.format(res, null); 56 | } 57 | 58 | // Boolean publishBulletin(String token, String bulletinMsg); 59 | 60 | @RequestMapping(path = "/api/admin/publishBulletin", method = RequestMethod.POST, produces = {"application/json"}) 61 | String publishBulletin(String token, String bulletinMsg) { 62 | Boolean res = adminService.publishBulletin(token, bulletinMsg); 63 | return Utils.format(res, null); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /flea_market_project/src/test/java/application/test/ChatServiceTest.java: -------------------------------------------------------------------------------- 1 | package application.test; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.ChatMsg; 5 | import model.bean.ChatSession; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | import service.ChatService; 12 | import service.UserService; 13 | 14 | import java.util.List; 15 | 16 | @Slf4j 17 | @SpringBootTest 18 | @RunWith(SpringRunner.class) 19 | public class ChatServiceTest { 20 | private UserService userService; 21 | private ChatService chatService; 22 | 23 | @Autowired 24 | public void setUserService(UserService userService) { 25 | this.userService = userService; 26 | } 27 | 28 | @Autowired 29 | public void setChatService(ChatService chatService) { 30 | this.chatService = chatService; 31 | } 32 | 33 | @Test 34 | public void testChat() { 35 | userService.register("userChat1", "userChat1", "password"); 36 | userService.register("userChat2", "userChat2", "password"); 37 | String token1 = userService.authorize("userChat1", "password"); 38 | String token2 = userService.authorize("userChat2", "password"); 39 | 40 | Long chatSessionId = chatService.startChatSession(token1, "userChat2"); 41 | assert chatService.sendMsg(token1, chatSessionId, "PING"); 42 | 43 | List chatSessionList2 = chatService.getChatSessions(token2); 44 | 45 | assert chatSessionList2 != null; 46 | assert chatSessionList2.size() == 1; 47 | 48 | assert chatService.sendMsg(token2, chatSessionList2.get(0).getChatSessionId(), "PONG"); 49 | 50 | List chatSessionList1 = chatService.getChatSessions(token1); 51 | 52 | assert chatSessionList1 != null; 53 | assert chatSessionList1.size() == 1; 54 | 55 | List chatMsgList1 = chatService.getMsg(token1, chatSessionList1.get(0).getChatSessionId()); 56 | assert chatMsgList1 != null; 57 | assert chatMsgList1.size() == 2; 58 | 59 | assert chatMsgList1.get(0).getContent().equals("PING"); 60 | assert chatMsgList1.get(1).getContent().equals("PONG"); 61 | 62 | List chatMsgList2 = chatService.getMsg(token2, chatSessionList2.get(0).getChatSessionId()); 63 | assert chatMsgList2 != null; 64 | assert chatMsgList2.size() == 2; 65 | 66 | assert chatMsgList2.get(0).getContent().equals("PING"); 67 | assert chatMsgList2.get(1).getContent().equals("PONG"); 68 | 69 | ChatMsg msg10 = chatMsgList1.get(0); 70 | ChatMsg msg11 = chatMsgList1.get(1); 71 | 72 | ChatMsg msg20 = chatMsgList2.get(0); 73 | ChatMsg msg21 = chatMsgList2.get(1); 74 | 75 | assert msg10.equals(msg20); 76 | assert msg11.equals(msg21); 77 | 78 | assert msg10.getSender().equals(msg20.getSender()); 79 | assert msg11.getSender().equals(msg21.getSender()); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /flea_market_project/src/test/java/application/test/UserServiceTest.java: -------------------------------------------------------------------------------- 1 | package application.test; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.UserDetail; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | import service.UserService; 11 | 12 | @Slf4j 13 | @SpringBootTest 14 | @RunWith(SpringRunner.class) 15 | public class UserServiceTest { 16 | private UserService userService; 17 | 18 | @Autowired 19 | public void setUserService(UserService userService) { 20 | this.userService = userService; 21 | } 22 | 23 | @Test 24 | public void testRegisterAndLogin() { 25 | String username = "testUser"; 26 | String password = "testPassword"; 27 | String nickname = "testNickname"; 28 | 29 | String newNickname = "newNickname"; 30 | String newPassword = "newPassword"; 31 | 32 | 33 | assert userService.register(username, nickname, password); 34 | assert userService.authorize(username, password + "1234") == null; 35 | 36 | String token = userService.authorize(username, password); 37 | log.info("token get: {}", token); 38 | assert token != null; 39 | 40 | UserDetail userDetailInit = userService.getMyDetail(token); 41 | assert userDetailInit != null; 42 | assert userDetailInit.getNickname().equals(nickname); 43 | assert userDetailInit.getUsername().equals(username); 44 | 45 | assert userService.modifyNickname(token, newNickname); 46 | assert userService.modifyPassword(token, newPassword); 47 | 48 | UserDetail userDetailNew = userService.getMyDetail(token); 49 | assert userDetailNew != null; 50 | assert userDetailNew.getNickname().equals(newNickname); 51 | 52 | assert userService.logout(token); 53 | assert !userService.modifyNickname(token, "anotherNickname"); 54 | 55 | String newToken = userService.authorize(username, newPassword); 56 | log.info("new token get: {}", newToken); 57 | 58 | Long socialId = userService.addSocial(newToken, "testSocialType", "social://testUrl"); 59 | 60 | UserDetail myDetail = userService.getMyDetail(newToken); 61 | UserDetail userDetail = userService.getUserDetail(username); 62 | assert myDetail != null; 63 | assert userDetail != null; 64 | assert myDetail.equals(userDetail); 65 | 66 | assert myDetail.getSocialList().size() == 1; 67 | assert myDetail.getSocialList().get(0).getSocialType().equals("testSocialType"); 68 | assert myDetail.getSocialList().get(0).getSocialUrl().equals("social://testUrl"); 69 | 70 | assert socialId != null; 71 | assert userService.removeSocial(newToken, socialId); 72 | assert userService.modifyAvatar(newToken, "new avatarUrl"); 73 | 74 | UserDetail myDetailRemoveSocial = userService.getMyDetail(newToken); 75 | assert myDetailRemoveSocial != null; 76 | assert myDetailRemoveSocial.getSocialList().size() == 0; 77 | assert myDetailRemoveSocial.getAvatarUrl().equals("new avatarUrl"); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/webController/api/User.java: -------------------------------------------------------------------------------- 1 | package webController.api; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.UserDetail; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import service.UserService; 10 | import webController.Utils; 11 | 12 | @Slf4j 13 | @RestController 14 | public class User { 15 | private UserService userService; 16 | 17 | @Autowired 18 | public User(UserService userService) { 19 | this.userService = userService; 20 | } 21 | 22 | @RequestMapping(value = "/api/user/register", method = RequestMethod.POST, produces = {"application/json"}) 23 | String register(String username, String nickname, String password) { 24 | Boolean res = userService.register(username, nickname, password); 25 | return Utils.format(res, null); 26 | } 27 | 28 | @RequestMapping(value = "/api/user/authorize", method = RequestMethod.POST, produces = {"application/json"}) 29 | String authorize(String username, String password) { 30 | String token = userService.authorize(username, password); 31 | return Utils.format(token != null, token); 32 | } 33 | 34 | @RequestMapping(value = "/api/user/logout", method = RequestMethod.POST, produces = {"application/json"}) 35 | String logout(String token) { 36 | Boolean res = userService.logout(token); 37 | return Utils.format(res, null); 38 | } 39 | 40 | @RequestMapping(value = "/api/user/modifyPassword", method = RequestMethod.POST, produces = {"application/json"}) 41 | String modifyPassword(String token, String password) { 42 | Boolean res = userService.modifyPassword(token, password); 43 | return Utils.format(res, null); 44 | } 45 | 46 | @RequestMapping(value = "/api/user/modifyNickname", method = RequestMethod.POST, produces = {"application/json"}) 47 | String modifyNickname(String token, String nickname) { 48 | Boolean res = userService.modifyNickname(token, nickname); 49 | return Utils.format(res, null); 50 | } 51 | 52 | @RequestMapping(value = "/api/user/modifyAvatar", method = RequestMethod.POST, produces = {"application/json"}) 53 | String modifyAvatar(String token, String avatarUrl) { 54 | Boolean res = userService.modifyAvatar(token, avatarUrl); 55 | return Utils.format(res, null); 56 | } 57 | 58 | @RequestMapping(value = "/api/user/addSocial", method = RequestMethod.POST, produces = {"application/json"}) 59 | String addSocial(String token, String socialType, String socialUrl) { 60 | Long id = userService.addSocial(token, socialType, socialUrl); 61 | return Utils.format(id != null, String.valueOf(id)); 62 | } 63 | 64 | @RequestMapping(value = "/api/user/removeSocial", method = RequestMethod.POST, produces = {"application/json"}) 65 | String removeSocial(String token, Long socialId) { 66 | log.info("debug: token='{}'", token); 67 | Boolean res = userService.removeSocial(token, socialId); 68 | return Utils.format(res, null); 69 | } 70 | 71 | @RequestMapping(value = "/api/user/getMyDetail", method = RequestMethod.POST, produces = {"application/json"}) 72 | String getMyDetail(String token) { 73 | UserDetail detail = userService.getMyDetail(token); 74 | 75 | return Utils.format(detail != null, detail); 76 | } 77 | 78 | @RequestMapping(value = "/api/user/getUserDetail", produces = {"application/json"}) 79 | String getUserDetail(String username) { 80 | UserDetail detail = userService.getUserDetail(username); 81 | 82 | return Utils.format(detail != null, detail); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /flea_market_project/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.springframework.boot 9 | spring-boot-starter-parent 10 | 2.2.6.RELEASE 11 | 12 | 13 | org.example 14 | flea_market 15 | 1.0-SNAPSHOT 16 | 17 | 18 | 13 19 | 13 20 | UTF-8 21 | UTF-8 22 | application.MainApplication 23 | 24 | 25 | war 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-maven-plugin 32 | 33 | application.MainApplication 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-web 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-thymeleaf 48 | 49 | 50 | 51 | org.projectlombok 52 | lombok 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-starter-test 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-starter-data-jpa 63 | 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-starter-data-redis 68 | 69 | 70 | io.lettuce 71 | lettuce-core 72 | 73 | 74 | 75 | 76 | 77 | org.mariadb.jdbc 78 | mariadb-java-client 79 | 80 | 81 | 82 | com.h2database 83 | h2 84 | 85 | 86 | 87 | 88 | com.google.code.findbugs 89 | jsr305 90 | 3.0.2 91 | 92 | 93 | 94 | 95 | commons-io 96 | commons-io 97 | 2.6 98 | 99 | 100 | 101 | redis.clients 102 | jedis 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/impl/SystemServiceImpl.java: -------------------------------------------------------------------------------- 1 | package service.impl; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.dao.entity.TokenEntity; 5 | import model.dao.entity.UserEntity; 6 | import model.dao.repo.TokenRepo; 7 | import model.dao.repo.UserRepo; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.lang.Nullable; 10 | import org.springframework.stereotype.Service; 11 | import service.SystemService; 12 | 13 | import java.util.*; 14 | 15 | @Slf4j 16 | @Service 17 | public class SystemServiceImpl implements SystemService { 18 | private TokenRepo tokenRepo; 19 | private UserRepo userRepo; 20 | 21 | @Autowired 22 | public SystemServiceImpl(TokenRepo tokenRepo, UserRepo userRepo) { 23 | this.tokenRepo = tokenRepo; 24 | this.userRepo = userRepo; 25 | } 26 | 27 | @Nullable 28 | @Override 29 | public UserEntity token2User(String token) { 30 | List tokenList = tokenRepo.findByTokenEquals(token); 31 | if (! tokenList.isEmpty()) { 32 | if (tokenList.get(0).getExpireTime().after(new Date())) { 33 | UserEntity user = tokenList.get(0).getUser(); 34 | if (user.getBanUntil().after(new Date())) { 35 | log.warn("user '{}' has been banned until '{}'", user.getUsername(), user.getBanUntil()); 36 | return null; 37 | } else { 38 | log.info("token2User: get user '{}' from token '{}'", user.getUsername(), token); 39 | return tokenList.get(0).getUser(); 40 | } 41 | } else { 42 | log.warn("token2User: such token is expired: '{}'", token); 43 | return null; 44 | } 45 | } else { 46 | log.warn("token2User: no such token: '{}'", token); 47 | return null; 48 | } 49 | } 50 | 51 | // create token for user 52 | @Nullable 53 | @Override 54 | public String authorizeToken(Long userId) { 55 | Optional user = userRepo.findById(userId); 56 | if (user.isPresent()) { 57 | TokenEntity token = new TokenEntity(); 58 | token.setToken(UUID.randomUUID().toString()); 59 | 60 | token.setUser(user.get()); 61 | 62 | Calendar calendar = Calendar.getInstance(); 63 | calendar.add(Calendar.DATE, 7); 64 | token.setExpireTime(calendar.getTime()); 65 | 66 | token = tokenRepo.save(token); 67 | 68 | log.debug("authorized token: id='{}' username='{}' expire_time='{}' token='{}'", 69 | token.getTokenId(), token.getUser().getUsername(), token.getExpireTime(), token.getToken()); 70 | log.info("authorized token for user '{}'", user.get().getUsername()); 71 | 72 | return token.getToken(); 73 | } else { 74 | log.error("authorized token failed: userId not found: '{}'", userId); 75 | return null; 76 | } 77 | } 78 | 79 | @Override 80 | public Boolean invokeToken(String token) { 81 | List tokenList = tokenRepo.findByTokenEquals(token); 82 | if (! tokenList.isEmpty()) { 83 | TokenEntity tokenEntity = tokenList.get(0); 84 | tokenRepo.delete(tokenEntity); 85 | 86 | log.debug("invoke token: tokenId='{}' token='{}' expireTime='{}'", 87 | tokenEntity.getTokenId(), tokenEntity.getToken(), tokenEntity.getExpireTime()); 88 | 89 | return true; 90 | } else { 91 | log.warn("invoke token failed: token not found: '{}'", token); 92 | return false; 93 | } 94 | } 95 | 96 | // used for be the object to be operated. 97 | @Nullable 98 | @Override 99 | public UserEntity findUserByUsername(String username) { 100 | List userList = userRepo.findByUsernameEquals(username); 101 | if (userList.isEmpty()) { 102 | return null; 103 | } else { 104 | return userList.get(0); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/impl/AdminServiceImpl.java: -------------------------------------------------------------------------------- 1 | package service.impl; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.ProductSummary; 5 | import model.dao.entity.BulletinMsgEntity; 6 | import model.dao.entity.ProductEntity; 7 | import model.dao.entity.UserEntity; 8 | import model.dao.repo.BulletinMsgRepo; 9 | import model.dao.repo.ProductRepo; 10 | import model.dao.repo.UserRepo; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.lang.Nullable; 13 | import org.springframework.stereotype.Service; 14 | import service.AdminService; 15 | import service.ProductService; 16 | import service.SystemService; 17 | 18 | import java.util.*; 19 | 20 | @Slf4j 21 | @Service 22 | public class AdminServiceImpl implements AdminService { 23 | private SystemService systemService; 24 | private UserRepo userRepo; 25 | private ProductRepo productRepo; 26 | private BulletinMsgRepo bulletinMsgRepo; 27 | 28 | @Autowired 29 | public AdminServiceImpl(SystemService systemService, UserRepo userRepo, 30 | ProductRepo productRepo, BulletinMsgRepo bulletinMsgRepo) { 31 | this.systemService = systemService; 32 | this.userRepo = userRepo; 33 | this.productRepo = productRepo; 34 | this.bulletinMsgRepo = bulletinMsgRepo; 35 | } 36 | 37 | @Nullable 38 | private UserEntity validateAdmin(String token) { 39 | UserEntity user = systemService.token2User(token); 40 | if (user == null) { 41 | log.warn("invalided token '{}'", token); 42 | return null; 43 | } else { 44 | if (user.getAdmin()) { 45 | log.info("user '{}' admin validate pass", user.getUsername()); 46 | return user; 47 | } else { 48 | log.warn("user '{}' not admin", user.getUsername()); 49 | return null; 50 | } 51 | } 52 | } 53 | 54 | 55 | @Override 56 | public Boolean grantUser(String token, String username) { 57 | UserEntity admin = validateAdmin(token); 58 | if (admin == null) { 59 | log.warn("grant failed, invalid token or user is not admin"); 60 | return false; 61 | } else { 62 | UserEntity user = systemService.findUserByUsername(username); 63 | if (user == null) { 64 | log.warn("no such user: '{}'", username); 65 | return false; 66 | } else { 67 | if (user.getAdmin()) { 68 | log.warn("user '{}' is admin already", username); 69 | return false; 70 | } else { 71 | user.setAdmin(true); 72 | userRepo.save(user); 73 | log.info("user '{}' grant admin to user '{}'", admin.getUsername(), username); 74 | return true; 75 | } 76 | } 77 | } 78 | } 79 | 80 | @Override 81 | public Boolean banUser(String token, String username, Integer day) { 82 | UserEntity admin = validateAdmin(token); 83 | if (admin == null) { 84 | log.warn("ban failed, invalid token or user is not admin"); 85 | return false; 86 | } else { 87 | UserEntity user = systemService.findUserByUsername(username); 88 | if (user == null) { 89 | log.warn("no such user '{}'", username); 90 | return false; 91 | } else { 92 | Calendar calendar = Calendar.getInstance(); 93 | calendar.setTime(new Date()); 94 | calendar.add(Calendar.DATE, day); 95 | 96 | user.setBanUntil(calendar.getTime()); 97 | userRepo.save(user); 98 | 99 | log.info("admin '{}' banned user '{}' for '{}' days.", admin.getUsername(), username, day); 100 | return true; 101 | } 102 | } 103 | } 104 | 105 | @Nullable 106 | @Override 107 | public List getCensoringProducts(String token) { 108 | UserEntity admin = validateAdmin(token); 109 | if (admin == null) { 110 | log.warn("get failed, invalid token or user is not admin"); 111 | return null; 112 | } else { 113 | List productEntityList = 114 | productRepo.findByProductStatusEquals(ProductService.PRODUCT_CENSORING, productRepo.sortByReleaseDesc); 115 | List productSummaryList = new ArrayList<>(productEntityList.size()); 116 | for (ProductEntity productEntity : productEntityList) { 117 | productSummaryList.add(new ProductSummary(productEntity)); 118 | } 119 | log.info("admin '{}' get '{}' censoring products", admin.getUsername(), productSummaryList.size()); 120 | return productSummaryList; 121 | } 122 | } 123 | 124 | @Override 125 | public Boolean censorProduct(String token, Long productId, Boolean pass) { 126 | UserEntity admin = validateAdmin(token); 127 | if (admin == null) { 128 | log.warn("censor failed, invalid token or user is not admin"); 129 | return false; 130 | } else { 131 | Optional productOpt = productRepo.findById(productId); 132 | if (productOpt.isPresent()) { 133 | ProductEntity product = productOpt.get(); 134 | if (pass) { 135 | product.setProductStatus(ProductService.PRODUCT_SELLING); 136 | } else { 137 | product.setProductStatus(ProductService.PRODUCT_NOT_APPROVED); 138 | } 139 | productRepo.save(product); 140 | log.info("admin '{}' censor product '{}' pass as '{}'", admin.getUsername(), productId, pass); 141 | return true; 142 | } else { 143 | log.warn("no such product '{}'", productId); 144 | return false; 145 | } 146 | } 147 | } 148 | 149 | @Override 150 | public Boolean publishBulletin(String token, String bulletinContent) { 151 | UserEntity admin = validateAdmin(token); 152 | if (admin == null) { 153 | log.warn("publish bulletin failed, invalid token or user is not admin"); 154 | return false; 155 | } else { 156 | BulletinMsgEntity bulletinMsg = new BulletinMsgEntity(); 157 | bulletinMsg.setContent(bulletinContent); 158 | bulletinMsg.setPublishTime(new Date()); 159 | bulletinMsg.setUser(admin); 160 | bulletinMsgRepo.save(bulletinMsg); 161 | log.info("admin '{}' publish bulletin: '{}'", admin.getUsername(), bulletinContent); 162 | return true; 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/impl/ChatServiceImpl.java: -------------------------------------------------------------------------------- 1 | package service.impl; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.ChatMsg; 5 | import model.bean.ChatSession; 6 | import model.dao.entity.ChatMsgEntity; 7 | import model.dao.entity.ChatSessionEntity; 8 | import model.dao.entity.UserEntity; 9 | import model.dao.repo.ChatMsgRepo; 10 | import model.dao.repo.ChatRepo; 11 | import model.dao.repo.UserRepo; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.lang.Nullable; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.transaction.annotation.Transactional; 16 | import service.ChatService; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Date; 20 | import java.util.List; 21 | import java.util.Optional; 22 | 23 | @Slf4j 24 | @Service 25 | public class ChatServiceImpl implements ChatService { 26 | private SystemServiceImpl systemService; 27 | private UserRepo userRepo; 28 | private ChatRepo chatRepo; 29 | private ChatMsgRepo chatMsgRepo; 30 | 31 | @Autowired 32 | public ChatServiceImpl(SystemServiceImpl systemService, UserRepo userRepo, 33 | ChatRepo chatRepo, ChatMsgRepo chatMsgRepo) { 34 | this.systemService = systemService; 35 | this.userRepo = userRepo; 36 | this.chatRepo = chatRepo; 37 | this.chatMsgRepo = chatMsgRepo; 38 | } 39 | 40 | @Override 41 | @Nullable 42 | @Transactional 43 | public Long startChatSession(String token, String username) { 44 | UserEntity user = systemService.token2User(token); 45 | UserEntity targetUser = systemService.findUserByUsername(username); 46 | if (user == null || targetUser == null) { 47 | log.warn("invalid token '{}' or not exist username '{}'", token, username); 48 | return null; 49 | } else { 50 | List chatList = chatRepo.findByChatMember(user, targetUser); 51 | if (chatList.size() > 0) { 52 | Long chatId = chatList.get(0).getChatSessionId(); 53 | log.info("use exist chat '{}' for user '{}' and '{}'", chatId, user.getUsername(), username); 54 | return chatId; 55 | } else { 56 | ChatSessionEntity chat = new ChatSessionEntity(); 57 | 58 | user.getChatSessionList().add(chat); 59 | chat.getUserList().add(user); 60 | targetUser.getChatSessionList().add(chat); 61 | chat.getUserList().add(targetUser); 62 | 63 | chat = chatRepo.save(chat); 64 | userRepo.save(user); 65 | userRepo.save(targetUser); 66 | 67 | log.info("create new chat '{}' for user '{}' and '{}'", 68 | chat.getChatSessionId(), user.getUsername(), username); 69 | return chat.getChatSessionId(); 70 | } 71 | } 72 | } 73 | 74 | @Override 75 | @Nullable 76 | public List getChatSessions(String token) { 77 | UserEntity user = systemService.token2User(token); 78 | if (user == null) { 79 | log.warn("invalid or expired token: '{}'", token); 80 | return null; 81 | } else { 82 | List chatList = chatRepo.findByChatMember(user); 83 | List chatSessionList = new ArrayList<>(chatList.size()); 84 | for (ChatSessionEntity chatSessionEntity : chatList) { 85 | chatSessionList.add(new ChatSession(chatSessionEntity)); 86 | } 87 | log.info("user '{}' get '{}' chat session", user.getUsername(), chatSessionList.size()); 88 | return chatSessionList; 89 | } 90 | } 91 | 92 | @Override 93 | @Transactional 94 | public Boolean sendMsg(String token, Long chatSessionId, String content) { 95 | UserEntity user = systemService.token2User(token); 96 | if (user == null) { 97 | log.warn("invalid or expired token: '{}'", token); 98 | return null; 99 | } else { 100 | Optional chatEntityOpt = chatRepo.findById(chatSessionId); 101 | if (chatEntityOpt.isPresent()) { 102 | ChatSessionEntity chat = chatEntityOpt.get(); 103 | if (chat.getUserList().contains(user)) { 104 | ChatMsgEntity chatMsg = new ChatMsgEntity(); 105 | chatMsg.setChatSession(chat); 106 | chatMsg.setMessageTime(new Date()); 107 | chatMsg.setSender(user); 108 | chatMsg.setContent(content); 109 | chatMsg = chatMsgRepo.save(chatMsg); 110 | log.info("user '{}' send message '{}' in chat session '{}'", 111 | user.getUsername(), chatMsg.getContent(), chatSessionId); 112 | return true; 113 | } else { 114 | log.warn("user '{}' want to send message in a not related chat session '{}'", 115 | user.getUsername(), chatSessionId); 116 | return false; 117 | } 118 | } else { 119 | log.warn("user '{}' want to send message in not exist chat session '{}'", 120 | user.getUsername(), chatSessionId); 121 | return false; 122 | } 123 | } 124 | } 125 | 126 | @Override 127 | @Nullable 128 | @Transactional 129 | public List getMsg(String token, Long chatSessionId) { 130 | UserEntity user = systemService.token2User(token); 131 | if (user == null) { 132 | log.warn("invalid or expired token: '{}'", token); 133 | return null; 134 | } else { 135 | Optional chatEntityOpt = chatRepo.findById(chatSessionId); 136 | if (chatEntityOpt.isPresent()) { 137 | ChatSessionEntity chat = chatEntityOpt.get(); 138 | if (chat.getUserList().contains(user)) { 139 | List chatMsgEntityList = chatMsgRepo.findByChatSessionEquals(chat); 140 | List chatMsgList = new ArrayList<>(chatMsgEntityList.size()); 141 | for (ChatMsgEntity chatMsgEntity : chatMsgEntityList) { 142 | chatMsgList.add(new ChatMsg(chatMsgEntity)); 143 | } 144 | log.info("user '{}' get '{}' message(s) from chat session '{}'", 145 | user.getUsername(), chatMsgList.size(), chatSessionId); 146 | return chatMsgList; 147 | } else { 148 | log.warn("user '{}' want to get message in a not related chat session '{}'", 149 | user.getUsername(), chatSessionId); 150 | return null; 151 | } 152 | } else { 153 | log.warn("user '{}' want to get message in not exist chat session '{}'", 154 | user.getUsername(), chatSessionId); 155 | return null; 156 | } 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package service.impl; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.UserDetail; 5 | import model.dao.entity.SocialEntity; 6 | import model.dao.entity.UserEntity; 7 | import model.dao.repo.SocialRepo; 8 | import model.dao.repo.UserRepo; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.lang.Nullable; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Transactional; 13 | import service.SystemService; 14 | import service.UserService; 15 | 16 | import java.util.Date; 17 | import java.util.Optional; 18 | 19 | @Slf4j 20 | @Service 21 | public class UserServiceImpl implements UserService { 22 | private SystemService systemService; 23 | private UserRepo userRepo; 24 | private SocialRepo socialRepo; 25 | 26 | @Autowired 27 | public UserServiceImpl(SystemService systemService, UserRepo userRepo, SocialRepo socialRepo) { 28 | this.systemService = systemService; 29 | this.userRepo = userRepo; 30 | this.socialRepo = socialRepo; 31 | } 32 | 33 | @Override 34 | public Boolean register(String username, String nickname, String password) { 35 | UserEntity user = new UserEntity(); 36 | user.setBanUntil(new Date(0)); 37 | user.setAdmin(false); 38 | user.setAvatarUrl(""); 39 | user.setJoinTime(new Date()); 40 | user.setNickname(nickname); 41 | user.setUsername(username); 42 | user.setPassword(password); 43 | 44 | user = userRepo.save(user); 45 | log.debug("new user: userId='{}' username='{}' nickname='{}'", user.getUserId(), username, nickname); 46 | return true; 47 | } 48 | 49 | @Nullable 50 | @Override 51 | public String authorize(String username, String password) { 52 | UserEntity user = systemService.findUserByUsername(username); 53 | if (user == null) { 54 | log.warn("no such user '{}'", username); 55 | return null; 56 | } else { 57 | if (user.getPassword().equals(password)) { 58 | if (user.getBanUntil().after(new Date())) { 59 | log.warn("user '{}' has been banned until '{}'", username, user.getBanUntil()); 60 | return null; 61 | } else { 62 | String token = systemService.authorizeToken(user.getUserId()); 63 | log.info("user '{}' log in.", username); 64 | return token; 65 | } 66 | } else { 67 | log.warn("user '{}' identify failed.", username); 68 | return null; 69 | } 70 | } 71 | } 72 | 73 | @Override 74 | public Boolean logout(String token) { 75 | Boolean invoke = systemService.invokeToken(token); 76 | log.info("user who use token '{}' logout.", token); 77 | return invoke; 78 | } 79 | 80 | @Override 81 | public Boolean modifyPassword(String token, String password) { 82 | UserEntity user = systemService.token2User(token); 83 | if (user == null) { 84 | log.warn("invalid or expired token '{}'", token); 85 | return false; 86 | } else { 87 | user.setPassword(password); 88 | userRepo.save(user); 89 | log.info("user '{}' modified password.", user.getUsername()); 90 | return true; 91 | } 92 | } 93 | 94 | @Override 95 | public Boolean modifyNickname(String token, String nickname) { 96 | UserEntity user = systemService.token2User(token); 97 | if (user == null) { 98 | log.warn("invalid or expired token '{}'", token); 99 | return false; 100 | } else { 101 | user.setNickname(nickname); 102 | userRepo.save(user); 103 | log.info("user '{}' modified nickname to '{}'.", user.getUsername(), nickname); 104 | return true; 105 | } 106 | } 107 | 108 | @Override 109 | public Boolean modifyAvatar(String token, String avatarUrl) { 110 | UserEntity user = systemService.token2User(token); 111 | if (user == null) { 112 | log.warn("invalid or expired token '{}'", token); 113 | return false; 114 | } else { 115 | user.setAvatarUrl(avatarUrl); 116 | userRepo.save(user); 117 | log.info("user '{}' modified avatarUrl to '{}'.", user.getUsername(), avatarUrl); 118 | return true; 119 | } 120 | } 121 | 122 | @Override 123 | @Nullable 124 | public Long addSocial(String token, String socialType, String socialUrl) { 125 | UserEntity user = systemService.token2User(token); 126 | if (user == null) { 127 | log.warn("invalid or expired token '{}'", token); 128 | return null; 129 | } else { 130 | SocialEntity social = new SocialEntity(); 131 | social.setSocialType(socialType); 132 | social.setSocialUrl(socialUrl); 133 | social.setUser(user); 134 | social = socialRepo.save(social); 135 | log.info("new social: socialId='{}' username='{}' socialType='{}' socialUrl='{}'", 136 | social.getSocialId(), social.getUser().getUsername(), 137 | social.getSocialType(), social.getSocialUrl()); 138 | return social.getSocialId(); 139 | } 140 | } 141 | 142 | @Override 143 | public Boolean removeSocial(String token, Long socialId) { 144 | UserEntity user = systemService.token2User(token); 145 | if (user == null) { 146 | log.warn("invalid or expired token '{}'", token); 147 | return false; 148 | } else { 149 | Optional socialOpt = socialRepo.findById(socialId); 150 | if (socialOpt.isPresent()) { 151 | SocialEntity social = socialOpt.get(); 152 | // if (social.getUser().equals(user)) { 153 | if (social.getUser().getUserId().equals(user.getUserId())) { 154 | socialRepo.deleteById(socialId); 155 | log.info("user '{}' delete social '{}'", user.getUsername(), socialId); 156 | return true; 157 | } else { 158 | log.warn("user '{}' delete social '{}' which not related to him(her)", 159 | user.getUsername(), socialId); 160 | return false; 161 | } 162 | } else { 163 | log.warn("user '{}' delete social '{}' which not existed", 164 | user.getUsername(), socialId); 165 | return false; 166 | } 167 | } 168 | } 169 | 170 | @Override 171 | @Nullable 172 | @Transactional 173 | public UserDetail getMyDetail(String token) { 174 | UserEntity user = systemService.token2User(token); 175 | if (user == null) { 176 | log.warn("invalid or expired token '{}'", token); 177 | return null; 178 | } else { 179 | log.info("user '{}' get his(her) detail information", user.getUsername()); 180 | return new UserDetail(user); 181 | } 182 | } 183 | 184 | @Override 185 | @Nullable 186 | @Transactional 187 | public UserDetail getUserDetail(String username) { 188 | UserEntity user = systemService.findUserByUsername(username); 189 | if (user == null) { 190 | log.warn("nonexistent username '{}'", username); 191 | return null; 192 | } else { 193 | log.info("user '{}' get his(her) detail information", user.getUsername()); 194 | return new UserDetail(user); 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/webController/api/Product.java: -------------------------------------------------------------------------------- 1 | package webController.api; 2 | 3 | import model.bean.ProductComment; 4 | import model.bean.ProductDetail; 5 | import model.bean.ProductSummary; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import service.ProductService; 11 | import webController.Utils; 12 | 13 | import java.util.List; 14 | 15 | @RestController 16 | public class Product { 17 | 18 | private ProductService productService; 19 | 20 | @Autowired 21 | public Product(ProductService productService) { 22 | this.productService = productService; 23 | } 24 | 25 | // List getProductList(); 26 | @RequestMapping(path = "/api/product/getProductList", produces = {"application/json"}) 27 | String getProductList() { 28 | List productSummaryList = productService.getProductList(); 29 | return Utils.format(true, productSummaryList); 30 | } 31 | 32 | // @Nullable 33 | // List getBoughtProductList(String token); 34 | @RequestMapping(path = "/api/product/getBoughtProductList", method = RequestMethod.POST, produces = {"application/json"}) 35 | String getBoughtProductList(String token) { 36 | List productSummaryList = productService.getBoughtProductList(token); 37 | return Utils.format(productSummaryList != null, productSummaryList); 38 | } 39 | 40 | // @Nullable 41 | // List getMyProductList(String token); 42 | @RequestMapping(path = "/api/product/getMyProductList", method = RequestMethod.POST, produces = {"application/json"}) 43 | String getMyProductList(String token) { 44 | List productSummaryList = productService.getMyProductList(token); 45 | return Utils.format(productSummaryList != null, productSummaryList); 46 | } 47 | 48 | // @Nullable 49 | // ProductDetail getProductDetail(Long productId); 50 | @RequestMapping(path = "/api/product/getProductDetail", produces = {"application/json"}) 51 | String getProductDetail(Long productId) { 52 | ProductDetail detail = productService.getProductDetail(productId); 53 | return Utils.format(detail != null, detail); 54 | } 55 | 56 | // // create product, status is editing. return productId 57 | // @Nullable 58 | // Long newProduct(String token); 59 | @RequestMapping(path = "/api/product/newProduct", method = RequestMethod.POST, produces = {"application/json"}) 60 | String newProduct(String token) { 61 | Long productId = productService.newProduct(token); 62 | return Utils.format(productId != null, productId); 63 | } 64 | 65 | // // delete product status if status is selling,censoring or not_approved 66 | // Boolean deleteProduct(String token, Long productId); 67 | @RequestMapping(path = "/api/product/deleteProduct", method = RequestMethod.POST, produces = {"application/json"}) 68 | String deleteProduct(String token, Long productId) { 69 | Boolean res = productService.deleteProduct(token, productId); 70 | return Utils.format(res, null); 71 | } 72 | 73 | // // switch product status to editing from selling,censoring,not_approved 74 | // Boolean editProduct(String token, Long productId); 75 | @RequestMapping(path = "/api/product/editProduct", method = RequestMethod.POST, produces = {"application/json"}) 76 | String editProduct(String token, Long productId) { 77 | Boolean res = productService.editProduct(token, productId); 78 | return Utils.format(res, null); 79 | } 80 | 81 | // // switch product status to censoring 82 | // Boolean editFinish(String token, Long productId); 83 | @RequestMapping(path = "/api/product/editFinish", method = RequestMethod.POST, produces = {"application/json"}) 84 | String editFinish(String token, Long productId) { 85 | Boolean res = productService.editFinish(token, productId); 86 | return Utils.format(res, null); 87 | } 88 | 89 | // Boolean editExpectedPrice(String token, Long productId, Double price); 90 | @RequestMapping(path = "/api/product/editExpectedPrice", method = RequestMethod.POST, produces = {"application/json"}) 91 | String editExpectedPrice(String token, Long productId, Double price) { 92 | Boolean res = productService.editExpectedPrice(token, productId, price); 93 | return Utils.format(res, null); 94 | } 95 | 96 | // Boolean editProductName(String token, Long productId, String productName); 97 | @RequestMapping(path = "/api/product/editProductName", method = RequestMethod.POST, produces = {"application/json"}) 98 | String editProductName(String token, Long productId, String productName) { 99 | Boolean res = productService.editProductName(token, productId, productName); 100 | return Utils.format(res, null); 101 | } 102 | 103 | // Boolean editProductDetail(String token, Long productId, String productDetail); 104 | @RequestMapping(path = "/api/product/editProductDetail", method = RequestMethod.POST, produces = {"application/json"}) 105 | String editProductDetail(String token, Long productId, String productDetail) { 106 | Boolean res = productService.editProductDetail(token, productId, productDetail); 107 | return Utils.format(res, null); 108 | } 109 | 110 | // // add picture to product, return picture id 111 | // @Nullable 112 | // Long editAddPic(String token, Long productId, String picUrl); 113 | @RequestMapping(path = "/api/product/editAddPic", method = RequestMethod.POST, produces = {"application/json"}) 114 | String editAddPic(String token, Long productId, String picUrl) { 115 | Long picId = productService.editAddPic(token, productId, picUrl); 116 | return Utils.format(picId != null, picId); 117 | } 118 | 119 | // // drop picture from product. 120 | // Boolean editDeletePic(String token, Long productId, Long picId); 121 | @RequestMapping(path = "/api/product/editDeletePic", method = RequestMethod.POST, produces = {"application/json"}) 122 | String editDeletePic(String token, Long productId, Long picId) { 123 | Boolean res = productService.editDeletePic(token, productId, picId); 124 | return Utils.format(res, null); 125 | } 126 | 127 | // Boolean orderProduct(String token, Long productId); 128 | @RequestMapping(path = "/api/product/orderProduct", method = RequestMethod.POST, produces = {"application/json"}) 129 | String orderProduct(String token, Long productId) { 130 | Boolean res = productService.orderProduct(token, productId); 131 | return Utils.format(res, null); 132 | } 133 | 134 | // Boolean cancelOrder(String token, Long productId); 135 | @RequestMapping(path = "/api/product/cancelOrder", method = RequestMethod.POST, produces = {"application/json"}) 136 | String cancelOrder(String token, Long productId) { 137 | Boolean res = productService.cancelOrder(token, productId); 138 | return Utils.format(res, null); 139 | } 140 | 141 | // // verify owner and buyer in method 142 | // Boolean confirmOrder(String token , Long productId); 143 | @RequestMapping(path = "/api/product/confirmOrder", method = RequestMethod.POST, produces = {"application/json"}) 144 | String confirmOrder(String token , Long productId) { 145 | Boolean res = productService.confirmOrder(token, productId); 146 | return Utils.format(res, null); 147 | } 148 | 149 | 150 | 151 | // Boolean comment(String token, Long productId, String content); 152 | @RequestMapping(path = "/api/product/comment", method = RequestMethod.POST, produces = {"application/json"}) 153 | String comment(String token, Long productId, String content) { 154 | Boolean res = productService.comment(token, productId, content); 155 | return Utils.format(res, null); 156 | } 157 | 158 | // @Nullable 159 | // List getComments(Long productId); 160 | @RequestMapping(path = "/api/product/getComments", produces = {"application/json"}) 161 | String getComments(Long productId) { 162 | List commentList = productService.getComments(productId); 163 | return Utils.format(commentList != null, commentList); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /flea_market_project/src/test/java/application/test/ProductServiceTest.java: -------------------------------------------------------------------------------- 1 | package application.test; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.ProductComment; 5 | import model.bean.ProductDetail; 6 | import model.bean.ProductPic; 7 | import model.bean.ProductSummary; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | import service.AdminService; 14 | import service.ProductService; 15 | import service.UserService; 16 | 17 | import java.util.List; 18 | 19 | @Slf4j 20 | @SpringBootTest 21 | @RunWith(SpringRunner.class) 22 | public class ProductServiceTest { 23 | 24 | private ProductService productService; 25 | private UserService userService; 26 | private AdminService adminService; 27 | 28 | @Autowired 29 | public void setProductService(ProductService productService) { 30 | this.productService = productService; 31 | } 32 | 33 | @Autowired 34 | public void setUserService(UserService userService) { 35 | this.userService = userService; 36 | } 37 | 38 | @Autowired 39 | public void setAdminService(AdminService adminService) { 40 | this.adminService = adminService; 41 | } 42 | 43 | @Test 44 | public void releaseAndCensorProduct() { 45 | assert userService.register("productRelease1", "productRelease1", "password"); 46 | String token = userService.authorize("productRelease1", "password"); 47 | assert token != null; 48 | String adminToken = userService.authorize("initAdmin", "initAdmin"); 49 | assert adminToken != null; 50 | 51 | // release product and edit information 52 | Long productId = productService.newProduct(token); 53 | assert productId != null; 54 | assert productService.editProductName(token, productId, "product release 1"); 55 | assert productService.editProductDetail(token, productId, "product release detail 1"); 56 | assert productService.editExpectedPrice(token, productId, 233.3); 57 | Long picId = productService.editAddPic(token, productId, "pic://product_release_1"); 58 | assert productService.editFinish(token, productId); 59 | 60 | // product information check 61 | ProductDetail product = productService.getProductDetail(productId); 62 | assert product != null; 63 | log.info("product detail : pic count: {}", product.getPics().size()); 64 | for (ProductPic pic : product.getPics()) { 65 | log.info("product pic: id={}, url={}", pic.getProductPicId(), pic.getProductPicUrl()); 66 | } 67 | assert product.getPics().size() == 1; 68 | assert product.getPics().get(0).getProductPicId().equals(picId); 69 | assert product.getPics().get(0).getProductPicUrl().equals("pic://product_release_1"); 70 | assert product.getSeller() != null; 71 | assert product.getSeller().getUsername().equals("productRelease1"); 72 | assert product.getBuyer() == null; 73 | 74 | // product should not be editable after finish 75 | assert !productService.editProductName(token, productId, "test edit protect"); 76 | 77 | // product could not be visible before censored 78 | assert productService.getProductList().size() == 0; 79 | 80 | // product should be visible to the seller no matter what happen. 81 | List productList = productService.getMyProductList(token); 82 | assert productList != null; 83 | assert productList.size() == 1; 84 | 85 | // get censor list and disapprove product; 86 | List productSummaryList0 = adminService.getCensoringProducts(adminToken); 87 | assert productSummaryList0 != null; 88 | assert productSummaryList0.size() == 1; 89 | assert adminService.censorProduct(adminToken, productSummaryList0.get(0).getProductId(), false); 90 | assert productSummaryList0.get(0).getProductId().equals(productId); 91 | 92 | // censor list should be empty after disapproved product 93 | List productSummaryList1 = adminService.getCensoringProducts(adminToken); 94 | assert productSummaryList1 != null; 95 | assert productSummaryList1.size() == 0; 96 | 97 | // disapproved product should not appear in public list 98 | List productList1 = productService.getProductList(); 99 | assert productList1.size() == 0; 100 | 101 | // re-edit product to censor again. 102 | assert productService.editProduct(token, productId); 103 | assert productService.editExpectedPrice(token, productId, 23.3); 104 | assert productService.editFinish(token, productId); 105 | 106 | // re-edited product should appear in censor list 107 | List productSummaryList2 = adminService.getCensoringProducts(adminToken); 108 | assert productSummaryList2 != null; 109 | assert productSummaryList2.size() == 1; 110 | assert adminService.censorProduct(adminToken, productSummaryList0.get(0).getProductId(), true); 111 | 112 | // censored product should appear in public product list 113 | List productList2 = productService.getProductList(); 114 | assert productList2.size() == 1; 115 | 116 | assert productService.deleteProduct(token, productId); 117 | 118 | // no product should appear after delete 119 | List productList3 = productService.getProductList(); 120 | assert productList3.size() == 0; 121 | } 122 | 123 | @Test 124 | public void testEditPic() { 125 | assert userService.register("productSeller", "productSeller", "password"); 126 | assert userService.register("productBuyer", "productBuyer", "password"); 127 | 128 | String sellerToken = userService.authorize("productSeller", "password"); 129 | String buyerToken = userService.authorize("productBuyer", "password"); 130 | String adminToken = userService.authorize("initAdmin", "initAdmin"); 131 | 132 | assert sellerToken != null; 133 | assert buyerToken != null; 134 | assert adminToken != null; 135 | 136 | Long sellerProductId = productService.newProduct(sellerToken); 137 | assert productService.editExpectedPrice(sellerToken, sellerProductId, 2.33); 138 | assert productService.editProductName(sellerToken, sellerProductId, "the test order product"); 139 | assert productService.editProductDetail(sellerToken, sellerProductId, "the test order product detail"); 140 | productService.editAddPic(sellerToken, sellerProductId, "pic to keep"); 141 | Long picId = productService.editAddPic(sellerToken, sellerProductId, "pic to drop"); 142 | assert productService.editDeletePic(sellerToken, sellerProductId, picId); 143 | assert productService.editFinish(sellerToken, sellerProductId); 144 | 145 | adminService.censorProduct(adminToken, sellerProductId, true); 146 | 147 | List publicProductList = productService.getProductList(); 148 | Long buyerProductId = publicProductList.get(0).getProductId(); 149 | assert buyerProductId.equals(sellerProductId); 150 | 151 | assert productService.orderProduct(buyerToken, buyerProductId); 152 | 153 | List buyerProductList = productService.getBoughtProductList(buyerToken); 154 | assert buyerProductList != null; 155 | assert buyerProductList.size() == 1; 156 | assert buyerProductList.get(0).getSeller().getUsername().equals("productSeller"); 157 | 158 | // order and confirm step by step 159 | 160 | ProductDetail productDetail1 = productService.getProductDetail(buyerProductId); 161 | assert productDetail1 != null; 162 | assert productDetail1.getProductStatus().equals(ProductService.PRODUCT_ORDERED); 163 | 164 | assert productService.confirmOrder(buyerToken, buyerProductId); 165 | 166 | ProductDetail productDetail2 = productService.getProductDetail(buyerProductId); 167 | assert productDetail2 != null; 168 | assert productDetail2.getProductStatus().equals(ProductService.PRODUCT_CONFIRM_BUYER); 169 | 170 | assert productService.confirmOrder(sellerToken, sellerProductId); 171 | 172 | ProductDetail productDetail3 = productService.getProductDetail(buyerProductId); 173 | assert productDetail3 != null; 174 | assert productDetail3.getProductStatus().equals(ProductService.PRODUCT_CLINCH); 175 | 176 | List sellerProductList = productService.getMyProductList(sellerToken); 177 | assert sellerProductList != null; 178 | assert sellerProductList.size() == 1; 179 | 180 | List publicProductListAfterClinch = productService.getProductList(); 181 | for (ProductSummary p : publicProductListAfterClinch) { 182 | log.info(p.toString()); 183 | } 184 | assert publicProductListAfterClinch.size() == 0; 185 | } 186 | 187 | @Test 188 | public void testCancelOrder() { 189 | userService.register("cancelOrderSeller", "cancelOrderSeller", "cancelOrderSeller"); 190 | userService.register("cancelOrderBuyer", "cancelOrderBuyer", "cancelOrderBuyer"); 191 | 192 | String sellerToken = userService.authorize("cancelOrderSeller", "cancelOrderSeller"); 193 | String buyerToken = userService.authorize("cancelOrderBuyer", "cancelOrderBuyer"); 194 | String adminToken = userService.authorize("initAdmin", "initAdmin"); 195 | 196 | assert sellerToken != null; 197 | assert buyerToken != null; 198 | assert adminToken != null; 199 | 200 | Long productId = productService.newProduct(sellerToken); 201 | assert productId != null; 202 | productService.editProductName(sellerToken, productId, "to cancel product"); 203 | productService.editProductDetail(sellerToken, productId, "to cancel product"); 204 | productService.editFinish(sellerToken, productId); 205 | 206 | adminService.censorProduct(adminToken, productId, true); 207 | 208 | assert productService.orderProduct(buyerToken, productId); 209 | assert productService.cancelOrder(buyerToken, productId); 210 | ProductDetail product1 = productService.getProductDetail(productId); 211 | assert product1 != null; 212 | assert product1.getBuyer() == null; 213 | assert product1.getProductStatus().equals(ProductService.PRODUCT_SELLING); 214 | 215 | assert productService.orderProduct(buyerToken, productId); 216 | assert productService.confirmOrder(sellerToken, productId); 217 | assert productService.cancelOrder(buyerToken, productId); 218 | ProductDetail product2 = productService.getProductDetail(productId); 219 | assert product2 != null; 220 | assert product2.getBuyer() == null; 221 | assert product2.getProductStatus().equals(ProductService.PRODUCT_SELLING); 222 | 223 | assert productService.orderProduct(buyerToken, productId); 224 | assert productService.confirmOrder(buyerToken, productId); 225 | assert productService.confirmOrder(sellerToken, productId); 226 | ProductDetail product3 = productService.getProductDetail(productId); 227 | assert product3 != null; 228 | assert product3.getBuyer().getUsername().equals("cancelOrderBuyer"); 229 | assert product3.getProductStatus().equals(ProductService.PRODUCT_CLINCH); 230 | } 231 | 232 | @Test 233 | public void testComment() { 234 | assert userService.register("productCommentSeller", "productCommentSeller", 235 | "productCommentSeller"); 236 | assert userService.register("productCommentBuyer", "productCommentBuyer", 237 | "productCommentBuyer"); 238 | 239 | String sellerToken = userService.authorize("productCommentSeller", "productCommentSeller"); 240 | String buyerToken = userService.authorize("productCommentBuyer", "productCommentBuyer"); 241 | String adminToken = userService.authorize("initAdmin", "initAdmin"); 242 | 243 | assert sellerToken != null; 244 | assert buyerToken != null; 245 | assert adminToken != null; 246 | 247 | Long productId = productService.newProduct(sellerToken); 248 | assert productId != null; 249 | assert productService.editProductName(sellerToken, productId, "product to comment"); 250 | assert productService.editProductDetail(sellerToken, productId, "product to comment, detail"); 251 | assert productService.editFinish(sellerToken, productId); 252 | 253 | adminService.censorProduct(adminToken, productId, true); 254 | 255 | assert productService.comment(sellerToken, productId, "first"); 256 | List commentList1 = productService.getComments(productId); 257 | assert commentList1 != null; 258 | assert commentList1.size() == 1; 259 | 260 | assert productService.comment(buyerToken, productId, "second"); 261 | List commentList2 = productService.getComments(productId); 262 | assert commentList2 != null; 263 | assert commentList2.size() == 2; 264 | 265 | for (ProductComment c : commentList2) { 266 | log.info(c.toString()); 267 | } 268 | 269 | productService.deleteProduct(sellerToken, productId); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /flea_market_project/src/main/java/service/impl/ProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package service.impl; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import model.bean.ProductComment; 5 | import model.bean.ProductDetail; 6 | import model.bean.ProductSummary; 7 | import model.dao.entity.ProductCommentEntity; 8 | import model.dao.entity.ProductEntity; 9 | import model.dao.entity.ProductPicEntity; 10 | import model.dao.entity.UserEntity; 11 | import model.dao.repo.ProductCommentRepo; 12 | import model.dao.repo.ProductPicRepo; 13 | import model.dao.repo.ProductRepo; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.lang.Nullable; 16 | import org.springframework.stereotype.Service; 17 | import org.springframework.transaction.annotation.Transactional; 18 | import service.ProductService; 19 | import service.SystemService; 20 | 21 | import java.util.ArrayList; 22 | import java.util.Date; 23 | import java.util.List; 24 | import java.util.Optional; 25 | 26 | @Slf4j 27 | @Service 28 | public class ProductServiceImpl implements ProductService { 29 | private SystemService systemService; 30 | private ProductRepo productRepo; 31 | private ProductPicRepo productPicRepo; 32 | private ProductCommentRepo productCommentRepo; 33 | 34 | @Autowired 35 | public ProductServiceImpl(SystemService systemService, ProductRepo productRepo, 36 | ProductPicRepo productPicRepo, ProductCommentRepo productCommentRepo) { 37 | this.systemService = systemService; 38 | this.productRepo = productRepo; 39 | this.productPicRepo = productPicRepo; 40 | this.productCommentRepo = productCommentRepo; 41 | } 42 | 43 | private Boolean productSwitchableToEdit(ProductEntity product) { 44 | return product.getProductStatus().equals(ProductService.PRODUCT_SELLING) || 45 | product.getProductStatus().equals(ProductService.PRODUCT_CENSORING) || 46 | product.getProductStatus().equals(ProductService.PRODUCT_EDITING) || 47 | product.getProductStatus().equals(ProductService.PRODUCT_NOT_APPROVED); 48 | } 49 | 50 | private List productEditable(@Nullable String token, Long productId) { 51 | UserEntity user = systemService.token2User(token); 52 | 53 | if (user == null) { 54 | log.warn("no such user"); 55 | return null; 56 | } 57 | 58 | Optional productOpt = productRepo.findById(productId); 59 | 60 | if (productOpt.isPresent()) { 61 | if (productOpt.get().getProductStatus().equals(ProductService.PRODUCT_EDITING)) { 62 | if (productOpt.get().getSeller().getUserId().equals(user.getUserId())) { 63 | log.info("user '{}' can edit product '{}'", user.getUsername(), productId); 64 | List list = new ArrayList<>(); 65 | list.add(user); 66 | list.add(productOpt.get()); 67 | return list; 68 | } else { 69 | log.warn("user '{}' is not the seller of product '{}'", user.getUsername(), productId); 70 | return null; 71 | } 72 | } else { 73 | log.warn("product '{}' is not in editing status", productId); 74 | return null; 75 | } 76 | } else { 77 | log.warn("no such product: '{}'", productId); 78 | return null; 79 | } 80 | } 81 | 82 | @Override 83 | public List getProductList() { 84 | List productEntityList = 85 | productRepo.findByProductStatusEquals(ProductService.PRODUCT_SELLING, productRepo.sortByReleaseDesc); 86 | List productSummaryList = new ArrayList<>(productEntityList.size()); 87 | for (ProductEntity productEntity : productEntityList) { 88 | productSummaryList.add(new ProductSummary(productEntity)); 89 | } 90 | return productSummaryList; 91 | } 92 | 93 | @Override 94 | @Nullable 95 | public List getBoughtProductList(String token) { 96 | UserEntity user = systemService.token2User(token); 97 | if (user == null) { 98 | log.warn("invalid or expired token"); 99 | return null; 100 | } else { 101 | List productEntityList = productRepo.findByBuyerEquals(user, productRepo.sortByReleaseDesc); 102 | List productSummaryList = new ArrayList<>(productEntityList.size()); 103 | for (ProductEntity productEntity : productEntityList) { 104 | productSummaryList.add(new ProductSummary(productEntity)); 105 | } 106 | log.info("user '{}' get '{}' bought product summary", user.getUsername(), productSummaryList.size()); 107 | return productSummaryList; 108 | } 109 | } 110 | 111 | @Override 112 | @Nullable 113 | public List getMyProductList(String token) { 114 | UserEntity user = systemService.token2User(token); 115 | if (user == null) { 116 | log.warn("invalid or expired token"); 117 | return null; 118 | } else { 119 | List productEntityList = productRepo.findBySellerEquals(user, productRepo.sortByReleaseDesc); 120 | List productSummaryList = new ArrayList<>(productEntityList.size()); 121 | for (ProductEntity productEntity : productEntityList) { 122 | productSummaryList.add(new ProductSummary(productEntity)); 123 | } 124 | log.info("user '{}' get '{}' sold product summary", user.getUsername(), productSummaryList.size()); 125 | return productSummaryList; 126 | } 127 | } 128 | 129 | @Nullable 130 | @Override 131 | @Transactional 132 | public ProductDetail getProductDetail(Long productId) { 133 | Optional productOpt = productRepo.findById(productId); 134 | if (productOpt.isPresent()) { 135 | log.info("get product detail id='{}'", productId); 136 | return new ProductDetail(productOpt.get()); 137 | } else { 138 | log.warn("no such product id='{}'", productId); 139 | return null; 140 | } 141 | } 142 | 143 | @Override 144 | @Nullable 145 | public Long newProduct(String token) { 146 | UserEntity user = systemService.token2User(token); 147 | if (user == null) { 148 | log.warn("invalid or expired token"); 149 | return null; 150 | } else { 151 | ProductEntity product = new ProductEntity(); 152 | product.setProductStatus(ProductService.PRODUCT_EDITING); 153 | product.setSeller(user); 154 | product.setPublishTime(new Date()); 155 | product.setExpectedPrice(0.0); 156 | product.setProductName("new product"); 157 | product.setProductDetail("product detail"); 158 | product = productRepo.save(product); 159 | log.info("user '{}' create a new product '{}'", user.getUsername(), product.getProductId()); 160 | return product.getProductId(); 161 | } 162 | } 163 | 164 | @Override 165 | public Boolean deleteProduct(String token, Long productId) { 166 | UserEntity user = systemService.token2User(token); 167 | if (user == null) { 168 | log.warn("invalid or expired token"); 169 | return false; 170 | } else { 171 | Optional productOpt = productRepo.findById(productId); 172 | if (productOpt.isPresent()) { 173 | ProductEntity product = productOpt.get(); 174 | if (product.getSeller().getUserId().equals(user.getUserId())) { 175 | if (productSwitchableToEdit(product)) { 176 | productRepo.delete(product); 177 | log.info("user '{}' delete product '{}'", user.getUsername(), productId); 178 | return true; 179 | } else { 180 | log.warn("user '{}' want to delete product '{}' while it's '{}'", 181 | user.getUsername(), productId, product.getProductStatus()); 182 | return false; 183 | } 184 | } else { 185 | log.warn("user '{}' is not the seller of product '{}'", user.getUsername(), productId); 186 | return false; 187 | } 188 | } else { 189 | log.warn("user '{}' want to delete not exist product '{}'", user.getUsername(), productId); 190 | return false; 191 | } 192 | } 193 | } 194 | 195 | @Override 196 | public Boolean editProduct(String token, Long productId) { 197 | UserEntity user = systemService.token2User(token); 198 | if (user == null) { 199 | log.warn("invalid or expired token"); 200 | return false; 201 | } else { 202 | Optional productOpt = productRepo.findById(productId); 203 | if (productOpt.isPresent()) { 204 | ProductEntity product = productOpt.get(); 205 | if (product.getSeller().getUserId().equals(user.getUserId())) { 206 | if (productSwitchableToEdit(product)) { 207 | product.setProductStatus(ProductService.PRODUCT_EDITING); 208 | productRepo.save(product); 209 | log.info("user '{}' edit product '{}'", user.getUsername(), productId); 210 | return true; 211 | } else { 212 | log.warn("user '{}' want to edit product '{}' while it's '{}'", 213 | user.getUsername(), productId, product.getProductStatus()); 214 | return false; 215 | } 216 | } else { 217 | log.warn("user '{}' is not the seller of product '{}'", user.getUsername(), productId); 218 | return false; 219 | } 220 | } else { 221 | log.warn("user '{}' want to edit not exist product '{}'", user.getUsername(), productId); 222 | return false; 223 | } 224 | } 225 | } 226 | 227 | @Override 228 | public Boolean editFinish(String token, Long productId) { 229 | UserEntity user = systemService.token2User(token); 230 | if (user == null) { 231 | log.warn("invalid or expired token"); 232 | return false; 233 | } else { 234 | Optional productOpt = productRepo.findById(productId); 235 | if (productOpt.isPresent()) { 236 | ProductEntity product = productOpt.get(); 237 | if (product.getSeller().getUserId().equals(user.getUserId())) { 238 | if (product.getProductStatus().equals(ProductService.PRODUCT_EDITING)) { 239 | product.setProductStatus(ProductService.PRODUCT_CENSORING); 240 | productRepo.save(product); 241 | log.info("user '{}' finish edit on product '{}'", user.getUsername(), productId); 242 | return true; 243 | } else { 244 | log.warn("user '{}' want to finish edit product '{}' while it's '{}'", 245 | user.getUsername(), productId, product.getProductStatus()); 246 | return false; 247 | } 248 | } else { 249 | log.warn("user '{}' is not the seller of product '{}'", user.getUsername(), productId); 250 | return false; 251 | } 252 | } else { 253 | log.warn("user '{}' want to finish edit on not exist product '{}'", user.getUsername(), productId); 254 | return false; 255 | } 256 | } 257 | } 258 | 259 | @Override 260 | public Boolean editExpectedPrice(String token, Long productId, Double price) { 261 | List list = productEditable(token, productId); 262 | if (list == null) { 263 | log.warn("edit price failed"); 264 | return false; 265 | } else { 266 | UserEntity user = (UserEntity)list.get(0); 267 | ProductEntity product = (ProductEntity)list.get(1); 268 | 269 | product.setExpectedPrice(price); 270 | productRepo.save(product); 271 | log.info("user '{}' edit expected price to '{}' on product '{}'", user.getUsername(), price, productId); 272 | return true; 273 | } 274 | } 275 | 276 | @Override 277 | public Boolean editProductName(String token, Long productId, String productName) { 278 | List list = productEditable(token, productId); 279 | if (list == null) { 280 | log.warn("edit product name failed"); 281 | return false; 282 | } else { 283 | UserEntity user = (UserEntity)list.get(0); 284 | ProductEntity product = (ProductEntity)list.get(1); 285 | 286 | product.setProductName(productName); 287 | productRepo.save(product); 288 | log.info("user '{}' edit product name to '{}' on product '{}'", user.getUsername(), productName, productId); 289 | return true; 290 | } 291 | } 292 | 293 | @Override 294 | public Boolean editProductDetail(String token, Long productId, String productDetail) { 295 | List list = productEditable(token, productId); 296 | if (list == null) { 297 | log.warn("edit product detail failed"); 298 | return false; 299 | } else { 300 | UserEntity user = (UserEntity)list.get(0); 301 | ProductEntity product = (ProductEntity)list.get(1); 302 | 303 | product.setProductDetail(productDetail); 304 | productRepo.save(product); 305 | log.info("user '{}' edit product detail to '{}' on product '{}'", 306 | user.getUsername(), productDetail, productId); 307 | return true; 308 | } 309 | } 310 | 311 | @Override 312 | @Nullable 313 | @Transactional() 314 | public Long editAddPic(String token, Long productId, String picUrl) { 315 | List list = productEditable(token, productId); 316 | if (list == null) { 317 | log.warn("edit add product picture failed"); 318 | return null; 319 | } else { 320 | UserEntity user = (UserEntity)list.get(0); 321 | ProductEntity product = (ProductEntity)list.get(1); 322 | 323 | ProductPicEntity productPic = new ProductPicEntity(); 324 | productPic.setProduct(product); 325 | productPic.setProductPicUrl(picUrl); 326 | 327 | productPic = productPicRepo.save(productPic); 328 | product.getProductPicList().add(productPic); 329 | productRepo.save(product); 330 | log.info("user '{}' add product picture '{}' on product '{}'", user.getUsername(), picUrl, productId); 331 | return productPic.getProductPicId(); 332 | } 333 | } 334 | 335 | @Override 336 | public Boolean editDeletePic(String token, Long productId, Long picId) { 337 | List list = productEditable(token, productId); 338 | if (list == null) { 339 | log.warn("edit delete product picture failed"); 340 | return false; 341 | } else { 342 | UserEntity user = (UserEntity)list.get(0); 343 | ProductEntity product = (ProductEntity)list.get(1); 344 | 345 | Optional productPicOpt = productPicRepo.findById(picId); 346 | if (productPicOpt.isPresent()) { 347 | if (productPicOpt.get().getProduct().getProductId().equals(product.getProductId())) { 348 | productPicRepo.delete(productPicOpt.get()); 349 | log.info("user '{}' delete product picture '{}' on product '{}'", 350 | user.getUsername(), picId, productId); 351 | return true; 352 | } else { 353 | log.warn("user '{}' delete product picture '{}' not belong to product '{}'", 354 | user.getUsername(), picId, productId); 355 | return false; 356 | } 357 | } else { 358 | log.warn("user '{}' delete not exist product picture '{}' on product '{}'", 359 | user.getUsername(), picId, productId); 360 | return false; 361 | } 362 | } 363 | } 364 | 365 | // @Override 366 | // public Boolean modifyProduct(String token, ProductDetail product) { 367 | // Optional productEntityOpt = productRepo.findById(product.getProductId()); 368 | // UserEntity user = systemService.token2User(token); 369 | // if (user == null) { 370 | // log.warn("invalid or expired token '{}'", token); 371 | // return false; 372 | // } else { 373 | // if (productEntityOpt.isPresent()) { 374 | // ProductEntity productEntity = productEntityOpt.get(); 375 | // if (product.getSeller().getUsername().equals(productEntity.getSeller().getUsername())) { 376 | // BeanUtils.copyProperties(product, productEntity); 377 | 378 | // List productPicList = product.getPics(); 379 | // // List productPicEntityList = new ArrayList<>(productPicList.size()); 380 | // for (ProductPic productPic : productPicList) { 381 | // ProductPicEntity picEntity = new ProductPicEntity(); 382 | // picEntity.setProduct(productEntity); 383 | // picEntity.setProductPicUrl(productPic.getProductPicUrl()); 384 | // productPicRepo.save(picEntity); 385 | // // productPicEntityList.set(i, new) 386 | // } 387 | // // productEntity.setProductPicList(productPicEntityList); 388 | // productRepo.save(productEntity); 389 | 390 | // log.info("user '{}' modified product('{}')", user.getUsername(), productEntity.getProductId()); 391 | // return true; 392 | // } else { 393 | // log.warn("product('{}')'s seller is not '{}'", product.getProductId(), user.getUsername()); 394 | // return false; 395 | // } 396 | // } else { 397 | // log.warn("product id had been changed or no such product whose id is '{}'", product.getProductId()); 398 | // return false; 399 | // } 400 | // } 401 | // } 402 | 403 | @Override 404 | public Boolean orderProduct(String token, Long productId) { 405 | UserEntity user = systemService.token2User(token); 406 | Optional productOpt = productRepo.findById(productId); 407 | if (user == null) { 408 | log.warn("invalid or expired token '{}'", token); 409 | return false; 410 | } else { 411 | if (productOpt.isPresent()) { 412 | ProductEntity product = productOpt.get(); 413 | if (product.getProductStatus().equals(ProductService.PRODUCT_SELLING)) { 414 | product.setBuyer(user); 415 | product.setProductStatus(ProductService.PRODUCT_ORDERED); 416 | productRepo.save(product); 417 | log.info("user '{}' order product '{}'", user.getUsername(), productId); 418 | return true; 419 | } else { 420 | log.warn("user '{}' want to order product '{}' which are not selling", 421 | user.getUsername(), productId); 422 | return false; 423 | } 424 | } else { 425 | log.warn("invalid productId"); 426 | return false; 427 | } 428 | } 429 | } 430 | 431 | @Override 432 | public Boolean cancelOrder(String token, Long productId) { 433 | UserEntity user = systemService.token2User(token); 434 | Optional productOpt = productRepo.findById(productId); 435 | if (user == null) { 436 | log.warn("invalid or expired token '{}'", token); 437 | return false; 438 | } else { 439 | if (productOpt.isPresent()) { 440 | ProductEntity product = productOpt.get(); 441 | if (product.getProductStatus().equals(ProductService.PRODUCT_ORDERED) 442 | || product.getProductStatus().equals(ProductService.PRODUCT_CONFIRM_SELLER) 443 | || product.getProductStatus().equals(ProductService.PRODUCT_CONFIRM_BUYER)) { 444 | if (product.getBuyer().getUserId().equals(user.getUserId())) { 445 | product.setProductStatus(ProductService.PRODUCT_SELLING); 446 | product.setBuyer(null); 447 | productRepo.save(product); 448 | 449 | log.info("buyer '{}' canceled order on product '{}'", user.getUsername(), productId); 450 | return true; 451 | } else if (product.getSeller().getUserId().equals(user.getUserId())) { 452 | product.setProductStatus(ProductService.PRODUCT_SELLING); 453 | product.setBuyer(null); 454 | productRepo.save(product); 455 | 456 | log.info("seller '{}' canceled order on product '{}'", user.getUsername(), productId); 457 | return true; 458 | } else { 459 | log.warn("user '{}' cancel order on product '{}' which not related to him(she)", 460 | user.getUsername(), productId); 461 | return false; 462 | } 463 | } else { 464 | log.warn("user '{}' cancel order on product '{}' which is not ordered", 465 | user.getUsername(), productId); 466 | return false; 467 | } 468 | } else { 469 | log.warn("invalid productId"); 470 | return false; 471 | } 472 | } 473 | } 474 | 475 | @Override 476 | public Boolean confirmOrder(String token, Long productId) { 477 | UserEntity user = systemService.token2User(token); 478 | Optional productOpt = productRepo.findById(productId); 479 | if (user == null) { 480 | log.warn("invalid or expired token '{}'", token); 481 | return false; 482 | } else { 483 | if (productOpt.isPresent()) { 484 | ProductEntity product = productOpt.get(); 485 | switch (product.getProductStatus()) { 486 | case ProductService.PRODUCT_ORDERED: 487 | if (product.getSeller().getUserId().equals(user.getUserId())) { 488 | product.setProductStatus(ProductService.PRODUCT_CONFIRM_SELLER); 489 | productRepo.save(product); 490 | return true; 491 | } else if (product.getBuyer().getUserId().equals(user.getUserId())) { 492 | product.setProductStatus(ProductService.PRODUCT_CONFIRM_BUYER); 493 | productRepo.save(product); 494 | return true; 495 | } else { 496 | log.warn("user '{}' want to confirm product '{}' which has not relation to him(she)", 497 | user.getUsername(), productId); 498 | return false; 499 | } 500 | case ProductService.PRODUCT_CONFIRM_SELLER: 501 | if (product.getBuyer().getUserId().equals(user.getUserId())) { 502 | product.setProductStatus(ProductService.PRODUCT_CLINCH); 503 | productRepo.save(product); 504 | return true; 505 | } else { 506 | log.warn("user '{}' want to confirm product '{}' which has not relation to him(she)", 507 | user.getUsername(), productId); 508 | return false; 509 | } 510 | case ProductService.PRODUCT_CONFIRM_BUYER: 511 | if (product.getSeller().getUserId().equals(user.getUserId())) { 512 | product.setProductStatus(ProductService.PRODUCT_CLINCH); 513 | productRepo.save(product); 514 | return true; 515 | } else { 516 | log.warn("user '{}' want to confirm product '{}' which has not relation to him(she)", 517 | user.getUsername(), productId); 518 | return false; 519 | } 520 | default: 521 | log.warn("user '{}' want to confirm product '{}' which cannot be confirmed", 522 | user.getUsername(), productId); 523 | return false; 524 | } 525 | } else { 526 | log.warn("invalid productId"); 527 | return false; 528 | } 529 | } 530 | } 531 | 532 | @Override 533 | public Boolean comment(String token, Long productId, String content) { 534 | UserEntity user = systemService.token2User(token); 535 | if (user == null) { 536 | log.warn("invalid or expired token '{}'", token); 537 | return false; 538 | } else { 539 | Optional productOpt = productRepo.findById(productId); 540 | if (productOpt.isPresent()) { 541 | ProductEntity product = productOpt.get(); 542 | ProductCommentEntity commentEntity = new ProductCommentEntity(); 543 | commentEntity.setUser(user); 544 | commentEntity.setProduct(product); 545 | commentEntity.setContent(content); 546 | commentEntity.setCommentTime(new Date()); 547 | productCommentRepo.save(commentEntity); 548 | 549 | log.info("user '{}' comment on product '{}': '{}'", 550 | user.getUsername(), productId, content); 551 | return true; 552 | } else { 553 | log.warn("user '{}' comment on not exist product '{}'", user.getUsername(), productId); 554 | return false; 555 | } 556 | } 557 | } 558 | 559 | @Override 560 | @Nullable 561 | public List getComments(Long productId) { 562 | Optional productOpt = productRepo.findById(productId); 563 | if (productOpt.isPresent()) { 564 | List commentEntityList = 565 | productCommentRepo.findByProductEquals(productOpt.get()); 566 | List commentList = new ArrayList<>(commentEntityList.size()); 567 | for (ProductCommentEntity productCommentEntity : commentEntityList) { 568 | commentList.add(new ProductComment(productCommentEntity)); 569 | } 570 | log.info("somebody get '{}' comment(s) on product '{}'", commentList.size(), productId); 571 | return commentList; 572 | } else { 573 | log.warn("somebody get product comment on not exist product '{}'", productId); 574 | return null; 575 | } 576 | } 577 | } 578 | --------------------------------------------------------------------------------