feat(user): add user entity and repository with JPA integration

This commit is contained in:
2025-11-29 09:38:08 +08:00
parent 3eb651e039
commit 894a1c5d07
10 changed files with 178 additions and 8 deletions

18
.idea/dataSources.xml generated Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="weblog@127.0.0.1" uuid="bb8330e4-9a89-4978-ad63-ad6402096c16">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<imported>true</imported>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://127.0.0.1:5432/weblog</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
<property name="com.intellij.clouds.kubernetes.db.container.port" />
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

1
.idea/modules.xml generated
View File

@@ -5,6 +5,7 @@
<module fileurl="file://$PROJECT_DIR$/weblog-springboot.iml" filepath="$PROJECT_DIR$/weblog-springboot.iml" /> <module fileurl="file://$PROJECT_DIR$/weblog-springboot.iml" filepath="$PROJECT_DIR$/weblog-springboot.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/weblog-module-common/weblog-springboot.weblog-module-common.main.iml" filepath="$PROJECT_DIR$/.idea/modules/weblog-module-common/weblog-springboot.weblog-module-common.main.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/weblog-module-common/weblog-springboot.weblog-module-common.main.iml" filepath="$PROJECT_DIR$/.idea/modules/weblog-module-common/weblog-springboot.weblog-module-common.main.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/weblog-web/weblog-springboot.weblog-web.main.iml" filepath="$PROJECT_DIR$/.idea/modules/weblog-web/weblog-springboot.weblog-web.main.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/weblog-web/weblog-springboot.weblog-web.main.iml" filepath="$PROJECT_DIR$/.idea/modules/weblog-web/weblog-springboot.weblog-web.main.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/weblog-web/weblog-springboot.weblog-web.test.iml" filepath="$PROJECT_DIR$/.idea/modules/weblog-web/weblog-springboot.weblog-web.test.iml" />
</modules> </modules>
</component> </component>
</project> </project>

7
.idea/sqldialects.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="file://$PROJECT_DIR$/sql/createTable.sql" dialect="PostgreSQL" />
<file url="PROJECT" dialect="PostgreSQL" />
</component>
</project>

33
sql/createTable.sql Normal file
View File

@@ -0,0 +1,33 @@
-- 1. 创建一个函数,用于在数据更新时自动修改 update_time 字段
CREATE OR REPLACE FUNCTION set_update_time()
RETURNS TRIGGER AS
$$
BEGIN
NEW.update_time = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 2. 创建表(使用 BOOLEAN 替代 SMALLINT for is_deleted
CREATE TABLE t_user
(
id BIGSERIAL PRIMARY KEY,
username VARCHAR(60) NOT NULL UNIQUE,
password VARCHAR(60) NOT NULL,
create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
-- WITH TIME ZONE 是更严谨的选择
update_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
-- 使用 BOOLEAN 逻辑删除DEFAULT FALSE 对应 '0未删除'
is_deleted BOOLEAN NOT NULL DEFAULT FALSE
);
-- 3. 创建触发器,在每次 UPDATE 操作前调用函数
CREATE TRIGGER set_t_user_update_time
BEFORE UPDATE
ON t_user
FOR EACH ROW
EXECUTE FUNCTION set_update_time();
-- 添加注释
COMMENT ON TABLE t_user IS '用户表(优化版)';
COMMENT ON COLUMN t_user.is_deleted IS '逻辑删除FALSE未删除 TRUE已删除';

View File

@@ -1,5 +1,5 @@
plugins { plugins {
java `java-library`
} }
dependencies { dependencies {
@@ -8,6 +8,8 @@ dependencies {
implementation("com.google.guava:guava:33.5.0-jre") implementation("com.google.guava:guava:33.5.0-jre")
// commons-lang3 // commons-lang3
implementation("org.apache.commons:commons-lang3:3.20.0") implementation("org.apache.commons:commons-lang3:3.20.0")
// jpa
api("org.springframework.boot:spring-boot-starter-data-jpa")
// test // test
testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.boot:spring-boot-starter-test")
// jackson // jackson
@@ -17,4 +19,6 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-aop") implementation("org.springframework.boot:spring-boot-starter-aop")
// web // web
implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-web")
// postgresql
runtimeOnly("org.postgresql:postgresql")
} }

View File

@@ -0,0 +1,82 @@
package com.hanserwei.common.domain.dataobject;
import jakarta.persistence.*; // 使用 Jakarta Persistence API (JPA 3.0+)
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.io.Serial;
import java.io.Serializable;
import java.time.Instant; // 推荐用于 TIMESTAMP WITH TIME ZONE
/**
* 用户表t_user 对应实体)
*/
@Entity
@Setter
@Getter
@Builder
@Table(name = "t_user") // 对应数据库中的表名
public class User implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID (BIG SERIAL)
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
/**
* 用户名 (VARCHAR(60) NOT NULL UNIQUE)
*/
@Column(name = "username", length = 60, nullable = false, unique = true)
private String username;
/**
* 密码 (VARCHAR(60) NOT NULL)
*/
@Column(name = "password", length = 60, nullable = false)
private String password;
/**
* 创建时间 (TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW())
* 使用 Hibernate 的 @CreationTimestamp 确保创建时自动赋值
*/
@CreationTimestamp
@Column(name = "create_time", nullable = false, updatable = false)
private Instant createTime;
/**
* 最后一次更新时间 (TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW())
* 使用 Hibernate 的 @UpdateTimestamp 确保更新时自动赋值
* 注意:虽然数据库有触发器,但使用此注解可保持 ORM 层的同步性
*/
@UpdateTimestamp
@Column(name = "update_time", nullable = false)
private Instant updateTime;
/**
* 逻辑删除FALSE未删除 TRUE已删除 (BOOLEAN NOT NULL DEFAULT FALSE)
*/
@Builder.Default
@Column(name = "is_deleted", nullable = false)
private Boolean isDeleted = false; // 对应数据库默认值
public User() {
}
public User(Long id, String username, String password, Instant createTime, Instant updateTime, Boolean isDeleted) {
this.id = id;
this.username = username;
this.password = password;
this.createTime = createTime;
this.updateTime = updateTime;
this.isDeleted = isDeleted;
}
}

View File

@@ -0,0 +1,7 @@
package com.hanserwei.common.domain.repository;
import com.hanserwei.common.domain.dataobject.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}

View File

@@ -9,7 +9,6 @@ dependencies {
// Spring Boot Web示例 // Spring Boot Web示例
implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-web")
// Test // Test
testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.boot:spring-boot-starter-test")

View File

@@ -2,10 +2,12 @@ package com.hanserwei.web;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan; import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication @SpringBootApplication(scanBasePackages = "com.hanserwei")
@ComponentScan({"com.hanserwei.*"}) @EnableJpaRepositories(basePackages = "com.hanserwei.common.domain.repository")
@EntityScan(basePackages = "com.hanserwei.common.domain.dataobject")
public class WeblogWebApplication { public class WeblogWebApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(WeblogWebApplication.class, args); SpringApplication.run(WeblogWebApplication.class, args);

View File

@@ -1,13 +1,19 @@
package com.hanserwei.web; package com.hanserwei.web;
import com.hanserwei.common.domain.dataobject.User;
import com.hanserwei.common.domain.repository.UserRepository;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import lombok.extern.slf4j.Slf4j;
@SpringBootTest
@Slf4j @Slf4j
@SpringBootTest
class WeblogWebApplicationTests { class WeblogWebApplicationTests {
@Resource
private UserRepository userRepository;
@Test @Test
void contextLoads() { void contextLoads() {
} }
@@ -23,4 +29,15 @@ class WeblogWebApplicationTests {
log.info("这是一行带有占位符日志,作者:{}", author); log.info("这是一行带有占位符日志,作者:{}", author);
} }
@Test
void insertTest() {
User user = User.builder()
.username("Hanserwei")
.password("123456")
.build();
// 使用jpa插入数据
User savedUser = userRepository.save(user); // 保存并获取返回的实体
userRepository.flush(); // 强制同步到数据库
}
} }