LayUI+SSM实现一个简单的后台管理系统
阅读原文时间:2023年07月10日阅读:1

该后台管理系统是用于管理视频网站数据的,目前分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 map = new HashMap();
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

Arabic

Hebrew

Polish

Bulgarian

Hindi

Portuguese

Catalan

Hmong Daw

Romanian

Chinese Simplified

Hungarian

Russian

Chinese Traditional

Indonesian

Slovak

Czech

Italian

Slovenian

Danish

Japanese

Spanish

Dutch

Klingon

Swedish

English

Korean

Thai

Estonian

Latvian

Turkish

Finnish

Lithuanian

Ukrainian

French

Malay

Urdu

German

Maltese

Vietnamese

Greek

Norwegian

Welsh

Haitian Creole

Persian

 

TRANSLATE with

COPY THE URL BELOW

Back

EMBED THE SNIPPET BELOW IN YOUR SITE

Enable collaborative features and customize widget: Bing Webmaster Portal

Back

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章