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

一、Java后端

1、实体

新增了两个字段 titleImg、noticeDesc。可以动态校验(业务层)。

java 复制代码
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、控制层

java 复制代码
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)
    @PostMapping
    public 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)
    @PutMapping
    public 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、小程序控制层

java 复制代码
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、接口

java 复制代码
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载体。

如果你还想添加其他字段,就需要在这里添加一些判断,用于后台是否需要添加。当然前端在写的时候也要判断。

java 复制代码
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;

    @Override
    public 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
     */
    @Override
    public 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
     */
    @Override
    public 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 公告信息
     */
    @Override
    public SysNoticeVo selectNoticeById(Long noticeId) {
        return baseMapper.selectVoById(noticeId);
    }

    /**
     * 查询公告列表
     *
     * @param notice 公告信息
     * @return 公告集合
     */
    @Override
    public 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 结果
     */
    @Override
    public int insertNotice(SysNoticeBo bo) {
        validateNotice(bo);
        SysNotice notice = MapstructUtils.convert(bo, SysNotice.class);
        return baseMapper.insert(notice);
    }

    /**
     * 修改公告
     *
     * @param bo 公告信息
     * @return 结果
     */
    @Override
    public 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 结果
     */
    @Override
    public int deleteNoticeById(Long noticeId) {
        return baseMapper.deleteById(noticeId);
    }

    /**
     * 批量删除公告信息
     *
     * @param noticeIds 需要删除的公告ID
     * @return 结果
     */
    @Override
    public int deleteNoticeByIds(Long[] noticeIds) {
        return baseMapper.deleteByIds(Arrays.asList(noticeIds));
    }


}

注:这里用到 dictDataService.selectDictLabelVo()实现就是返回一个字典实体。可以自己去定义接口。参考如下:

java 复制代码
    /**
     * 查询字典数据
     *
     * @param dictType  字典类型
     * @param dictValue 字典键值
     * @return 字典标签
     */
    @Override
    public 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、通过路由获取内容管理的类型

javascript 复制代码
const router = useRouter()
queryParams.value.noticeType = router.currentRoute.value.name

规定:

配置路由时,路由名称和字典名称要一致,但是路由配置首字母小写,字典首字母大写。

路由组件路径统一通一个index.vue这里时:system/notice/index.vue

2、通过字典获取配置参数

javascript 复制代码
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 // 立即执行一次,获取初始值
})

表单可以通过判断来实现是否显示:

html 复制代码
<ElTableColumn label="摘要" prop="noticeDesc" :show-overflow-tooltip="true" v-if="noticeConfig.noticeDesc && 'T' == noticeConfig.noticeDesc" />

这里字典配置参数如下:

java 复制代码
{"isOne":"T","titleImg":"F","noticeDesc":"F","isLogin":"T","isWechat":"T"}

三、总结

通过字典和路由的配置,灵活的配置内容管理。再做客户开发中,我们经常会遇到一堆内容管理:通知、公告、关于我们、隐私协议、用户协议、看板等等。这些其实都是一个富文本输入为主。或多或少一个字段。为此我们单独去给他弄一个代码,实属复杂。

这篇很大程度同化不必要的内容管理,可以灵活的实现不改代码就能添加一个目录。

如果这个小技巧对你有所帮助,请不要吝啬你的点赞和收藏。

相关推荐
ywf12151 小时前
前端的dist包放到后端springboot项目下一起打包
前端·spring boot·后端
还是大剑师兰特7 小时前
Vue3 中的 defineExpose 完全指南
前端·javascript·vue.js
大阿明8 小时前
Spring Boot(快速上手)
java·spring boot·后端
哆啦A梦15888 小时前
Springboot整合MyBatis实现数据库操作
数据库·spring boot·mybatis
bearpping8 小时前
Java进阶,时间与日期,包装类,正则表达式
java
邵奈一8 小时前
清明纪念·时光信笺——项目运行指南
java·实战·项目
sunwenjian8868 小时前
Java进阶——IO 流
java·开发语言·python
sinat_255487818 小时前
读者、作家 Java集合学习笔记
java·笔记·学习
皮皮林5519 小时前
如何画出一张优秀的架构图?(老鸟必备)
java
百锦再9 小时前
Java 并发编程进阶,从线程池、锁、AQS 到并发容器与性能调优全解析
java·开发语言·jvm·spring·kafka·tomcat·maven