feat(admin): implement category management functionality
- Added AddCategoryReqVO for category creation with validation - Created AdminCategoryController with endpoints for add, list, delete and select operations - Implemented AdminCategoryService interface and its methods - Added Category entity with JPA annotations and logical delete support - Created CategoryRepository extending JpaRepository with custom query methods - Added SQL table creation script for t_category with indexes and constraints - Implemented PageResponse utility for handling paginated results - Added FindCategoryPageListReqVO and FindCategoryPageListRspVO for pagination - Included DeleteCategoryReqVO for category deletion requests - Updated Jackson configuration to ignore unknown properties - Added base page query model and user info response VO - Fixed typo in response code enum for user not exist error
This commit is contained in:
9
.idea/ApifoxUploaderProjectSetting.xml
generated
9
.idea/ApifoxUploaderProjectSetting.xml
generated
@@ -1,6 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ApifoxUploaderProjectSetting">
|
||||
<option name="apiAccessToken" value="APS-mJ5jVj0KjHRVPvJnChI91r8WFqR0oXhE" />
|
||||
<option name="apiAccessToken" value="APS-nkhftrUwkg4bhzK4DRYUNguJFix8j1fd" />
|
||||
<option name="apiProjectIds">
|
||||
<array>
|
||||
<option value="<byte-array>rO0ABXNyADZjb20uaXRhbmdjZW50LmlkZWEucGx1Z2luLmFwaS5hY2NvdW50LlByb2plY3RBbmRNb2R1bGUAAAAAAAAAAQIAFVoABmVuYWJsZUwACG1vZHVsZUlkdAASTGphdmEvbGFuZy9TdHJpbmc7TAAGb3RoZXIxcQB+AAFMAAdvdGhlcjEwcQB+AAFMAAdvdGhlcjExcQB+AAFMAAdvdGhlcjEycQB+AAFMAAZvdGhlcjJxAH4AAUwABm90aGVyM3EAfgABTAAGb3RoZXI0cQB+AAFMAAZvdGhlcjVxAH4AAUwABm90aGVyNnEAfgABTAAGb3RoZXI3cQB+AAFMAAZvdGhlcjhxAH4AAUwABm90aGVyOXEAfgABTAAKcGF0aEJlZm9yZXEAfgABTAANcHJvamVjdEZvbGRlcnEAfgABTAAPcHJvamVjdEZvbGRlcklkcQB+AAFMAAlwcm9qZWN0SWRxAH4AAUwAC3Byb2plY3ROYW1lcQB+AAFMAAxzY2hlbWFGb2xkZXJxAH4AAUwACHNjaGVtYUlkcQB+AAF4cAF0ACp3ZWJsb2ctc3ByaW5nYm9vdC53ZWJsb2ctbW9kdWxlLWFkbWluLm1haW50AAc3MjIwMjQ1cHBwdAAHNjY1NzM5NHQAC2JyYW5jaC1tYWludAAM6buY6K6k5qih5Z2XcHBwcHB0AAB0AAnmoLnnm67lvZV0AAEwdAAHNzQ4NDkxM3QABVdCbG9ncQB+AAlxAH4ACg==</byte-array>" />
|
||||
</array>
|
||||
</option>
|
||||
<option name="treeNodes" value="<byte-array>rO0ABXNyABdqYXZhLnV0aWwuTGlua2VkSGFzaE1hcDTATlwQbMD7AgABWgALYWNjZXNzT3JkZXJ4cgARamF2YS51dGlsLkhhc2hNYXAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hvbGR4cD9AAAAAAAAMdwgAAAAQAAAAAnQABzM0MjU5MzBzcgAuY29tLml0YW5nY2VudC5pZGVhLnBsdWdpbi5hcGkuYWNjb3VudC5UcmVlTm9kZQAAAAAAAAABAgAQTAAHYWxsUGF0aHQAEkxqYXZhL2xhbmcvU3RyaW5nO1sAFGJyYW5jaEFuZFZlcnNpb25JdGVtdABLW0xjb20vaXRhbmdjZW50L2lkZWEvcGx1Z2luL2RpYWxvZy9jb21wb25lbnQvYWNjb3VudC9BY2NvdW50UmlnaHRQYW5lbEl0ZW07TAAUYnJhbmNoSWRBbmRWZXJzaW9uSWRxAH4ABUwACGNoaWxkcmVudAAPTGphdmEvdXRpbC9NYXA7TAAKZm9sZGVyVHlwZXEAfgAFTAAIZnVsbFBhdGhxAH4ABUwAA2tleXEAfgAFWwAJbW9kZWxJdGVtcQB+AAZMAAhtb2R1bGVJZHEAfgAFTAAEbmFtZXEAfgAFTAAIcGFyZW50SWRxAH4ABUwACXByb2plY3RJZHEAfgAFTAALcHJvamVjdE5hbWVxAH4ABUwABnRlYW1JZHEAfgAFTAAIdGVhbU5hbWVxAH4ABUwABHR5cGV0ADBMY29tL2l0YW5nY2VudC9pZGVhL3BsdWdpbi9hcGkvYWNjb3VudC9Ob2RlVHlwZTt4cHQADOS4quS6uuWboumYn3Bwc3EAfgAAP0AAAAAAAAx3CAAAABAAAAABdAAHNzQ4NDkxM3NxAH4ABHQAEuS4quS6uuWboumYny9XQmxvZ3Bwc3EAfgAAP0AAAAAAAAB3CAAAABAAAAAAeABwcHEAfgAMcHB0AA9XQmxvZyAoNzQ4NDkxMyl0AAczNDI1OTMwcQB+AAx0AAVXQmxvZ3EAfgARcH5yAC5jb20uaXRhbmdjZW50LmlkZWEucGx1Z2luLmFwaS5hY2NvdW50Lk5vZGVUeXBlAAAAAAAAAAASAAB4cgAOamF2YS5sYW5nLkVudW0AAAAAAAAAABIAAHhwdAAHUFJPSkVDVHgAcHBxAH4AA3BwcQB+AApwcHBxAH4AA3EAfgAKfnEAfgATdAAEVEVBTXQABzM5NjY0MDlzcQB+AAR0AAlIYW5zZXJEZXZwcHNxAH4AAD9AAAAAAAAMdwgAAAAQAAAAAXQABzc0NjI0NzJzcQB+AAR0ABlIYW5zZXJEZXYvSU4tQUktaW50ZXJ2aWV3cHBzcQB+AAA/QAAAAAAAAHcIAAAAEAAAAAB4AHBwcQB+AB1wcHQAGUlOLUFJLWludGVydmlldyAoNzQ2MjQ3Mil0AAczOTY2NDA5cQB+AB10AA9JTi1BSS1pbnRlcnZpZXdxAH4AInBxAH4AFXgAcHBxAH4AGXBwcQB+ABtwcHBxAH4AGXEAfgAbcQB+ABd4AA==</byte-array>" />
|
||||
<option name="treeNodesJTree" value="<byte-array>rO0ABXNyACFqYXZheC5zd2luZy50cmVlLkRlZmF1bHRUcmVlTW9kZWynvpEmGsXl2QMAA1oAEmFza3NBbGxvd3NDaGlsZHJlbkwADGxpc3RlbmVyTGlzdHQAJUxqYXZheC9zd2luZy9ldmVudC9FdmVudExpc3RlbmVyTGlzdDtMAARyb290dAAbTGphdmF4L3N3aW5nL3RyZWUvVHJlZU5vZGU7eHAAc3IAI2phdmF4LnN3aW5nLmV2ZW50LkV2ZW50TGlzdGVuZXJMaXN0kUjMLXPfDt4DAAB4cHB4c3IAJ2phdmF4LnN3aW5nLnRyZWUuRGVmYXVsdE11dGFibGVUcmVlTm9kZcRYv/zyqHHgAwADWgAOYWxsb3dzQ2hpbGRyZW5MAAhjaGlsZHJlbnQAEkxqYXZhL3V0aWwvVmVjdG9yO0wABnBhcmVudHQAIkxqYXZheC9zd2luZy90cmVlL011dGFibGVUcmVlTm9kZTt4cAFzcgAQamF2YS51dGlsLlZlY3RvctmXfVuAO68BAwADSQARY2FwYWNpdHlJbmNyZW1lbnRJAAxlbGVtZW50Q291bnRbAAtlbGVtZW50RGF0YXQAE1tMamF2YS9sYW5nL09iamVjdDt4cAAAAAAAAAACdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAACnNxAH4ABgFzcQB+AAoAAAAAAAAAAXVxAH4ADQAAAApzcQB+AAYBcHEAfgAPdXEAfgANAAAAAnQACnVzZXJPYmplY3RzcgAuY29tLml0YW5nY2VudC5pZGVhLnBsdWdpbi5hcGkuYWNjb3VudC5UcmVlTm9kZQAAAAAAAAABAgAQTAAHYWxsUGF0aHQAEkxqYXZhL2xhbmcvU3RyaW5nO1sAFGJyYW5jaEFuZFZlcnNpb25JdGVtdABLW0xjb20vaXRhbmdjZW50L2lkZWEvcGx1Z2luL2RpYWxvZy9jb21wb25lbnQvYWNjb3VudC9BY2NvdW50UmlnaHRQYW5lbEl0ZW07TAAUYnJhbmNoSWRBbmRWZXJzaW9uSWRxAH4AFkwACGNoaWxkcmVudAAPTGphdmEvdXRpbC9NYXA7TAAKZm9sZGVyVHlwZXEAfgAWTAAIZnVsbFBhdGhxAH4AFkwAA2tleXEAfgAWWwAJbW9kZWxJdGVtcQB+ABdMAAhtb2R1bGVJZHEAfgAWTAAEbmFtZXEAfgAWTAAIcGFyZW50SWRxAH4AFkwACXByb2plY3RJZHEAfgAWTAALcHJvamVjdE5hbWVxAH4AFkwABnRlYW1JZHEAfgAWTAAIdGVhbU5hbWVxAH4AFkwABHR5cGV0ADBMY29tL2l0YW5nY2VudC9pZGVhL3BsdWdpbi9hcGkvYWNjb3VudC9Ob2RlVHlwZTt4cHQAEuS4quS6uuWboumYny9XQmxvZ3VyAEtbTGNvbS5pdGFuZ2NlbnQuaWRlYS5wbHVnaW4uZGlhbG9nLmNvbXBvbmVudC5hY2NvdW50LkFjY291bnRSaWdodFBhbmVsSXRlbTspvFKeKrgMqQIAAHhwAAAAAXNyAEhjb20uaXRhbmdjZW50LmlkZWEucGx1Z2luLmRpYWxvZy5jb21wb25lbnQuYWNjb3VudC5BY2NvdW50UmlnaHRQYW5lbEl0ZW0AAAAAAAAAAQIABFoAD2lzTWFpbk9yRGVmYXVsdEwACGljb25UeXBlcQB+ABZMAAJpZHEAfgAWTAAEbmFtZXEAfgAWeHABdAAGYnJhbmNodAAHNzIyMDI0NXQABG1haW5wc3IAF2phdmEudXRpbC5MaW5rZWRIYXNoTWFwNMBOXBBswPsCAAFaAAthY2Nlc3NPcmRlcnhyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAB3CAAAABAAAAAAeABwcHQABzc0ODQ5MTN1cQB+ABwAAAABc3EAfgAeAXQABW1vZGVsdAAHNjY1NzM5NHQADOm7mOiupOaooeWdl3B0AA9XQmxvZyAoNzQ4NDkxMyl0AAczNDI1OTMwdAAHNzQ4NDkxM3QABVdCbG9ndAAHMzQyNTkzMHB+cgAuY29tLml0YW5nY2VudC5pZGVhLnBsdWdpbi5hcGkuYWNjb3VudC5Ob2RlVHlwZQAAAAAAAAAAEgAAeHIADmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQAB1BST0pFQ1R4cHBwcHBwcHBweHEAfgAJdXEAfgANAAAAAnEAfgAUc3EAfgAVdAAM5Liq5Lq65Zui6ZifcHBzcQB+ACM/QAAAAAAAAHcIAAAAEAAAAAB4AHBwdAAHMzQyNTkzMHBwdAAM5Liq5Lq65Zui6ZifcHBwdAAHMzQyNTkzMHQADOS4quS6uuWboumYn35xAH4AMXQABFRFQU14c3EAfgAGAXNxAH4ACgAAAAAAAAABdXEAfgANAAAACnNxAH4ABgFwcQB+AD91cQB+AA0AAAACcQB+ABRzcQB+ABV0ABlIYW5zZXJEZXYvSU4tQUktaW50ZXJ2aWV3cHBzcQB+ACM/QAAAAAAAAHcIAAAAEAAAAAB4AHBwdAAHNzQ2MjQ3MnBwdAAZSU4tQUktaW50ZXJ2aWV3ICg3NDYyNDcyKXQABzM5NjY0MDl0AAc3NDYyNDcydAAPSU4tQUktaW50ZXJ2aWV3dAAHMzk2NjQwOXBxAH4AM3hwcHBwcHBwcHB4cQB+AAl1cQB+AA0AAAACcQB+ABRzcQB+ABV0AAlIYW5zZXJEZXZwcHNxAH4AIz9AAAAAAAAAdwgAAAAQAAAAAHgAcHB0AAczOTY2NDA5cHB0AAlIYW5zZXJEZXZwcHB0AAczOTY2NDA5dAAJSGFuc2VyRGV2cQB+AD14cHBwcHBwcHB4cHVxAH4ADQAAAAJxAH4AFHNxAH4AFXQABFJvb3RwcHBwcHQAATBwcHEAfgBXcHBwcHBxAH4APXhzcQB+AAoAAAAAAAAAAnVxAH4ADQAAAAp0AARyb290cQB+AAlwcHBwcHBwcHh4</byte-array>" />
|
||||
</component>
|
||||
</project>
|
||||
1
.idea/data_source_mapping.xml
generated
1
.idea/data_source_mapping.xml
generated
@@ -2,5 +2,6 @@
|
||||
<project version="4">
|
||||
<component name="DataSourcePerFileMappings">
|
||||
<file url="file://$PROJECT_DIR$/sql/createTable.sql" value="bb8330e4-9a89-4978-ad63-ad6402096c16" />
|
||||
<file url="file://$PROJECT_DIR$/weblog-module-common/src/main/java/com/hanserwei/common/domain/dataobject/Category.java" value="bb8330e4-9a89-4978-ad63-ad6402096c16" />
|
||||
</component>
|
||||
</project>
|
||||
1
.idea/sqldialects.xml
generated
1
.idea/sqldialects.xml
generated
@@ -2,6 +2,5 @@
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/sql/createTable.sql" dialect="PostgreSQL" />
|
||||
<file url="PROJECT" dialect="PostgreSQL" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -40,11 +40,59 @@ CREATE TABLE t_user_role
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
username VARCHAR(60) NOT NULL,
|
||||
role_name VARCHAR(60) NOT NULL, -- 重命名为 role_name 避免关键字冲突
|
||||
create_time TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_username ON t_user_role (username);
|
||||
|
||||
COMMENT ON COLUMN t_user_role.role_name IS '角色名称';
|
||||
-- 为 t_user_role 表创建触发器
|
||||
CREATE TRIGGER set_t_user_role_update_time
|
||||
BEFORE UPDATE
|
||||
ON t_user_role
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_update_time();
|
||||
-- ====================================================================================================================
|
||||
-- ====================================================================================================================
|
||||
|
||||
-- ====================================================================================================================
|
||||
-- ====================================================================================================================
|
||||
CREATE TABLE t_category
|
||||
(
|
||||
-- id:对应 MySQL 的 bigint(20) unsigned NOT NULL AUTO_INCREMENT
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
|
||||
-- 分类名称:VARCHAR(60) NOT NULL DEFAULT '',同时是 UNIQUE 约束
|
||||
"name" VARCHAR(60) NOT NULL DEFAULT '',
|
||||
|
||||
-- 创建时间
|
||||
create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
||||
|
||||
-- 最后一次更新时间
|
||||
update_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
||||
|
||||
-- 逻辑删除标志位:tinyint(2) NOT NULL DEFAULT '0',改为 BOOLEAN
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- UNIQUE KEY uk_name (`name`)
|
||||
CONSTRAINT uk_name UNIQUE ("name")
|
||||
);
|
||||
|
||||
-- 添加非唯一索引(对应 MySQL 的 KEY `idx_create_time`)
|
||||
CREATE INDEX idx_create_time ON t_category (create_time);
|
||||
|
||||
-- 可选:添加注释
|
||||
COMMENT ON TABLE t_category IS '文章分类表';
|
||||
COMMENT ON COLUMN t_category.id IS '分类id';
|
||||
COMMENT ON COLUMN t_category.name IS '分类名称';
|
||||
COMMENT ON COLUMN t_category.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN t_category.update_time IS '最后一次更新时间';
|
||||
COMMENT ON COLUMN t_category.is_deleted IS '逻辑删除标志位:FALSE:未删除 TRUE:已删除';
|
||||
-- 为 t_category 表创建触发器
|
||||
CREATE TRIGGER set_t_category_update_time
|
||||
BEFORE UPDATE
|
||||
ON t_category
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_update_time();
|
||||
-- ====================================================================================================================
|
||||
-- ====================================================================================================================
|
||||
@@ -8,6 +8,7 @@ dependencies {
|
||||
implementation(project(":weblog-module-common"))
|
||||
|
||||
api(project(":weblog-module-jwt"))
|
||||
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
testImplementation("org.springframework.security:spring-security-test")
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.hanserwei.admin.controller;
|
||||
|
||||
import com.hanserwei.admin.model.vo.AddCategoryReqVO;
|
||||
import com.hanserwei.admin.model.vo.DeleteCategoryReqVO;
|
||||
import com.hanserwei.admin.model.vo.FindCategoryPageListReqVO;
|
||||
import com.hanserwei.admin.model.vo.FindCategoryPageListRspVO;
|
||||
import com.hanserwei.admin.service.AdminCategoryService;
|
||||
import com.hanserwei.common.aspect.ApiOperationLog;
|
||||
import com.hanserwei.common.model.vo.SelectRspVO;
|
||||
import com.hanserwei.common.utils.PageResponse;
|
||||
import com.hanserwei.common.utils.Response;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 管理端分类控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/admin")
|
||||
public class AdminCategoryController {
|
||||
|
||||
@Resource
|
||||
private AdminCategoryService adminCategoryService;
|
||||
|
||||
/**
|
||||
* 添加分类
|
||||
*/
|
||||
@PostMapping("/category/add")
|
||||
@ApiOperationLog(description = "添加分类")
|
||||
public Response<?> addCategory(@RequestBody @Validated AddCategoryReqVO addCategoryReqVO) {
|
||||
return adminCategoryService.addCategory(addCategoryReqVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分类分页数据获取
|
||||
*/
|
||||
@PostMapping("/category/list")
|
||||
@ApiOperationLog(description = "分类分页数据获取")
|
||||
public PageResponse<FindCategoryPageListRspVO> findCategoryList(@RequestBody @Validated FindCategoryPageListReqVO findCategoryPageListReqVO) {
|
||||
return adminCategoryService.findCategoryList(findCategoryPageListReqVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除分类
|
||||
*/
|
||||
@PostMapping("/category/delete")
|
||||
@ApiOperationLog(description = "删除分类")
|
||||
public Response<?> deleteCategory(@RequestBody @Validated DeleteCategoryReqVO deleteCategoryReqVO) {
|
||||
return adminCategoryService.deleteCategory(deleteCategoryReqVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分类下拉列表
|
||||
*/
|
||||
@PostMapping("/category/select/list")
|
||||
@ApiOperationLog(description = "分类 Select 下拉列表数据获取")
|
||||
public Response<List<SelectRspVO>> findCategorySelectList() {
|
||||
return adminCategoryService.findCategorySelectList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.hanserwei.admin.controller;
|
||||
|
||||
import com.hanserwei.admin.model.vo.FindUserInfoRspVO;
|
||||
import com.hanserwei.admin.model.vo.UpdateAdminUserPasswordReqVO;
|
||||
import com.hanserwei.admin.service.AdminUserService;
|
||||
import com.hanserwei.common.aspect.ApiOperationLog;
|
||||
import com.hanserwei.common.utils.Response;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 管理端用户控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/admin")
|
||||
public class AdminUserController {
|
||||
|
||||
@Resource
|
||||
private AdminUserService adminUserService;
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*/
|
||||
@PostMapping("/password/update")
|
||||
@ApiOperationLog(description = "修改用户密码")
|
||||
public Response<?> updatePassword(@RequestBody @Validated UpdateAdminUserPasswordReqVO updateAdminUserPasswordReqVO) {
|
||||
return adminUserService.updatePassword(updateAdminUserPasswordReqVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
@PostMapping("/user/info")
|
||||
@ApiOperationLog(description = "获取用户信息")
|
||||
public Response<FindUserInfoRspVO> findUserInfo() {
|
||||
return adminUserService.findUserInfo();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.hanserwei.admin.model.vo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class AddCategoryReqVO {
|
||||
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
@NotBlank(message = "分类名称不能为空")
|
||||
@Length(min = 1, max = 10, message = "分类名称字数限制 1 ~ 10 之间")
|
||||
private String name;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.hanserwei.admin.model.vo;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class DeleteCategoryReqVO {
|
||||
|
||||
@NotNull(message = "分类 ID 不能为空")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.hanserwei.admin.model.vo;
|
||||
|
||||
import com.hanserwei.common.model.BasePageQuery;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class FindCategoryPageListReqVO extends BasePageQuery {
|
||||
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 创建的起始日期
|
||||
*/
|
||||
private LocalDate startDate;
|
||||
|
||||
/**
|
||||
* 创建的结束日期
|
||||
*/
|
||||
private LocalDate endDate;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.hanserwei.admin.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class FindCategoryPageListRspVO {
|
||||
/**
|
||||
* 分类 ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.hanserwei.admin.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class FindUserInfoRspVO {
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.hanserwei.admin.model.vo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class UpdateAdminUserPasswordReqVO {
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 新密码
|
||||
*/
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.hanserwei.admin.service;
|
||||
|
||||
import com.hanserwei.admin.model.vo.AddCategoryReqVO;
|
||||
import com.hanserwei.admin.model.vo.DeleteCategoryReqVO;
|
||||
import com.hanserwei.admin.model.vo.FindCategoryPageListReqVO;
|
||||
import com.hanserwei.admin.model.vo.FindCategoryPageListRspVO;
|
||||
import com.hanserwei.common.model.vo.SelectRspVO;
|
||||
import com.hanserwei.common.utils.PageResponse;
|
||||
import com.hanserwei.common.utils.Response;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AdminCategoryService {
|
||||
/**
|
||||
* 添加分类
|
||||
*
|
||||
* @param addCategoryReqVO 添加分类请求参数
|
||||
* @return 添加结果
|
||||
*/
|
||||
Response<?> addCategory(AddCategoryReqVO addCategoryReqVO);
|
||||
|
||||
/**
|
||||
* 分类分页数据查询
|
||||
*
|
||||
* @param findCategoryPageListReqVO 分页查询分类参数
|
||||
* @return 查询结果
|
||||
*/
|
||||
PageResponse<FindCategoryPageListRspVO> findCategoryList(FindCategoryPageListReqVO findCategoryPageListReqVO);
|
||||
|
||||
/**
|
||||
* 删除分类
|
||||
*
|
||||
* @param deleteCategoryReqVO 删除分类参数
|
||||
* @return 删除结果
|
||||
*/
|
||||
Response<?> deleteCategory(DeleteCategoryReqVO deleteCategoryReqVO);
|
||||
|
||||
/**
|
||||
* 获取文章分类的 Select 列表数据
|
||||
*
|
||||
* @return Select 列表数据
|
||||
*/
|
||||
Response<List<SelectRspVO>> findCategorySelectList();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.hanserwei.admin.service;
|
||||
|
||||
import com.hanserwei.admin.model.vo.FindUserInfoRspVO;
|
||||
import com.hanserwei.admin.model.vo.UpdateAdminUserPasswordReqVO;
|
||||
import com.hanserwei.common.utils.Response;
|
||||
|
||||
public interface AdminUserService {
|
||||
/**
|
||||
* 修改密码
|
||||
* @param updateAdminUserPasswordReqVO 修改密码参数
|
||||
* @return 修改密码结果
|
||||
*/
|
||||
Response<?> updatePassword(UpdateAdminUserPasswordReqVO updateAdminUserPasswordReqVO);
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
* @return 当前登录用户信息
|
||||
*/
|
||||
Response<FindUserInfoRspVO> findUserInfo();
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.hanserwei.admin.service.impl;
|
||||
|
||||
import com.hanserwei.admin.model.vo.AddCategoryReqVO;
|
||||
import com.hanserwei.admin.model.vo.DeleteCategoryReqVO;
|
||||
import com.hanserwei.admin.model.vo.FindCategoryPageListReqVO;
|
||||
import com.hanserwei.admin.model.vo.FindCategoryPageListRspVO;
|
||||
import com.hanserwei.admin.service.AdminCategoryService;
|
||||
import com.hanserwei.common.domain.dataobject.Category;
|
||||
import com.hanserwei.common.domain.repository.CategoryRepository;
|
||||
import com.hanserwei.common.enums.ResponseCodeEnum;
|
||||
import com.hanserwei.common.exception.BizException;
|
||||
import com.hanserwei.common.model.vo.SelectRspVO;
|
||||
import com.hanserwei.common.utils.PageResponse;
|
||||
import com.hanserwei.common.utils.Response;
|
||||
import io.jsonwebtoken.lang.Strings;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class AdminCategoryServiceImpl implements AdminCategoryService {
|
||||
|
||||
@Resource
|
||||
private CategoryRepository categoryRepository;
|
||||
|
||||
@Override
|
||||
public Response<?> addCategory(AddCategoryReqVO addCategoryReqVO) {
|
||||
String categoryName = addCategoryReqVO.getName();
|
||||
// 先判断是否存在
|
||||
if (categoryRepository.existsCategoryByName(categoryName)) {
|
||||
throw new BizException(ResponseCodeEnum.CATEGORY_NAME_IS_EXISTED);
|
||||
}
|
||||
// 构造Category对象
|
||||
Category category = Category.builder()
|
||||
.name(categoryName)
|
||||
.build();
|
||||
categoryRepository.save(category);
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResponse<FindCategoryPageListRspVO> findCategoryList(FindCategoryPageListReqVO findCategoryPageListReqVO) {
|
||||
Long current = findCategoryPageListReqVO.getCurrent();
|
||||
Long size = findCategoryPageListReqVO.getSize();
|
||||
|
||||
Pageable pageable = PageRequest.of(current.intValue() - 1,
|
||||
size.intValue(),
|
||||
Sort.by(Sort.Direction.DESC, "createTime"));
|
||||
|
||||
// 构建查询条件
|
||||
Specification<Category> specification = (root, query, criteriaBuilder) -> {
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
String name = findCategoryPageListReqVO.getName();
|
||||
if (Strings.hasText(name)) {
|
||||
predicates.add(
|
||||
criteriaBuilder.like(root.get("name"), "%" + name.trim() + "%")
|
||||
);
|
||||
}
|
||||
if (Objects.nonNull(findCategoryPageListReqVO.getStartDate())){
|
||||
predicates.add(
|
||||
criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), findCategoryPageListReqVO.getStartDate())
|
||||
);
|
||||
}
|
||||
if (Objects.nonNull(findCategoryPageListReqVO.getEndDate())) {
|
||||
predicates.add(
|
||||
criteriaBuilder.lessThan(root.get("createTime"), findCategoryPageListReqVO.getEndDate().plusDays(1).atStartOfDay())
|
||||
);
|
||||
}
|
||||
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
|
||||
};
|
||||
|
||||
Page<Category> categoryDOPage = categoryRepository.findAll(specification, pageable);
|
||||
|
||||
List<FindCategoryPageListRspVO> vos = categoryDOPage.getContent().stream()
|
||||
.map(category -> FindCategoryPageListRspVO.builder()
|
||||
.id(category.getId())
|
||||
.name(category.getName())
|
||||
.createTime(LocalDateTime.ofInstant(category.getCreateTime(), ZoneId.systemDefault()))
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return PageResponse.success(categoryDOPage, vos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<?> deleteCategory(DeleteCategoryReqVO deleteCategoryReqVO) {
|
||||
Long id = deleteCategoryReqVO.getId();
|
||||
categoryRepository.deleteById(id);
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<List<SelectRspVO>> findCategorySelectList() {
|
||||
List<Category> categoryList = categoryRepository.findAll();
|
||||
// DO 转 VO
|
||||
List<SelectRspVO> selectRspVOS = null;
|
||||
if (!CollectionUtils.isEmpty(categoryList)){
|
||||
selectRspVOS = categoryList.stream()
|
||||
.map(category -> SelectRspVO.builder()
|
||||
.label(category.getName())
|
||||
.value(category.getId())
|
||||
.build())
|
||||
.toList();
|
||||
}
|
||||
return Response.success(selectRspVOS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.hanserwei.admin.service.impl;
|
||||
|
||||
import com.hanserwei.admin.model.vo.FindUserInfoRspVO;
|
||||
import com.hanserwei.admin.model.vo.UpdateAdminUserPasswordReqVO;
|
||||
import com.hanserwei.admin.service.AdminUserService;
|
||||
import com.hanserwei.common.domain.repository.UserRepository;
|
||||
import com.hanserwei.common.enums.ResponseCodeEnum;
|
||||
import com.hanserwei.common.exception.BizException;
|
||||
import com.hanserwei.common.utils.Response;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AdminUserServiceImpl implements AdminUserService {
|
||||
|
||||
@Resource
|
||||
private UserRepository userRepository;
|
||||
@Resource
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
public Response<?> updatePassword(UpdateAdminUserPasswordReqVO updateAdminUserPasswordReqVO) {
|
||||
// 拿到用户名密码
|
||||
String username = updateAdminUserPasswordReqVO.getUsername();
|
||||
String password = updateAdminUserPasswordReqVO.getPassword();
|
||||
|
||||
// 加密密码
|
||||
String encodePassword = passwordEncoder.encode(password);
|
||||
|
||||
int updatedRows = userRepository.updatePasswordByUsername(username, encodePassword);
|
||||
|
||||
if (updatedRows == 0) {
|
||||
// 如果更新行数为 0,说明用户名不存在
|
||||
throw new BizException(ResponseCodeEnum.USER_NOT_EXIST);
|
||||
}
|
||||
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<FindUserInfoRspVO> findUserInfo() {
|
||||
// 获取存储在 ThreadLocal 中的用户信息
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
// 拿到用户名
|
||||
String username = authentication.getName();
|
||||
return Response.success(new FindUserInfoRspVO(username));
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,8 @@ public class JacksonConfig {
|
||||
|
||||
// 设置凡是为 null 的字段,返参中均不返回,请根据项目组约定是否开启
|
||||
// objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
// 忽略未知属性
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.hanserwei.common.domain.dataobject;
|
||||
|
||||
import jakarta.persistence.*; // 使用 Jakarta Persistence API (JPA 3.0+)
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import org.hibernate.annotations.*;
|
||||
import lombok.*; // 引入所有 Lombok 注解
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* 文章分类表(t_category 对应实体)
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Entity
|
||||
@Table(name = "t_category",
|
||||
uniqueConstraints = {
|
||||
@UniqueConstraint(name = "uk_name", columnNames = {"name"})
|
||||
},
|
||||
indexes = {
|
||||
@Index(name = "idx_create_time", columnList = "create_time")
|
||||
})
|
||||
@SQLRestriction("is_deleted = false")
|
||||
@SQLDelete(sql = "UPDATE t_category SET is_deleted = true WHERE id = ?")
|
||||
public class Category implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 分类ID (BIG SERIAL PRIMARY KEY)
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 分类名称 (VARCHAR(60) NOT NULL DEFAULT '')
|
||||
*/
|
||||
@Column(name = "name", length = 60, nullable = false)
|
||||
private String name = ""; // 对应数据库的 DEFAULT ''
|
||||
|
||||
/**
|
||||
* 创建时间 (TIMESTAMP WITHOUT TIME ZONE NOT NULL)
|
||||
*/
|
||||
@CreationTimestamp
|
||||
@Column(name = "create_time", nullable = false, updatable = false)
|
||||
private Instant createTime;
|
||||
|
||||
/**
|
||||
* 最后一次更新时间 (TIMESTAMP WITHOUT TIME ZONE NOT NULL)
|
||||
* 配合数据库触发器或 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;
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.SQLDelete;
|
||||
import org.hibernate.annotations.SQLRestriction;
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
|
||||
import java.io.Serial;
|
||||
@@ -18,7 +20,9 @@ import java.time.Instant; // 推荐用于 TIMESTAMP WITH TIME ZONE
|
||||
@Setter
|
||||
@Getter
|
||||
@Builder
|
||||
@Table(name = "t_user") // 对应数据库中的表名
|
||||
@Table(name = "t_user")
|
||||
@SQLRestriction("is_deleted = false")
|
||||
@SQLDelete(sql = "UPDATE t_user SET is_deleted = true WHERE id = ?")
|
||||
public class User implements Serializable {
|
||||
|
||||
@Serial
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.hanserwei.common.domain.repository;
|
||||
|
||||
import com.hanserwei.common.domain.dataobject.Category;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface CategoryRepository extends JpaRepository<Category, Long> {
|
||||
boolean existsCategoryByName(String name);
|
||||
|
||||
Page<Category> findAll(Specification<Category> specification, Pageable pageable);
|
||||
}
|
||||
@@ -2,7 +2,17 @@ package com.hanserwei.common.domain.repository;
|
||||
|
||||
import com.hanserwei.common.domain.dataobject.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
User getUsersByUsername(String username);
|
||||
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE User u SET u.password = :newPassword WHERE u.username = :username")
|
||||
int updatePasswordByUsername(@Param("username") String username,
|
||||
@Param("newPassword") String newPassword);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ public enum ResponseCodeEnum implements BaseExceptionInterface {
|
||||
LOGIN_FAIL("20000", "登录失败"),
|
||||
USERNAME_OR_PWD_ERROR("20001", "用户名或密码错误"),
|
||||
UNAUTHORIZED("20002", "无访问权限,请先登录!"),
|
||||
FORBIDDEN("20004", "演示账号仅支持查询操作!")
|
||||
FORBIDDEN("20004", "演示账号仅支持查询操作!"),
|
||||
USER_NOT_EXIST("2005", "有户不存在!"),
|
||||
CATEGORY_NAME_IS_EXISTED("20005", "该分类已存在,请勿重复添加!")
|
||||
;
|
||||
|
||||
// 异常码
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.hanserwei.common.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BasePageQuery {
|
||||
/**
|
||||
* 当前页码, 默认第一页
|
||||
*/
|
||||
private Long current = 1L;
|
||||
/**
|
||||
* 每页展示的数据数量,默认每页展示 10 条数据
|
||||
*/
|
||||
private Long size = 10L;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.hanserwei.common.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class SelectRspVO {
|
||||
/**
|
||||
* Select 下拉列表的展示文字
|
||||
*/
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* Select 下拉列表的 value 值,如 ID 等
|
||||
*/
|
||||
private Object value;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.hanserwei.common.utils;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class PageResponse<T> extends Response<List<T>> {
|
||||
|
||||
/**
|
||||
* 总记录数
|
||||
*/
|
||||
private long total = 0L;
|
||||
|
||||
/**
|
||||
* 每页显示的记录数,默认每页显示 10 条
|
||||
*/
|
||||
private long size = 10L;
|
||||
|
||||
/**
|
||||
* 当前页码 (JPA Page 从 0 开始, 这里为方便前端, 统一改为从 1 开始)
|
||||
*/
|
||||
private long current;
|
||||
|
||||
/**
|
||||
* 总页数
|
||||
*/
|
||||
private long pages;
|
||||
|
||||
/**
|
||||
* 成功响应
|
||||
*
|
||||
* @param page Spring Data JPA 提供的分页接口
|
||||
* @param <T> 响应数据类型
|
||||
*/
|
||||
public static <T> PageResponse<T> success(Page<T> page) {
|
||||
PageResponse<T> response = new PageResponse<>();
|
||||
response.setSuccess(true);
|
||||
|
||||
if (Objects.nonNull(page)) {
|
||||
// JPA Page 的 getNumber() 是当前页码 (从 0 开始), 我们在返回时通常习惯改为从 1 开始
|
||||
response.setCurrent(page.getNumber() + 1);
|
||||
// JPA Page 的 getSize() 是每页大小
|
||||
response.setSize(page.getSize());
|
||||
// JPA Page 的 getTotalPages() 是总页数
|
||||
response.setPages(page.getTotalPages());
|
||||
// JPA Page 的 getTotalElements() 是总记录数
|
||||
response.setTotal(page.getTotalElements());
|
||||
// JPA Page 的 getContent() 是当前页的数据列表
|
||||
response.setData(page.getContent());
|
||||
} else {
|
||||
// 如果传入的 page 为 null,设置默认值
|
||||
response.setCurrent(1L);
|
||||
response.setSize(10L);
|
||||
response.setPages(0L);
|
||||
response.setTotal(0L);
|
||||
response.setData(null);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
// 如果您需要处理分页结果DTO(例如实体转DTO),可以添加一个重载方法:
|
||||
|
||||
/**
|
||||
* 成功响应 (适用于将实体 Page<E> 转换为 DTO PageResponse<D>)
|
||||
*
|
||||
* @param page Spring Data JPA 提供的实体分页接口
|
||||
* @param data 经过转换后的 DTO 列表
|
||||
* @param <E> 实体类型
|
||||
* @param <D> DTO 类型
|
||||
*/
|
||||
public static <E, D> PageResponse<D> success(Page<E> page, List<D> data) {
|
||||
PageResponse<D> response = new PageResponse<>();
|
||||
response.setSuccess(true);
|
||||
|
||||
if (Objects.nonNull(page)) {
|
||||
response.setCurrent(page.getNumber() + 1);
|
||||
response.setSize(page.getSize());
|
||||
response.setPages(page.getTotalPages());
|
||||
response.setTotal(page.getTotalElements());
|
||||
response.setData(data); // 使用传入的 DTO 列表
|
||||
} else {
|
||||
response.setCurrent(1L);
|
||||
response.setSize(10L);
|
||||
response.setPages(0L);
|
||||
response.setTotal(0L);
|
||||
response.setData(data);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.hanserwei.web.controller;
|
||||
|
||||
import com.hanserwei.common.aspect.ApiOperationLog;
|
||||
import com.hanserwei.common.utils.Response;
|
||||
import com.hanserwei.web.model.User;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class TestController {
|
||||
|
||||
@PostMapping("/admin/test")
|
||||
@ApiOperationLog(description = "测试接口")
|
||||
public ResponseEntity<String>test(@RequestBody @Validated User user, BindingResult bindingResult) {
|
||||
// 是否存在校验错误
|
||||
if (bindingResult.hasErrors()) {
|
||||
// 获取校验不通过字段的提示信息
|
||||
String errorMsg = bindingResult.getFieldErrors()
|
||||
.stream()
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
return ResponseEntity.badRequest().body(errorMsg);
|
||||
}
|
||||
|
||||
// 返参
|
||||
return ResponseEntity.ok("参数没有任何问题");
|
||||
}
|
||||
|
||||
@PostMapping("/admin/update")
|
||||
@ApiOperationLog(description = "测试更新接口")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Response<?> testUpdate() {
|
||||
log.info("更新成功...");
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user