
一、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"}

三、总结
通过字典和路由的配置,灵活的配置内容管理。再做客户开发中,我们经常会遇到一堆内容管理:通知、公告、关于我们、隐私协议、用户协议、看板等等。这些其实都是一个富文本输入为主。或多或少一个字段。为此我们单独去给他弄一个代码,实属复杂。
这篇很大程度同化不必要的内容管理,可以灵活的实现不改代码就能添加一个目录。
如果这个小技巧对你有所帮助,请不要吝啬你的点赞和收藏。
