基于若依-内容管理动态修改,通过路由字典配置动态管理

一、Java后端
1、实体
新增了两个字段 titleImg、noticeDesc。可以动态校验(业务层)。
package org.dromara.system.domain;import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;/*** 通知公告表 sys_notice** @author Lion Li*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_notice")
public class SysNotice extends TenantEntity {/*** 公告ID*/@TableId(value = "notice_id")private Long noticeId;/*** 公告标题*/private String noticeTitle;/*** 公告类型(字典:sys_notice_type)*/private String noticeType;/*** 标题图片*/private Long titleImg;/*** 公告摘要*/private String noticeDesc;/*** 公告内容*/private String noticeContent;/*** 公告状态(0正常 1关闭)*/private String status;/*** 备注*/private String remark;}
1、控制层
package org.dromara.system.controller.system;import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.service.DictService;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.sse.utils.SseMessageUtils;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysNoticeBo;
import org.dromara.system.domain.vo.SysNoticeVo;
import org.dromara.system.service.ISysNoticeService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;/*** 公告 信息操作处理** @author Lion Li*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/notice")
public class SysNoticeController extends BaseController {private final ISysNoticeService noticeService;/*** 获取通知公告列表*/@SaCheckPermission("system:notice:list")@GetMapping("/list")public TableDataInfo<SysNoticeVo> list(SysNoticeBo notice, PageQuery pageQuery) {return noticeService.selectPageNoticeList(notice, pageQuery);}/*** 根据通知公告编号获取详细信息** @param noticeId 公告ID*/@SaCheckPermission("system:notice:query")@GetMapping(value = "/{noticeId}")public R<SysNoticeVo> getInfo(@PathVariable Long noticeId) {return R.ok(noticeService.selectNoticeById(noticeId));}/*** 新增通知公告*/@SaCheckPermission("system:notice:add")@Log(title = "通知公告", businessType = BusinessType.INSERT)@PostMappingpublic R<Void> add(@Validated @RequestBody SysNoticeBo notice) {int rows = noticeService.insertNotice(notice);if (rows <= 0) {return R.fail();}return R.ok();}/*** 修改通知公告*/@SaCheckPermission("system:notice:edit")@Log(title = "通知公告", businessType = BusinessType.UPDATE)@PutMappingpublic R<Void> edit(@Validated @RequestBody SysNoticeBo notice) {return toAjax(noticeService.updateNotice(notice));}/*** 删除通知公告** @param noticeIds 公告ID串*/@SaCheckPermission("system:notice:remove")@Log(title = "通知公告", businessType = BusinessType.DELETE)@DeleteMapping("/{noticeIds}")public R<Void> remove(@PathVariable Long[] noticeIds) {return toAjax(noticeService.deleteNoticeByIds(noticeIds));}
}
2、小程序控制层
package org.dromara.system.api.controller;import cn.dev33.satoken.annotation.SaIgnore;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.vo.SysNoticeVo;
import org.dromara.system.service.ISysNoticeService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 移动端-公告|协议** @author Lion Li*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/notice/api")
public class ApiNoticeController extends BaseController {private final ISysNoticeService noticeService;/*** 根据公告类型获取通知公告||协议列表*/@SaIgnore@GetMapping("/{noticeType}")public R<Object> userPact(@NotNull(message = "主键不能为空")@PathVariable String noticeType) {return R.ok(noticeService.selectNoticeByType(noticeType));}/*** 根据公告类型获取通知公告||协议详情*/@SaIgnore@GetMapping("/detail/{noticeId}")public R<SysNoticeVo> detail(@NotNull(message = "主键不能为空")@PathVariable Long noticeId) {return R.ok(noticeService.selectNoticeByTypeInfo(noticeId));}}
3、接口
package org.dromara.system.service;import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.system.domain.bo.SysNoticeBo;
import org.dromara.system.domain.vo.SysNoticeVo;import java.util.List;/*** 公告 服务层** @author Lion Li*/
public interface ISysNoticeService {TableDataInfo<SysNoticeVo> selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery);/*** 小程序-通过公告类型查询公告信息* @param noticeType* @return*/Object selectNoticeByType(String noticeType);/*** 查询公告信息** @param noticeId 公告ID* @return 公告信息*/SysNoticeVo selectNoticeById(Long noticeId);/*** 查询公告列表** @param notice 公告信息* @return 公告集合*/List<SysNoticeVo> selectNoticeList(SysNoticeBo notice);/*** 新增公告** @param bo 公告信息* @return 结果*/int insertNotice(SysNoticeBo bo);/*** 修改公告** @param bo 公告信息* @return 结果*/int updateNotice(SysNoticeBo bo);/*** 删除公告信息** @param noticeId 公告ID* @return 结果*/int deleteNoticeById(Long noticeId);/*** 批量删除公告信息** @param noticeIds 需要删除的公告ID* @return 结果*/int deleteNoticeByIds(Long[] noticeIds);/*** 小程序-通过公告ID查询公告信息* @param noticeId* @return*/SysNoticeVo selectNoticeByTypeInfo(Long noticeId);
}
4、业务层
所有的校验都通过参数判断。
titleImg、noticeDesc通过字典中某个字段的json参数去判断,这里我不想改变字典的参数,我就用了不常用的cssClass字典作为json载体。
如果你还想添加其他字段,就需要在这里添加一些判断,用于后台是否需要添加。当然前端在写的时候也要判断。
package org.dromara.system.service.impl;import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysNotice;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.bo.SysNoticeBo;
import org.dromara.system.domain.vo.SysDictDataVo;
import org.dromara.system.domain.vo.SysNoticeVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysNoticeMapper;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysDictDataService;
import org.dromara.system.service.ISysNoticeService;
import org.springframework.stereotype.Service;import java.util.Arrays;
import java.util.List;/*** 公告 服务层实现** @author Lion Li*/
@RequiredArgsConstructor
@Service
public class SysNoticeServiceImpl implements ISysNoticeService {private final SysNoticeMapper baseMapper;private final SysUserMapper userMapper;private final ISysDictDataService dictDataService;@Overridepublic TableDataInfo<SysNoticeVo> selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery) {LambdaQueryWrapper<SysNotice> lqw = buildQueryWrapper(notice);Page<SysNoticeVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);return TableDataInfo.build(page);}/*** 小程序-通过公告类型查询公告信息* @param noticeType* @return*/@Overridepublic Object selectNoticeByType(String noticeType) {SysDictDataVo sysNoticeType = dictDataService.selectDictLabelVo("sys_notice_type", noticeType);if (ObjectUtil.isNull(sysNoticeType)) throw new ServiceException("公告不存在");String json = sysNoticeType.getCssClass();Dict dict = JsonUtils.parseMap(json);String isWechat = (String) dict.get("isWechat");String isLogin = (String) dict.get("isLogin");if (!"T".equals(isWechat)) throw new ServiceException("非法请求!");if ("T".equals(isLogin) && !LoginHelper.isLogin()) throw new ServiceException("请先登录!");return baseMapper.selectVoList(new LambdaQueryWrapper<SysNotice>().select(SysNotice::getNoticeId, SysNotice::getNoticeTitle,SysNotice::getNoticeContent,SysNotice::getNoticeDesc, SysNotice::getTitleImg,SysNotice::getRemark).eq(SysNotice::getNoticeType,noticeType).eq(SysNotice::getStatus, "1"));}/*** 小程序 通过公告ID查询公告信息* @param noticeId* @return*/@Overridepublic SysNoticeVo selectNoticeByTypeInfo(Long noticeId) {SysNoticeVo sysNotice = baseMapper.selectVoById(noticeId);if (ObjectUtil.isNull(sysNotice)) throw new ServiceException("该公告已下线");if ("0".equals(sysNotice.getStatus())) throw new ServiceException("该公告已下线");SysDictDataVo sysNoticeType = dictDataService.selectDictLabelVo("sys_notice_type", sysNotice.getNoticeType());if (ObjectUtil.isNull(sysNoticeType)) throw new ServiceException("公告类型不存在");String json = sysNoticeType.getCssClass();Dict dict = JsonUtils.parseMap(json);String isWechat = (String) dict.get("isWechat");String isLogin = (String) dict.get("isLogin");if (!"T".equals(isWechat)) throw new ServiceException("非法请求!");if ("T".equals(isLogin) && !LoginHelper.isLogin()) throw new ServiceException("请先登录!");return sysNotice;}/*** 查询公告信息** @param noticeId 公告ID* @return 公告信息*/@Overridepublic SysNoticeVo selectNoticeById(Long noticeId) {return baseMapper.selectVoById(noticeId);}/*** 查询公告列表** @param notice 公告信息* @return 公告集合*/@Overridepublic List<SysNoticeVo> selectNoticeList(SysNoticeBo notice) {LambdaQueryWrapper<SysNotice> lqw = buildQueryWrapper(notice);return baseMapper.selectVoList(lqw);}private LambdaQueryWrapper<SysNotice> buildQueryWrapper(SysNoticeBo bo) {if (StringUtils.isBlank(bo.getNoticeType())) throw new ServiceException("公告类型不能为空");LambdaQueryWrapper<SysNotice> lqw = Wrappers.lambdaQuery();lqw.like(StringUtils.isNotBlank(bo.getNoticeTitle()), SysNotice::getNoticeTitle, bo.getNoticeTitle());lqw.eq(SysNotice::getNoticeType, bo.getNoticeType());if (StringUtils.isNotBlank(bo.getCreateByName())) {SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, bo.getCreateByName()));lqw.eq(SysNotice::getCreateBy, ObjectUtil.isNotNull(sysUser) ? sysUser.getUserId() : null);}lqw.orderByAsc(SysNotice::getNoticeId);return lqw;}/*** 新增公告** @param bo 公告信息* @return 结果*/@Overridepublic int insertNotice(SysNoticeBo bo) {validateNotice(bo);SysNotice notice = MapstructUtils.convert(bo, SysNotice.class);return baseMapper.insert(notice);}/*** 修改公告** @param bo 公告信息* @return 结果*/@Overridepublic int updateNotice(SysNoticeBo bo) {validateNotice(bo);SysNotice notice = MapstructUtils.convert(bo, SysNotice.class);return baseMapper.updateById(notice);}/*** 新增修改前的校验*/private void validateNotice(SysNoticeBo bo) {if (StringUtils.isBlank(bo.getNoticeType())) throw new ServiceException("公告类型不能为空");SysDictDataVo sysNoticeType = dictDataService.selectDictLabelVo("sys_notice_type", bo.getNoticeType());if (ObjectUtil.isNull(sysNoticeType)) throw new ServiceException("公告类型不存在");String json = sysNoticeType.getCssClass();Dict dict = JsonUtils.parseMap(json);String isOne = (String) dict.get("isOne");String titleImg = (String) dict.get("titleImg");String noticeDesc = (String) dict.get("noticeDesc");if (StringUtils.isBlank(titleImg)) bo.setTitleImg(null);if (StringUtils.isBlank(noticeDesc)) bo.setNoticeDesc(null);if (StringUtils.isNotBlank(bo.getStatus()) && "1".equals(bo.getStatus())&& "T".equals(isOne)) {baseMapper.update(new LambdaUpdateWrapper<SysNotice>().eq(SysNotice::getNoticeType, bo.getNoticeType()).set(SysNotice::getStatus, "0"));}}/*** 删除公告对象** @param noticeId 公告ID* @return 结果*/@Overridepublic int deleteNoticeById(Long noticeId) {return baseMapper.deleteById(noticeId);}/*** 批量删除公告信息** @param noticeIds 需要删除的公告ID* @return 结果*/@Overridepublic int deleteNoticeByIds(Long[] noticeIds) {return baseMapper.deleteByIds(Arrays.asList(noticeIds));}}
注:这里用到 dictDataService.selectDictLabelVo()实现就是返回一个字典实体。可以自己去定义接口。参考如下:
/*** 查询字典数据** @param dictType 字典类型* @param dictValue 字典键值* @return 字典标签*/@Overridepublic SysDictDataVo selectDictLabelVo(String dictType, String dictValue) {return baseMapper.selectVoOne(new LambdaQueryWrapper<SysDictData>().select(SysDictData::getDictLabel,SysDictData::getCssClass,SysDictData::getRemark).eq(SysDictData::getDictType, dictType).eq(SysDictData::getDictValue, dictValue));}二、前端
前端我就不详细描述,给出主要的几个方法,具体配置根据你的表单来弄。
1、通过路由获取内容管理的类型
const router = useRouter()
queryParams.value.noticeType = router.currentRoute.value.name规定:
配置路由时,路由名称和字典名称要一致,但是路由配置首字母小写,字典首字母大写。
路由组件路径统一通一个index.vue这里时:system/notice/index.vue


2、通过字典获取配置参数
const noticeConfig = ref({isLogin: 'F', // 是否需要校验登录 F否T是isOne: 'F', // 发布项目是否唯一isWechat: 'F', // 是否是微信接口label: '公告', // 标题noticeDesc: 'F', // 摘要titleImg: 'F' // 封面图
});
const { sys_notice_type } = toRefs<any>(useDict( 'sys_notice_type'));function handleDictChange(newDict) {if (newDict && newDict.length > 0) {newDict.forEach(item => {if (item.value == router.currentRoute.value.name) {noticeConfig.value = JSON.parse(item.elTagClass)noticeConfig.value.label = item.label}})}
}// 监听字典值变化
watch(sys_notice_type, (newValue, oldValue) => {handleDictChange(newValue)
}, {deep: true, // 深度监听,确保对象内部变化也能触发immediate: true // 立即执行一次,获取初始值
})表单可以通过判断来实现是否显示:
<ElTableColumn label="摘要" prop="noticeDesc" :show-overflow-tooltip="true" v-if="noticeConfig.noticeDesc && 'T' == noticeConfig.noticeDesc" />这里字典配置参数如下:
{"isOne":"T","titleImg":"F","noticeDesc":"F","isLogin":"T","isWechat":"T"}
三、总结
通过字典和路由的配置,灵活的配置内容管理。再做客户开发中,我们经常会遇到一堆内容管理:通知、公告、关于我们、隐私协议、用户协议、看板等等。这些其实都是一个富文本输入为主。或多或少一个字段。为此我们单独去给他弄一个代码,实属复杂。
这篇很大程度同化不必要的内容管理,可以灵活的实现不改代码就能添加一个目录。
如果这个小技巧对你有所帮助,请不要吝啬你的点赞和收藏。

