feat(form): 新增数据权限表单管理模块

- 添加表单相关的请求和响应VO类:DescVO、FormAddRequest、FormApiItemVO、FormApiListVO、FormApiSaveItemRequest、FormApiSaveRequest、FormApiSelectedVO、FormApiVO、FormColumnsSaveItemRequest、FormColumnsSaveRequest、FormColumnVO、FormUpdateRequest
- 实现FormController,提供表单增删改查接口以及表单列和功能API管理接口
- 实现TableInfoService,封装表和列的元数据信息查询逻辑
- 新增TableMetaMapper,使用MyBatis注解方式查询数据库表和列的元信息
- 支持表单的添加时自动同步表和列的元数据
- 支持表单列的保存与更新,自动管理列信息的增删改
- 支持表单功能API列表的保存,关联API与列权限信息
- 完善接口请求参数校验及事务控制,保证数据一致性
This commit is contained in:
曹鹏飞 2026-04-10 15:18:09 +08:00
parent 6cd27fd045
commit 99d7e654c3
15 changed files with 653 additions and 0 deletions

View File

@ -0,0 +1,299 @@
package com.nflg.wms.admin.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nflg.wms.admin.service.TableInfoService;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.*;
import com.nflg.wms.common.pojo.vo.DescVO;
import com.nflg.wms.common.pojo.vo.FormColumnVO;
import com.nflg.wms.common.pojo.vo.FormVO;
import com.nflg.wms.common.pojo.vo.PermissionApiItemVO;
import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.common.util.VUtil;
import com.nflg.wms.repository.entity.AdminPermissionApi;
import com.nflg.wms.repository.entity.AdminPermissionApiItem;
import com.nflg.wms.repository.entity.AdminPermissionColumn;
import com.nflg.wms.repository.entity.AdminPermissionTable;
import com.nflg.wms.repository.service.IAdminPermissionApiItemService;
import com.nflg.wms.repository.service.IAdminPermissionApiService;
import com.nflg.wms.repository.service.IAdminPermissionColumnService;
import com.nflg.wms.repository.service.IAdminPermissionTableService;
import com.nflg.wms.starter.BaseController;
import com.nflg.wms.starter.annotation.ApiMark;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 数据权限表单相关接口
* @author 曹鹏飞
**/
@RestController
@RequestMapping("/form")
public class FormController extends BaseController {
@Resource
private TableInfoService tableInfoService;
@Resource
private IAdminPermissionTableService permissionTableService;
@Resource
private IAdminPermissionColumnService permissionColumnService;
@Resource
private IAdminPermissionApiService permissionApiService;
@Resource
private IAdminPermissionApiItemService permissionApiItemService;
/**
* 获取表列表
*/
@GetMapping("getTables")
@ApiMark(moduleName = "表单管理", apiName = "获取表列表")
public ApiResult<List<DescVO>> getTables() {
return ApiResult.success(tableInfoService.getTableInfos());
}
/**
* 获取列列表
*/
@GetMapping("getTableColumns")
@ApiMark(moduleName = "表单管理", apiName = "获取列列表")
public ApiResult<List<DescVO>> getTableColumnInfos(@RequestParam String tableName) {
return ApiResult.success(tableInfoService.getTableColumnInfos(tableName));
}
/**
* 获取表单列表
*/
@PostMapping("search")
public ApiResult<PageData<FormVO>> search(@RequestBody FormSearchRequest request) {
IPage<FormVO> datas = permissionTableService.search(request);
if (CollectionUtil.isEmpty(datas.getRecords())) {
return ApiResult.success(PageData.empty());
}
List<AdminPermissionApi> apis = permissionApiService
.lambdaQuery()
.in(AdminPermissionApi::getTableId, datas.getRecords().stream().map(FormVO::getId).collect(Collectors.toList()))
.list();
datas.getRecords().forEach(form -> {
form.setApis(
apis.stream()
.filter(api -> Objects.equals(api.getTableId(), form.getId()))
.map(AdminPermissionApi::getApiName)
.collect(Collectors.toList())
);
});
return ApiResult.success(datas);
}
/**
* 新增表单
*/
@Transactional
@PostMapping("add")
public void add(@Valid @RequestBody FormAddRequest request) {
VUtil.trueThrowBusinessError(permissionTableService.lambdaQuery()
.eq(AdminPermissionTable::getTableName, request.getTableName())
.exists()
).throwMessage("表单已存在");
AdminPermissionTable table=new AdminPermissionTable()
.setTableName(request.getTableName())
.setTableDesc(request.getTableDesc())
.setRemark(request.getRemark())
.setCreateBy(UserUtil.getUserName())
.setCreateTime(LocalDateTime.now());
permissionTableService.save(table);
List<DescVO> columns = tableInfoService.getTableColumnInfos(request.getTableName());
permissionColumnService.saveBatch(
columns.stream()
.map(col -> new AdminPermissionColumn()
.setTableId(table.getId())
.setColName(col.getName())
.setColCode(StrUtil.toCamelCase(col.getName()))
.setColDesc(col.getDesc())
.setCreateBy(UserUtil.getUserName())
.setCreateTime(LocalDateTime.now())
)
.collect(Collectors.toList())
);
}
/**
* 修改表单
*/
@PostMapping("update")
public void update(@Valid @RequestBody FormUpdateRequest request) {
permissionTableService.lambdaUpdate()
.set(AdminPermissionTable::getTableDesc, request.getTableDesc())
.set(AdminPermissionTable::getRemark, request.getRemark())
.set(AdminPermissionTable::getUpdateBy, UserUtil.getUserName())
.set(AdminPermissionTable::getUpdateTime, LocalDateTime.now())
.eq(AdminPermissionTable::getId, request.getId())
.update();
}
/**
* 删除表单
* @param id 表单ID
*/
@PostMapping("delete")
@Transactional
public void delete(@RequestBody @NotNull Long id) {
permissionTableService.removeById(id);
permissionColumnService.lambdaUpdate()
.eq(AdminPermissionColumn::getTableId, id)
.remove();
}
/**
* 获取表单列
* @param id 表单ID
*/
@GetMapping("getFormColumns")
public ApiResult<List<FormColumnVO>> getFormColumns(@RequestParam Long id) {
AdminPermissionTable table = permissionTableService.getById(id);
VUtil.trueThrowBusinessError(Objects.isNull(table)).throwMessage("表不存在");
List<DescVO> columns = tableInfoService.getTableColumnInfos(table.getTableName());
List<AdminPermissionColumn> cols = permissionColumnService.lambdaQuery()
.eq(AdminPermissionColumn::getTableId, id)
.list();
return ApiResult.success(
columns.stream().map(col -> {
AdminPermissionColumn dc = cols.stream()
.filter(c -> StrUtil.equals(c.getColName(), col.getName()))
.findFirst()
.orElse(null);
return Objects.nonNull(dc) ? Convert.convert(FormColumnVO.class, dc) : new FormColumnVO()
.setColName(col.getName())
.setColDesc(col.getDesc());
}).collect(Collectors.toList())
);
}
/**
* 保存表单列
* @param request 请求参数
*/
@Transactional
@PostMapping("saveFormColumns")
public ApiResult<List<FormColumnVO>> saveFormColumns(@RequestBody FormColumnsSaveRequest request) {
List<FormColumnsSaveItemRequest> items1 = request.getItems()
.stream()
.filter(item -> Objects.nonNull(item.getId()))
.collect(Collectors.toList());
permissionColumnService.lambdaUpdate()
.eq(AdminPermissionColumn::getTableId, request.getId())
.notIn(CollectionUtil.isNotEmpty(items1), AdminPermissionColumn::getId, items1.stream().map(FormColumnsSaveItemRequest::getId).collect(Collectors.toList()))
.remove();
if (CollectionUtil.isNotEmpty(items1)) {
permissionColumnService.updateBatchById(
items1.stream()
.map(item -> new AdminPermissionColumn()
.setId(item.getId())
.setColDesc(item.getColDesc())
.setUpdateBy(UserUtil.getUserName())
.setUpdateTime(LocalDateTime.now())
)
.collect(Collectors.toList())
);
}
request.getItems().removeAll(items1);
permissionColumnService.saveBatch(
request.getItems().stream()
.map(item -> new AdminPermissionColumn()
.setTableId(request.getId())
.setColName(item.getColName())
.setColCode(StrUtil.toCamelCase(item.getColName()))
.setColDesc(item.getColDesc())
.setCreateBy(UserUtil.getUserName())
.setCreateTime(LocalDateTime.now())
)
.collect(Collectors.toList())
);
return getFormColumns(request.getId());
}
/**
* 获取表单功能API列表
* @param id 表单ID
*/
@GetMapping("getApiList")
public ApiResult<List<PermissionApiItemVO>> getApiList(@RequestParam Long id) {
return ApiResult.success(permissionApiService.getListVO(id));
}
/**
* 保存表单功能API列表
* @param request 请求参数
*/
@Transactional
@PostMapping("saveApiList")
public ApiResult<Void> saveApiList(@RequestBody FormApiSaveRequest request) {
List<FormApiSaveItemRequest> items = request.getApis()
.stream()
.filter(api -> Objects.nonNull(api.getId()))
.collect(Collectors.toList());
permissionApiService.lambdaUpdate()
.eq(AdminPermissionApi::getTableId, request.getTableId())
.notIn(CollectionUtil.isNotEmpty(items), AdminPermissionApi::getId, items.stream().map(FormApiSaveItemRequest::getId).collect(Collectors.toList()))
.remove();
permissionApiItemService.lambdaUpdate()
.eq(AdminPermissionApiItem::getTableId, request.getTableId())
.remove();
if (CollectionUtil.isNotEmpty(items)) {
permissionApiService.updateBatchById(
items.stream().map(item -> new AdminPermissionApi()
.setId(item.getId())
.setApiName(item.getFunctionName())
.setUpdateBy(UserUtil.getUserName())
.setUpdateTime(LocalDateTime.now())
).collect(Collectors.toList())
);
}
List<FormApiSaveItemRequest> items1 = request.getApis()
.stream()
.filter(api -> Objects.isNull(api.getId()))
.collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(items1)) {
items1.forEach(item -> item.setId(IdUtil.getSnowflakeNextId()));
permissionApiService.saveBatch(
items1.stream().map(item -> new AdminPermissionApi()
.setId(item.getId())
.setApiId(item.getApiId())
.setApiName(item.getFunctionName())
.setTableId(request.getTableId())
.setCreateBy(UserUtil.getUserName())
.setCreateTime(LocalDateTime.now())
).collect(Collectors.toList())
);
}
List<AdminPermissionApiItem> apiItems = new ArrayList<>();
request.getApis().forEach(item -> {
item.getColIds().forEach(colId -> {
apiItems.add(new AdminPermissionApiItem()
.setApiId(item.getId())
.setColId(colId)
.setTableId(request.getTableId())
);
});
});
permissionApiItemService.saveBatch(apiItems);
return ApiResult.success();
}
}

View File

@ -0,0 +1,23 @@
package com.nflg.wms.admin.service;
import com.nflg.wms.common.pojo.vo.DescVO;
import com.nflg.wms.repository.mapper.TableMetaMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class TableInfoService {
@Resource
private TableMetaMapper tableMetaMapper;
public List<DescVO> getTableInfos() {
return tableMetaMapper.getTableMeta();
}
public List<DescVO> getTableColumnInfos(String tableName) {
return tableMetaMapper.getTableColumnMeta(tableName);
}
}

View File

@ -0,0 +1,26 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class FormAddRequest {
/**
* 表名
*/
@NotBlank
private String tableName;
/**
* 表描述
*/
@NotBlank
private String tableDesc;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,28 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.util.List;
@Data
public class FormApiSaveItemRequest {
private Long id;
/**
* 功能ID
*/
private Long apiId;
/**
* 功能名称
*/
private String functionName;
/**
* 表单列ID
*/
@NotEmpty
private List<Long> colIds;
}

View File

@ -0,0 +1,15 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.Valid;
import lombok.Data;
import java.util.List;
@Data
public class FormApiSaveRequest {
private Long tableId;
@Valid
private List<FormApiSaveItemRequest> apis;
}

View File

@ -0,0 +1,19 @@
package com.nflg.wms.common.pojo.qo;
import lombok.Data;
@Data
public class FormColumnsSaveItemRequest {
private Long id;
/**
* 列名
*/
private String colName;
/**
* 列描述
*/
private String colDesc;
}

View File

@ -0,0 +1,23 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.util.List;
@Data
public class FormColumnsSaveRequest {
/**
* 表单ID
*/
private Long id;
/**
* 表单列
*/
@Valid
@NotEmpty
private List<FormColumnsSaveItemRequest> items;
}

View File

@ -0,0 +1,19 @@
package com.nflg.wms.common.pojo.qo;
import lombok.Data;
@Data
public class FormUpdateRequest {
private Long id;
/**
* 表描述
*/
private String tableDesc;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,17 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
@Data
public class DescVO {
/**
* 名称
*/
private String name;
/**
* 描述
*/
private String desc;
}

View File

@ -0,0 +1,19 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class FormApiItemVO {
/**
* 接口id
*/
private Long id;
/**
* 接口名称
*/
private String name;
}

View File

@ -0,0 +1,21 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
public class FormApiListVO {
/**
* 未选中的功能
*/
private List<FormApiVO> all;
/**
* 已选中的功能
*/
private List<FormApiSelectedVO> selected;
}

View File

@ -0,0 +1,26 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class FormApiSelectedVO {
private Long id;
/**
* 接口id
*/
private Long apiId;
/**
* 模块名称
*/
private String moduleName;
/**
* 接口名称
*/
private String apiName;
}

View File

@ -0,0 +1,21 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
public class FormApiVO {
/**
* 模块名称
*/
private String moduleName;
/**
* 模块下的接口
*/
private List<FormApiItemVO> itemVOS;
}

View File

@ -0,0 +1,53 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
import java.util.Objects;
@Data
@Accessors(chain = true)
public class FormColumnVO {
private Long id;
/**
* 列名
*/
private String colName;
/**
* 列描述
*/
private String colDesc;
/**
* 创建人
*/
private String createBy;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 最后更新人
*/
private String updateBy;
/**
* 最后更新时间
*/
private LocalDateTime updateTime;
/**
* 是否选中
*/
private boolean selected;
public boolean getSelected() {
return Objects.nonNull(id);
}
}

View File

@ -0,0 +1,44 @@
package com.nflg.wms.repository.mapper;
import com.nflg.wms.common.pojo.vo.DescVO;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface TableMetaMapper {
@Select("SELECT \n" +
" t.table_name AS \"name\",\n" +
" COALESCE(NULLIF(obj_description(c.oid), ''), t.table_name) AS \"desc\"\n" +
"FROM \n" +
" information_schema.tables t\n" +
"JOIN \n" +
" pg_namespace n ON n.nspname = t.table_schema\n" +
"JOIN \n" +
" pg_class c ON c.relname = t.table_name AND c.relnamespace = n.oid\n" +
"WHERE \n" +
" t.table_schema = current_schema(); "
)
List<DescVO> getTableMeta();
@Select("SELECT \n" +
" c.column_name AS \"name\",\n" +
" COALESCE(\n" +
" NULLIF(col_description(t.oid, c.ordinal_position), ''), \n" +
" c.column_name\n" +
" ) AS \"desc\"\n" +
"FROM \n" +
" information_schema.columns c\n" +
"JOIN \n" +
" pg_class t ON t.relname = c.table_name\n" +
"JOIN \n" +
" pg_namespace n ON n.oid = t.relnamespace AND n.nspname = c.table_schema\n" +
"WHERE \n" +
" c.table_name = #{tableName}\n" +
" AND c.table_schema = current_schema() -- 限制为当前模式(通常是 public防止查到其他同名表\n" +
"ORDER BY \n" +
" c.ordinal_position; "
)
List<DescVO> getTableColumnMeta(@Param("tableName") String tableName);
}