first commit

This commit is contained in:
2025-11-07 14:57:14 +07:00
commit 06ffe84de4
25 changed files with 977 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
package com.example.project_it207_server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ProjectIt207ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ProjectIt207ServerApplication.class, args);
}
}

View File

@@ -0,0 +1,25 @@
package com.example.project_it207_server.model.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table(name = "carts")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class Cart {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long cartId;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
private LocalDateTime createdAt = LocalDateTime.now();
@OneToMany(mappedBy = "cart", cascade = CascadeType.ALL)
private List<CartItem> items;
}

View File

@@ -0,0 +1,30 @@
package com.example.project_it207_server.model.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
@Entity
@Table(name = "cart_items")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
class CartItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long cartItemId;
@ManyToOne
@JoinColumn(name = "cart_id")
private Cart cart;
@ManyToOne
@JoinColumn(name = "product_id")
private Product product;
private int quantity;
private BigDecimal price;
}

View File

@@ -0,0 +1,26 @@
package com.example.project_it207_server.model.entity;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table(name = "categories")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long categoryId;
@Column(unique = true, nullable = false)
private String categoryName;
private String description;
private String imageUrl;
private LocalDateTime createdAt = LocalDateTime.now();
private LocalDateTime updatedAt = LocalDateTime.now();
@OneToMany(mappedBy = "category", cascade = CascadeType.ALL)
private List<Product> products;
}

View File

@@ -0,0 +1,29 @@
package com.example.project_it207_server.model.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table(name = "orders")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long orderId;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
private BigDecimal totalPrice;
private String orderStatus = "PENDING";
private String shippingAddress;
private LocalDateTime createdAt = LocalDateTime.now();
private LocalDateTime updatedAt = LocalDateTime.now();
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems;
}

View File

@@ -0,0 +1,29 @@
package com.example.project_it207_server.model.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
@Entity
@Table(name = "order_items")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long orderItemId;
@ManyToOne
@JoinColumn(name = "order_id")
private Order order;
@ManyToOne
@JoinColumn(name = "product_id")
private Product product;
private int quantity;
private BigDecimal price;
}

View File

@@ -0,0 +1,28 @@
package com.example.project_it207_server.model.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table(name = "products")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long productId;
private String productName;
private String description;
private BigDecimal price;
private int stockQuantity;
private String imageUrl;
private LocalDateTime createdAt = LocalDateTime.now();
private LocalDateTime updatedAt = LocalDateTime.now();
@ManyToOne
@JoinColumn(name = "category_id")
private Category category;
}

View File

@@ -0,0 +1,16 @@
package com.example.project_it207_server.model.entity;
import jakarta.persistence.*;
import lombok.*;
@Entity
@Table(name = "roles")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long roleId;
@Column(unique = true, nullable = false)
private String roleName;
}

View File

@@ -0,0 +1,38 @@
package com.example.project_it207_server.model.entity;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "users")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String passwordHash;
@Column(unique = true, nullable = false)
private String email;
private String firstName;
private String lastName;
private String gender;
private String phoneNumber;
private String address;
private String avatarUrl;
@ManyToOne
@JoinColumn(name = "role_id")
private Role role;
private LocalDateTime createdAt = LocalDateTime.now();
private LocalDateTime updatedAt = LocalDateTime.now();
}

View File

@@ -0,0 +1,29 @@
package com.example.project_it207_server.redis;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// Cấu hình serializer cho key (String)
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// Cấu hình serializer cho value (Object)
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.afterPropertiesSet();
return template;
}
}

View File

@@ -0,0 +1,210 @@
package com.example.project_it207_server.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Service
public class RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
// ===== VALUE OPERATIONS (String/Object) =====
/**
* Lưu giá trị đơn giản với key
*/
public void setValue(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* Lưu giá trị với thời gian hết hạn
*/
public void setValueWithExpiry(String key, Object value, long timeout, TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* Lấy giá trị theo key
*/
public Object getValue(String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* Chỉ set nếu key chưa tồn tại
*/
public Boolean setIfAbsent(String key, Object value) {
return redisTemplate.opsForValue().setIfAbsent(key, value);
}
/**
* Tăng giá trị số
*/
public Long increment(String key) {
return redisTemplate.opsForValue().increment(key);
}
/**
* Tăng giá trị số với delta
*/
public Long increment(String key, long delta) {
return redisTemplate.opsForValue().increment(key, delta);
}
// ===== HASH OPERATIONS =====
/**
* Lưu field vào hash
*/
public void setHashField(String key, String field, Object value) {
redisTemplate.opsForHash().put(key, field, value);
}
/**
* Lấy field từ hash
*/
public Object getHashField(String key, String field) {
return redisTemplate.opsForHash().get(key, field);
}
/**
* Lấy tất cả fields từ hash
*/
public Map<Object, Object> getAllHashFields(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* Kiểm tra field có tồn tại trong hash
*/
public Boolean hasHashField(String key, String field) {
return redisTemplate.opsForHash().hasKey(key, field);
}
// ===== LIST OPERATIONS =====
/**
* Thêm vào đầu list
*/
public Long addToListLeft(String key, Object value) {
return redisTemplate.opsForList().leftPush(key, value);
}
/**
* Thêm vào cuối list
*/
public Long addToListRight(String key, Object value) {
return redisTemplate.opsForList().rightPush(key, value);
}
/**
* Lấy và xóa phần tử đầu list
*/
public Object popFromListLeft(String key) {
return redisTemplate.opsForList().leftPop(key);
}
public Object deleteItemListByIndex(String key, long index) {
// Lấy phần tử tại index trước khi xóa
Object itemToDelete = redisTemplate.opsForList().index(key, index);
if (itemToDelete != null) {
// Xóa phần tử đầu tiên có giá trị bằng itemToDelete
redisTemplate.opsForList().remove(key, 1, itemToDelete);
return itemToDelete; // Trả về phần tử đã xóa
}
return null; // Trả về null nếu không tìm thấy phần tử
}
/**
* Lấy range của list
*/
public List<Object> getListRange(String key, long start, long end) {
return redisTemplate.opsForList().range(key, start, end);
}
// ===== SET OPERATIONS =====
/**
* Thêm vào set
*/
public Long addToSet(String key, Object... values) {
return redisTemplate.opsForSet().add(key, values);
}
/**
* Lấy tất cả members của set
*/
public Set<Object> getSetMembers(String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* Kiểm tra value có trong set
*/
public Boolean isSetMember(String key, Object value) {
return redisTemplate.opsForSet().isMember(key, value);
}
// ===== STRING REDIS TEMPLATE EXAMPLES =====
/**
* Sử dụng StringRedisTemplate cho String operations
*/
public void setStringValue(String key, String value) {
stringRedisTemplate.opsForValue().set(key, value);
}
public String getStringValue(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
public void setStringValueWithExpiry(String key, String value, Duration duration) {
stringRedisTemplate.opsForValue().set(key, value, duration);
}
// ===== UTILITY METHODS =====
/**
* Kiểm tra key có tồn tại
*/
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
/**
* Xóa key
*/
public Boolean deleteKey(String key) {
return redisTemplate.delete(key);
}
/**
* Set thời gian hết hạn cho key
*/
public Boolean expireKey(String key, long timeout, TimeUnit timeUnit) {
return redisTemplate.expire(key, timeout, timeUnit);
}
/**
* Lấy thời gian còn lại của key
*/
public Long getKeyExpiry(String key) {
return redisTemplate.getExpire(key);
}
}

View File

@@ -0,0 +1,6 @@
package com.example.project_it207_server.repository;
import com.example.project_it207_server.model.entity.Category;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CategoryRepository extends JpaRepository<Category, Long> {}

View File

@@ -0,0 +1,6 @@
package com.example.project_it207_server.repository;
import com.example.project_it207_server.model.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;
public interface OrderRepository extends JpaRepository<Order, Long> {}

View File

@@ -0,0 +1,8 @@
package com.example.project_it207_server.repository;
import com.example.project_it207_server.model.entity.Product;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}

View File

@@ -0,0 +1,9 @@
package com.example.project_it207_server.repository;
import com.example.project_it207_server.model.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}

View File

@@ -0,0 +1,16 @@
spring.application.name=project_it207_server
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/project_it207?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.redis.host=localhost
spring.redis.port=6379
jwt.secret-key=404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
jwt.expiration=86400000

View File

@@ -0,0 +1,13 @@
package com.example.project_it207_server;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ProjectIt207ServerApplicationTests {
@Test
void contextLoads() {
}
}