diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/feature/KitDynamicTableColumn.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/feature/KitDynamicTableColumn.java new file mode 100644 index 00000000..5f4e506d --- /dev/null +++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/feature/KitDynamicTableColumn.java @@ -0,0 +1,43 @@ +/* + * Copyright 2021-2026 Odboy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.odboy.feature; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) +public @interface KitDynamicTableColumn { + + /** + * 标题 + */ + String value() default ""; + + /** + * 宽度 + */ + int width() default 0; + + /** + * 是否排序字段 + */ + boolean sortable() default false; +} diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/feature/KitDynamicTableResponse.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/feature/KitDynamicTableResponse.java new file mode 100644 index 00000000..75081f8d --- /dev/null +++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/feature/KitDynamicTableResponse.java @@ -0,0 +1,172 @@ +/* + * Copyright 2021-2026 Odboy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.odboy.feature; + +import cn.hutool.core.util.ReflectUtil; +import cn.odboy.base.KitObject; +import cn.odboy.base.KitPageArgs; +import cn.odboy.util.KitBeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.Getter; +import lombok.Setter; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * 动态表格 + * + * @param 数据表对象 + * @param 渲染对象 + * @author odboy + * @date 2026-02-05 + */ +@Getter +public class KitDynamicTableResponse extends KitObject { + + /** + * 主键 + */ + @Setter + private String primaryKey = "id"; + /** + * 表格列定义 + */ + private List columns = new ArrayList<>(); + /** + * 数据总数 + */ + private Long totalElements; + /** + * 数据内容 + */ + private List content; + + /** + * @param clazz 渲染类型 + * @param pageResult 渲染类型分页参数 + */ + public KitDynamicTableResponse(Class clazz, IPage pageResult) { + this.renderColumns(clazz); + this.setContent(clazz, pageResult); + } + + /** + * @param clazz 渲染类型 + * @param pageResult 渲染类型分页参数 + * @param primaryKey 主键 + */ + public KitDynamicTableResponse(Class clazz, IPage pageResult, String primaryKey) { + this.primaryKey = primaryKey; + this.renderColumns(clazz); + this.setContent(clazz, pageResult); + } + + /** + * @param clazz 渲染类型 + * @param pageArgs 分页参数 + * @param baseMapper 数据表Mapper + * @param wrapper 查询条件 + */ + public KitDynamicTableResponse(Class clazz, KitPageArgs pageArgs, BaseMapper baseMapper, LambdaQueryWrapper wrapper) { + this.renderColumns(clazz); + Page pageResult = baseMapper.selectPage(new Page<>(pageArgs.getPage(), pageArgs.getSize()), wrapper); + this.setContent(clazz, pageResult); + } + + /** + * @param clazz 渲染类型 + * @param pageArgs 分页参数 + * @param primaryKey 主键 + * @param baseMapper 数据表Mapper + * @param wrapper 查询条件 + */ + public KitDynamicTableResponse(Class clazz, KitPageArgs pageArgs, String primaryKey, BaseMapper baseMapper, LambdaQueryWrapper wrapper) { + this.primaryKey = primaryKey; + this.renderColumns(clazz); + Page pageResult = baseMapper.selectPage(new Page<>(pageArgs.getPage(), pageArgs.getSize()), wrapper); + this.setContent(clazz, pageResult); + } + + /** + * 渲染表格列 + * + * @param clazz 渲染类型 + */ + private void renderColumns(Class clazz) { + List columns = new ArrayList<>(); + if (clazz == null) { + this.columns = columns; + return; + } + Field[] fields = ReflectUtil.getFields(clazz); + for (Field field : fields) { + if ("serialVersionUID".equals(field.getName())) { + continue; + } + Column column = new Column(); + column.setName(field.getName()); + KitDynamicTableColumn annotation = field.getAnnotation(KitDynamicTableColumn.class); + if (annotation == null) { + column.setTitle(field.getName()); + column.setWidth(null); + } else { + column.setTitle(annotation.value()); + column.setWidth(annotation.width() == 0 ? null : annotation.width()); + column.setSortable(annotation.sortable()); + } + columns.add(column); + } + this.columns = columns; + } + + /** + * @param clazz 渲染类型 + * @param pageResult 渲染结果 + */ + public void setContent(Class clazz, IPage pageResult) { + if (pageResult == null) { + return; + } + this.totalElements = pageResult.getTotal(); + this.content = KitBeanUtil.copyToList(pageResult.getRecords(), clazz); + } + + @Getter + @Setter + public static class Column { + + /** + * 索引名称 + */ + private String name; + /** + * 索引标题 + */ + private String title; + /** + * 表格宽度 + */ + private Integer width; + /** + * 是否排序列 + */ + private Boolean sortable = false; + } +} diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/feature/KitDynamicTableUtil.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/feature/KitDynamicTableUtil.java new file mode 100644 index 00000000..9f33d1d4 --- /dev/null +++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/feature/KitDynamicTableUtil.java @@ -0,0 +1,65 @@ +/* + * Copyright 2021-2026 Odboy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.odboy.feature; + +import cn.odboy.base.KitPageArgs; +import cn.odboy.framework.mybatisplus.core.KitMpQUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.experimental.UtilityClass; + +/** + * 动态表格辅助工具 + * + * @author odboy + */ +@UtilityClass +public class KitDynamicTableUtil { + + /** + * 渲染排序规则 + * + * @param pageArgs 分页参数 + * @param 数据表对象 + * @param 渲染对象 + * @return / + */ + public static QueryWrapper renderOrder(KitPageArgs pageArgs) { + QueryWrapper wrapper = new QueryWrapper<>(); + KitPageArgs.OrderBy orderBy = pageArgs.getOrderBy(); + if (orderBy != null) { + wrapper.orderBy(true, orderBy.isAsc(), orderBy.getColumn()); + } + return wrapper; + } + + /** + * 渲染所有规则(需要配合 @KitMpQuery 注解使用) + * + * @param pageArgs 分页参数 + * @param 数据表对象 + * @param 渲染对象 + * @return / + */ + public static LambdaQueryWrapper renderAll(KitPageArgs pageArgs) { + QueryWrapper wrapper = KitMpQUtil.build(pageArgs.getArgs()); + KitPageArgs.OrderBy orderBy = pageArgs.getOrderBy(); + if (orderBy != null) { + wrapper.orderBy(true, orderBy.isAsc(), orderBy.getColumn()); + } + return wrapper.lambda(); + } +} diff --git a/cutejava-springboot3/cutejava-module-system/src/main/java/cn/odboy/system/features/CuteDynamicTableDemoApi.java b/cutejava-springboot3/cutejava-module-system/src/main/java/cn/odboy/system/features/CuteDynamicTableDemoApi.java new file mode 100644 index 00000000..d986fe8e --- /dev/null +++ b/cutejava-springboot3/cutejava-module-system/src/main/java/cn/odboy/system/features/CuteDynamicTableDemoApi.java @@ -0,0 +1,98 @@ +/* + * Copyright 2021-2026 Odboy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.odboy.system.features; + +import cn.hutool.core.util.StrUtil; +import cn.odboy.base.KitPageArgs; +import cn.odboy.feature.KitDynamicTableResponse; +import cn.odboy.feature.KitDynamicTableUtil; +import cn.odboy.system.dal.dataobject.SystemMenuTb; +import cn.odboy.system.dal.model.request.SystemQueryMenuArgs; +import cn.odboy.system.dal.mysql.SystemMenuMapper; +import cn.odboy.system.features.model.SystemMenuDynamicTableModel; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +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 +@Api(tags = "系统组件:CuteDynamicTable演示") +@RequestMapping("/api/features/CuteDynamicTable") +public class CuteDynamicTableDemoApi { + + @Autowired + private SystemMenuMapper systemMenuMapper; + + @ApiOperation("写法1:查询动态数据") + @PostMapping(value = "/searchMenu") + @PreAuthorize("@el.check()") + public ResponseEntity> searchMenu(@Validated @RequestBody KitPageArgs pageArgs) { + // 请求参数 + Integer page = pageArgs.getPage(); + Integer size = pageArgs.getSize(); + KitPageArgs.OrderBy orderBy = pageArgs.getOrderBy(); + SystemQueryMenuArgs args = pageArgs.getArgs(); + // 分页查询 + QueryWrapper wrapper = new QueryWrapper<>(); + if (orderBy != null) { + orderBy.bindWrapper(wrapper); + } + IPage iPage = new Page<>(page, size); + LambdaQueryWrapper lambda = wrapper.lambda(); + if (args != null) { + lambda.like(StrUtil.isNotBlank(args.getBlurry()), SystemMenuTb::getTitle, args.getBlurry()); + } + IPage pageResult = systemMenuMapper.selectPage(iPage, wrapper); + // 响应结果 + return ResponseEntity.ok(new KitDynamicTableResponse<>(SystemMenuDynamicTableModel.class, pageResult, "id")); + } + + @ApiOperation("写法2:查询动态数据") + @PostMapping(value = "/searchMenu2") + @PreAuthorize("@el.check()") + public ResponseEntity> searchMenu2(@Validated @RequestBody KitPageArgs pageArgs) { + // 渲染排序(非必须) + QueryWrapper wrapper = KitDynamicTableUtil.renderOrder(pageArgs); + LambdaQueryWrapper lambda = wrapper.lambda(); + // 查询条件 + SystemQueryMenuArgs args = pageArgs.getArgs(); + if (args != null) { + lambda.like(StrUtil.isNotBlank(args.getBlurry()), SystemMenuTb::getTitle, args.getBlurry()); + } + // 响应结果 + return ResponseEntity.ok(new KitDynamicTableResponse<>(SystemMenuDynamicTableModel.class, pageArgs, "id", systemMenuMapper, lambda)); + } + + @ApiOperation("写法3:查询动态数据") + @PostMapping(value = "/searchMenu3") + @PreAuthorize("@el.check()") + public ResponseEntity> searchMenu3(@Validated @RequestBody KitPageArgs pageArgs) { + // 渲染查询条件 + LambdaQueryWrapper wrapper = KitDynamicTableUtil.renderAll(pageArgs); + // 响应结果 + return ResponseEntity.ok(new KitDynamicTableResponse<>(SystemMenuDynamicTableModel.class, pageArgs, "id", systemMenuMapper, wrapper)); + } +} diff --git a/cutejava-springboot3/cutejava-module-system/src/main/java/cn/odboy/system/features/model/SystemMenuDynamicTableModel.java b/cutejava-springboot3/cutejava-module-system/src/main/java/cn/odboy/system/features/model/SystemMenuDynamicTableModel.java new file mode 100644 index 00000000..26852dd1 --- /dev/null +++ b/cutejava-springboot3/cutejava-module-system/src/main/java/cn/odboy/system/features/model/SystemMenuDynamicTableModel.java @@ -0,0 +1,58 @@ +/* + * Copyright 2021-2026 Odboy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.odboy.system.features.model; + +import cn.odboy.base.KitObject; +import cn.odboy.feature.KitDynamicTableColumn; +import lombok.Getter; +import lombok.Setter; + +/** + * 例子:渲染对象 + */ +@Getter +@Setter +public class SystemMenuDynamicTableModel extends KitObject { + + @KitDynamicTableColumn(value = "ID") + private Long id; + @KitDynamicTableColumn(value = "菜单标题") + private String title; + @KitDynamicTableColumn(value = "菜单组件名称", width = 200) + private String componentName; + @KitDynamicTableColumn(value = "排序") + private Integer menuSort = 999; + @KitDynamicTableColumn(value = "组件路径", width = 200) + private String component; + @KitDynamicTableColumn(value = "路由地址", width = 120) + private String path; + @KitDynamicTableColumn(value = "菜单类型") + private Integer type; + @KitDynamicTableColumn(value = "权限标识") + private String permission; + @KitDynamicTableColumn(value = "菜单图标") + private String icon; + @KitDynamicTableColumn(value = "缓存") + private Boolean cache; + @KitDynamicTableColumn(value = "是否隐藏") + private Boolean hidden; + @KitDynamicTableColumn(value = "上级菜单") + private Long pid; + @KitDynamicTableColumn(value = "子节点数目", sortable = true, width = 200) + private Integer subCount = 0; + @KitDynamicTableColumn(value = "外链菜单") + private Boolean iFrame; +}