该后台管理系统是用于管理视频网站数据的,目前分5个菜单项,这篇博客主要讲述【影片管理】的具体功能和实现
后台代码结构和【影片管理】的界面如下图
该界面分为上下2部分,【搜索条件】和【影片列表】,2部分所用到的字段都在【Video】实体类中,具体代码如下
package me.xiaomaju.entity;
import lombok.Data;
@Data
public class Video {
//表sys\_video字段
private String id\_video;
private String name\_video;
private String describe;
private String image;
private int id\_state;
private String id\_area;
private String dt\_show;
//关联sys\_type查询,拼接
private String type;
//关联sys\_state查询
private String name\_state;
//关联sys\_area查询
private String area;
//查询条件 page和limit要和LayUI的数据表格参数一致
private Integer page;//当前页码
private Integer limit;//每页显示数量
private String dt\_begin;
private String dt\_end;
private String id\_type;
}
视频表【sys_video】、状态表【sys_state】、地区表【sys_area】、类型表【sys_type】的表结构如下图
LayUI官网于2021年10月左右关闭,查看LayUI相关文档可以到 https://lln.kim/layui/index.html
【影片管理】明显用到LayUI的表单模块和数据表格模块,前端页面代码如下
开始写js代码,后面所有的js代码写在layui.use的 { } 里面。
通过url获取后台数据渲染数据表格,数据表格的数据要求4个属性,先新建该实体,代码如下
package me.xiaomaju.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class LayUIDataGridView {
private Integer code=0;
private String msg="";
private Long count;
private Object data;
/\*\*
\* 封装数据表格
\* @param count
\* @param data
\*/
public LayUIDataGridView(Long count, Object data) {
this.count = count;
this.data = data;
}
}
接下来通过 url: "${pageContext.request.contextPath}/video/video-list" 写后台代码
controller层代码如下
@Controller
@RequestMapping("/video")
public class VideoController {
private static final Logger logger = org.apache.log4j.Logger.getLogger(VideoController.class);
@Autowired
private VideoService videoService;
@RequestMapping(value = "/video-list")
@ResponseBody
public LayUIDataGridView findAll(Video video) {
//设置分页信息(当前页码,每页条数)
PageHelper.startPage(video.getPage(), video.getLimit());
//查询数据
List<Video> videoList = videoService.findByAttributes(video);
//创建分页对象
PageInfo<Video> pageInfo = new PageInfo<Video>(videoList);
//返回数据
return new LayUIDataGridView(pageInfo.getTotal(), pageInfo.getList());
}
}
pagehelper是一个分页插件,在mybatis.xml配置一下即可,配置如下
service层代码如下
@Service
public class VideoServiceImpl implements VideoService {
private static final Logger logger = org.apache.log4j.Logger.getLogger(VideoServiceImpl.class);
@Autowired
private IVideoMapper videoMapper;
@Override
public List<Video> findByAttributes(Video video) {
return videoMapper.findByAttributes(video);
}
}
mapper层代码如下
package me.xiaomaju.mapper;
import me.xiaomaju.entity.Area;
import me.xiaomaju.entity.Type;
import me.xiaomaju.entity.Video;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface IVideoMapper {
@Select("<script> " +
"select v.id\_video, v.name\_video,v.describe,v.image,v.id\_state,v.id\_area, v.dt\_show, s.name\_state,a.area from sys\_video v " +
"left join sys\_state s on v.id\_state=s.id\_state " +
"left join sys\_area a on v.id\_area=a.id\_area " +
" </script> ")
public List<Video> findByAttributes(Video video);
}
这样查出了【sys_video】表的所有字段,关联状态和地区表查出具体中文状态和地区。视频与类型则是多对多关系,这种多对多关系的数据用一张中间表来存储。
中间表【sys_video_type】只有2列,id_video和id_type,id_type又是类型表【sys_type】的主键。
所以可以在service层用id_video为入参,查询类型的中文,并将多个类型用逗号拼接在一起,代码如下
@Override
public List<Video> findByAttributes(Video video) {
List<Video> videoList = videoMapper.findByAttributes(video);
if (videoList.size() < 1)
return null;
//封装类型 type
for (Video \_video : videoList) {
List<String> typeList = videoMapper.findVideoType(\_video.getId\_video());
String type = StringUtil.getListStrs(typeList);
\_video.setType(type);
}
return videoList;
}
mapper层查询类型代码如下
@Select("select t.name\_type from sys\_type t left join sys\_video\_type vt ON t.id\_type= vt.id\_type where vt.id\_video=#{id} ")
public List<String> findVideoType(String id);
通过上述表关系在那几张表造一些数据,页面数据表格就有对应数据显示了。
接下来实现上方【搜索条件】的查询功能,效果如下图
其中2个时间项用到了LayUI的日期与时间选择模块,需要进行组件渲染。搜索表单中【类型】下拉框的数据是动态的,后面介绍新增与编辑功能时会将对应js代码写出来。
//渲染日期组件
laydate.render({
elem: "#dt\_begin",
});
laydate.render({
elem: "#dt\_end"
});
//监听搜索按钮提交事件
form.on("submit(doSearch)", function (data) {
tableIns.reload({
where: data.field,//查询条件
page: {
curr: 1
}
});
//禁止页面刷新
return false;
});
需要注意的是,搜索和一开始的数据表格渲染走的是相同的后台代码,即"${pageContext.request.contextPath}/video/video-list"。
搜索表单中的字段都在Video实体中,所以直接在mapper层的代码中新增过滤条件,将原方法修改后的代码如下
@Select("<script> " +
"select distinct v.id\_video, v.name\_video,v.describe,v.image,v.id\_state,v.id\_area, v.dt\_show, s.name\_state,a.area from sys\_video v " +
"left join sys\_state s on v.id\_state=s.id\_state " +
"left join sys\_area a on v.id\_area=a.id\_area " +
"left join sys\_video\_type vt on v.id\_video=vt.id\_video " +
" <where> " +
" <if test=\\"name\_video != null and name\_video !='' \\"> v.name\_video=#{name\_video} </if> " +
" <if test=\\" id\_type != null and id\_type !='' \\"> and vt.id\_type=#{id\_type} </if> " +
" <if test=\\"dt\_begin != null and dt\_begin!='' \\"> <!\[CDATA\[ and v.dt\_show >= #{dt\_begin} \]\]> </if> " +
" <if test=\\"dt\_end != null and dt\_end!='' \\"> <!\[CDATA\[ and v.dt\_show <= #{dt\_end} \]\]> </if> " +
" <if test=\\"id\_state != 0\\"> AND v.id\_state=#{id\_state}</if> " +
" </where> " +
" </script> ")
public List<Video> findByAttributes(Video video);
接下来实现新增和编辑的功能,新增和编辑用的是同一个表单,效果如下图
首先写这个表单的前台代码
新增和编辑对应的js代码,【上映日期】需要进行日期组件渲染
laydate.render({
elem: "#dt\_show",
type: "date"//默认
});
//监听表格头部工具栏事件
table.on("toolbar(dataTable)", function (obj) {
switch (obj.event) {
//添加
case 'add':
openAddWindow();
break;
}
});
//监听表格行工具栏事件
table.on("tool(dataTable)", function (obj) {
switch (obj.event) {
//编辑
case 'edit':
openUpdateWindow(obj.data);
break;
}
});
var url;//提交地址
var mainIndex;//窗口索引
//打开编辑窗口
function openUpdateWindow(data) {
//清空表单数据
$("#dataForm")\[0\].reset();
//将该行的类型给表单勾选上
var types = data.type.split(",");
var typeCheckbox = $("input:checkbox\[name='id\_types'\]");
for (var j = 0; j < types.length; j++) {
for (var i = 0; i < typeCheckbox.length; i++) {
if (typeCheckbox\[i\].title == types\[j\]) {
typeCheckbox\[i\].checked = true;
}
}
form.render(); //更新渲染
}
mainIndex = layer.open({
type: 1,//弹出层类型
title: "影片信息修改",
area: \['800px', '600px'\],
content: $("#addOrUpdateCardView"),//引用的窗口代码
success: function () {
//表单数据回显
// console.log(data);
form.val("dataForm", data);
//修改请求
url = "${pageContext.request.contextPath}/video/update";
}
});
}
//打开添加窗口
function openAddWindow() {
mainIndex = layer.open({
type: 1,//弹出层类型
title: "添加影片",
area: \['800px', '600px'\],
content: $("#addOrUpdateCardView"),//引用的窗口代码
success: function () {
//清空表单数据
$("#dataForm")\[0\].reset();
url = "${pageContext.request.contextPath}/video/add";
}
});
}
//监听弹出层的表单提交事件
form.on("submit(doSubmit)", function (data) {
if ($("input:checkbox\[name='id\_types'\]:checked").length > 3 || $("input:checkbox\[name='id\_types'\]:checked").length < 1) {
layer.msg('类型为必填项,且最多只能选3项!', {icon: 5});
return false;
}
//获取checkbox\[name='id\_types'\]的值,获取所有选中的复选框,并将其值放入数组中
var arr = new Array();
$("input:checkbox\[name='id\_types'\]:checked").each(function (i) {
arr\[i\] = $(this).val();
});
// 替换 data.field.id\_types的数据为拼接后的字符串
data.field.id\_types = arr.join(",");
$.post(url, data.field, function (result) {
if (result.success) {
layer.alert(result.message, {icon: 1});
//关闭窗口
layer.close(mainIndex);
//刷新数据表格
tableIns.reload();
} else {
layer.alert(result.message, {icon: 2});
}
}, "json");
return false;
});
编辑功能的controller层代码如下
@RequestMapping(value = "/update", produces = "text/html;charset=UTF-8")
@ResponseBody
public String update(Video video, String\[\] id\_types, HttpSession session) {
Map<String, Object> map = new HashMap<String, Object>();
int result = videoService.update(video);
// 先删除类型再新增
int types1 = videoService.deleteVideoType(video.getId\_video());
int types = videoService.addVideoType(video.getId\_video(), id\_types);
if (result > 0 && types > 0) {
map.put("success", true);
map.put("message", "修改成功");
Admin admin = (Admin) session.getAttribute("loginAdmin");
logger.info("修改影片的人员为:" + admin.getName\_admin() + ";影片ID为:" + video.getId\_video());
} else {
map.put("success", false);
map.put("message", "修改失败");
}
return JSON.toJSONString(map);
}
新增功能的controller层代码与编辑类似,新增的是直接新增类型,即往【sys_video_video】插入数据;而编辑需要先删除类型再新增类型,因为【id_types】的长度(表单中类型复选框勾选的数量)不是固定的。
而直接在新增功能的controller层代码中【video.getId_video()】是为空的,需要在mapper层加一个注解,详情见我下一篇博客。
搜索表单中的下拉框【类型】,新增功能和编辑功能的弹出层中的下拉框【地区】和复选框【类型】的数据是动态的,需要向后台发送Ajax请求,js代码如下
//发送Ajax请求查询类型
$.get("${pageContext.request.contextPath}/video/query-type", function (result) {
var duoxuan = "";
var xiala = "";
//循环遍历集合
for (let i = 0; i < result.length; i++) {
duoxuan += "<input type=\\"checkbox\\" name=\\"id\_types\\" title='" + result\[i\].name\_type + "' value='" + result\[i\].id\_type + "' lay-skin=\\"primary\\" lay-verify=\\"fuxuan\\"> "
xiala += "<option value='" + result\[i\].id\_type + "'>" + result\[i\].name\_type + "</option>"
}
//将网页代码追加到下拉列表和多选框中
$("\[id='chkBox\_type'\]").append(duoxuan);
$("\[id='select\_type'\]").append(xiala);
//更新渲染select下拉框
form.render("select");
}, "json");
//发送Ajax请求查询地区
$.get("${pageContext.request.contextPath}/video/query-area", function (result) {
var html = "";
//循环遍历集合
for (let i = 0; i < result.length; i++) {
html += "<option value='" + result\[i\].id\_area + "'>" + result\[i\].area + "</option>"
}
//将网页代码追加到下拉列表中
$("\[name='id\_area'\]").append(html);
//更新渲染select下拉框
form.render("select");
}, "json");
后台controller调用service,service 调用mapper查询地区和类型,返回对应实体的List集合即可。
如果你的前端页面和我一样是用jsp写的,不出意料的话,你的复选框显示可能有问题,在标签上面加上 即可。
下面实现弹出层表单中的图片上传功能,js代码如下
//图片上传
var uploadInst = upload.render({
elem: "#btn-img" /\*根据绑定id,打开本地图片\*/
, url: "${pageContext.request.contextPath}/video/upload-img" /\*上传后台接受接口\*/
, done: function (res) {
if (res.success) {
$('#imgPath').attr('value', res.message);
} else {
layer.alert(res.message, {icon: 2});
}
}
});
后台controller层代码如下
@RequestMapping(value = "/upload-img", produces = "text/html;charset=UTF-8")
@ResponseBody
public String uploadImg(@RequestParam(value = "file", required = false) MultipartFile file, HttpServletRequest request) {
Map<String, Object> map = new HashMap<String, Object>();
String originalFilename = file.getOriginalFilename(); // 获取文件上传名
String path = request.getServletContext().getRealPath("/") +"static\\\\img\\\\"+ originalFilename;
logger.info("上传路径:"+path );
try {
file.transferTo(new File(path));
map.put("success", true);
map.put("message", path);
} catch (IOException e) {
map.put("success", false);
map.put("message", "图片上传失败");
}
return JSON.toJSONString(map);
}
如果上传成功,将图片路径传到前台,放到弹出层表单中【封面】后的隐藏域中。
接下来实现行删除和批量删除,效果如下图
新增和批量删除在表格头部工具栏事件监听到,而行删除和编辑在表格行工具栏事件监听到,js代码如下
//监听表格头部工具栏事件
table.on("toolbar(dataTable)", function (obj) {
switch (obj.event) {
//添加
case 'add':
openAddWindow();
break;
//批量删除
case 'batchDelete':
batchDelete();
break;
}
});
//监听表格行工具栏事件
table.on("tool(dataTable)", function (obj) {
switch (obj.event) {
//编辑
case 'edit':
openUpdateWindow(obj.data);
break;
//删除
case 'delete':
deleteById(obj.data);
break;
}
});
//单个删除
function deleteById(data) {
//提示用户确认是否删除
layer.confirm('真的要删除吗?', {icon: 3, title: '提示'}, function (index) {
//发送ajax请求
$.post("${pageContext.request.contextPath}/video/deleteById", {"id\_video": data.id\_video}, function (result) {
if (result.success) {
layer.alert(result.message, {icon: 1});
//刷新数据表格
tableIns.reload();
} else {
layer.alert(result.message, {icon: 2});
}
}, "json");
//关闭提示框
layer.close(index);
});
}
//批量删除
function batchDelete() {
//获取表格对象
var checkStatus = table.checkStatus('dataTable');
//判断是否有选中行
if (checkStatus.data.length > 0) {
//定义数组,保存选中行的ID
var idArr = \[\];
//循环遍历获取选中行(目的是获取选中的每一行的ID值)
for (let i = 0; i < checkStatus.data.length; i++) {
//将选中的ID值添加到数组的末尾
idArr.push(checkStatus.data\[i\].id\_video);
}
//将数组转成字符串
var ids = idArr.join(",");
//提示用户是否删除
layer.confirm('真的要删除吗?', {icon: 3, title: "提示"}, function (index) {
//发送ajax请求
$.post("${pageContext.request.contextPath}/video/batch-delete", {"ids": ids}, function (result) {
if (result.success) {
layer.alert(result.message, {icon: 1});
//刷新数据表格
tableIns.reload();
} else {
layer.alert(result.message, {icon: 2});
}
}, "json");
//关闭提示框
layer.close(index);
});
} else {
layer.msg("请选择要删除的数据");
}
}
单个删除和批量删除的controller层代码如下
@RequestMapping(value = "/deleteById", produces = "text/html;charset=UTF-8")
@ResponseBody
public String deleteById(String id_video) {
Map
int result = videoService.deleteById(id_video);
if (result > 0) {
map.put("success", true);
map.put("message", "删除成功");
} else {
map.put("success", false);
map.put("message", "删除失败");
}
return JSON.toJSONString(map);
}
@RequestMapping(value = "/batch-delete", produces = "text/html;charset=UTF-8")
@ResponseBody
public String batchDelte(String ids) {
Map<String, Object> map = new HashMap<String, Object>();
int result = videoService.batchDelte(ids);
if (result > 0) {
map.put("success", true);
map.put("message", "删除成功");
} else {
map.put("success", false);
map.put("message", "删除失败");
}
return JSON.toJSONString(map);
}
批量删除需要在service层中将ids按逗号分隔成数组再删除。
完毕
TRANSLATE with x
English
TRANSLATE with
COPY THE URL BELOW
Back
EMBED THE SNIPPET BELOW IN YOUR SITE
Enable collaborative features and customize widget: Bing Webmaster Portal
Back
手机扫一扫
移动阅读更方便
你可能感兴趣的文章