springboot图书商城-layui+thymleaf+MP(第一部分)

创建项目:删除一些不需要的文件。
在这里插入图片描述

pom依赖:注意,使用thyleaf注意要引入依赖的。

 <dependencies>
        <!--spring-web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>2.5.0</version>
        </dependency>
        <!--devtools-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--mysql-connector-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--spring-jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <!--mybatis-plus-generator-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!--模板引擎freemarker 依赖-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>
        <!--processor-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

配置文件的编写:
创建一个application.yml文件:
在这里插入图片描述

部分配置如下:

#服务器的配置
server:
  port: 9000
  servlet:
    context-path: /book

#数据库的配置
spring:
  #jdbc配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver #com.mysql.cj.jdbc.Driver
    username: root
    password: root
    #jdbc:mysql://localhost:3306/test?allowMultiQueries=true&useSSL=false&serverTimezone=UTC
    url: jdbc:mysql://localhost:3306/test?allowMultiQueries=true&useSSL=false&serverTimezone=UTC

#mybatis-plus配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml #映射文件的位置
  #在Mybatis的mapper.xml文件中resultType的type或者paramterType会返回自定义entity,
  #此时可以用全类名名来指定这些实体。可以使用type-aliases-package中指定entity扫描包类让mybatis自定扫描到自定义的entity。
  type-aliases-package: com.fan.bookshop.entity #设置封装实体类类的别名,批量设置别名扫描,多个package用逗号隔开

  global-config:
    db-config:
      id-type: auto #主键策略,mysql是采取自增的
      logic-delete-field: deleted  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2,步骤2: 实体类字段上加上@TableLogic注解)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
  configuration:
    map-underscore-to-camel-case: true #开启驼峰命名,可以不用配置,默认就是配置了true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #控制台输出sql语句的日志

使用代码生成器生成三层架构的包:自己先不要写认个的包;
注意修改第一行的包名:package com.fan.bookshop.generator;以及导入一个生成器的依赖:

        <!--mybatis-plus-generator-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!--模板引擎 依赖-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>
package com.fan.bookshop.generator;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class CodeGenerator {

    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        //获取用户的目录
        final String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");//这里不用修改
        gc.setAuthor("fan");
        gc.setBaseResultMap(true);
        gc.setBaseColumnList(true);
        // 是否打开输出目录 默认为true
        gc.setOpen(false);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/test?allowMultiQueries=true&useSSL=false&serverTimezone=UTC");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        mpg.setDataSource(dsc);

        // 包配置
        final PackageConfig pc = new PackageConfig();
        // pc.setModuleName(scanner("模块名"));
        pc.setParent("com.fan");//这里需要修改成自己的模块名称
        pc.setEntity("entity");//设置实体类包
/*        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");*/

        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";
        // 如果模板引擎是 velocity
        // String templatePath = "/templates/mapper.xml.vm";

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<FileOutConfig>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        // 指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        // templateConfig.setEntity("templates/entity2.java");
        // templateConfig.setService();
        // templateConfig.setController();

        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        //默认支持驼峰名称
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        // strategy.setSuperEntityClass("com.fame.common.BaseEntity");
        strategy.setEntityLombokModel(true);//自动lombok
        strategy.setLogicDeleteFieldName("deleted");//逻辑删除字段
        //自动填充
        TableFill createTime = new TableFill("createTime", FieldFill.INSERT);
        TableFill updateTime = new TableFill("updateTime", FieldFill.UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(createTime);
        tableFills.add(updateTime);
        strategy.setTableFillList(tableFills);

        //乐观锁
        strategy.setVersionFieldName("version");

        strategy.setRestControllerStyle(true);//restful风格的支持
        // strategy.setSuperControllerClass("com.fame.common.BaseController");
        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
        strategy.setSuperEntityColumns("id");
        // strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix("sys");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

}

然后进行数据库的设计:
在这里插入图片描述
此处我们只先进行简单的数据库设计:如下单表
在这里插入图片描述

做登录页面;
在这里插入图片描述

注册使用模态框:
在这里插入图片描述

首页类似于这样:
在这里插入图片描述
上面是一个跑马灯一样的广告;
在这里插入图片描述
在这里插入图片描述
网上找几张图片然后写进div中,使用轮播图:
然后设置样式,让图片填充到整个div中:


        body
        {
            background-image: url(images/firstlogin.jpg);
            background-color: #000000;
        }
        img{
            width: 100%;
            height: 100%;
        }

轮播图代码:

         <div class="layui-row">
            <div class="layui-col-xs12">
                <!--轮播图-->
                <div class="layui-carousel" id="test10" style="margin: 10px;">
                    <div carousel-item="">
                        <div><img  th:src="@{/images/book1.jpg}"></div>
                        <div><img  th:src="@{/images/book2.jpg}"></div>
                        <div><img th:src="@{/images/book3.jpg}"></div>
                        <div><img th:src="@{/images/book4.jpg}"></div>
                        <div><img th:src="@{/images/book5.jpg}"></div>
                        <div><img th:src="@{/images/book6.jpg}"></div>
                    </div>
                </div>
            </div>
        </div>

在这里插入图片描述

使用layui的轮播图:让左右等距,高度我们定义,js

<script>
    layui.use(['carousel'], function(){
        var carousel = layui.carousel;
        //图片轮播
        carousel.render({
            elem: '#test10'
            ,width: 'auto'
            ,height: '250px'
            ,interval: 3000
        });
        //事件
        carousel.on('change(test4)', function(res){
            console.log(res)
        });
    });
</script>

同样,导航条我们也使用layui的:

引入js,css:我这里放在head中引入的:

    <link  th:href="@{/layui/css/layui.css}" rel="stylesheet">
    <script th:src="@{/layui/layui.js}"></script>

js代码如下:

<script>
    //导航条需要的js
    //注意:导航 依赖 element 模块,否则无法进行功能性操作
    layui.use('element', function(){
        var element = layui.element;

        //…
    });
</script>

初步效果如下:
在这里插入图片描述
百度搜图片素材:轮播图长条图片图书

给logo设置背景图片:

    <div style="width: auto;height: auto">
        <h1 id="logo">图书商城</h1>
    </div>

简单的样式:

#logo{
            background-image: url(images/logo.jpg);
            text-align: center;
        }

效果如下:
在这里插入图片描述
然后细微调整轮播图的间距:

<div class="layui-carousel" id="test10" style="margin: 10px;">

layer的使用:

官方参考文档:
链接: https://www.layui.com/doc/modules/layer.html#content.

使用layui的弹出层模块创建用户的修改信息:
在这里插入图片描述
1.layer概述:
layer 至今仍作为 layui 的代表作,它的受众广泛并非偶然,而是这数年来的坚持、不弃的执念,将那些不屑的眼光转化为应得的尊重,不断完善和维护、不断建设和提升社区服务,在 Web 开发者的圈子里口口相传,乃至于成为今天的 layui 最强劲的源动力。目前,layer 已然成为网页弹出层的首先交互方案,几乎随处可见。

2.使用方式:
在这里插入图片描述
如下使用:

<script>
    layui.use('layer', function onAddBtn(){
        //$("#add-form").show();
        //页面层-自定义
        layer.open({
            type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
            title:"修改用户信息",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
            closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
            shift: 2,
            skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
            area: ['600px','500px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
            shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
            //time: 90000, //time - 自动关闭所需毫秒
            anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
            btn: ['新增', '取消'],//模态框自带的最下边的按钮
            //btnAlign: 'c',//btnAlign: 'c'	按钮居中对齐
            content: $("#add-main"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
            success: function(layero, index){},//success - 层弹出后的成功回调方法
            yes: function(index, layero){//yes - 确定按钮回调方法
                //do something
                layer.close(index); //如果设定了yes回调,需进行手工关闭
            }
        });
    });

</script>

弹出层内部的内容:

在这里插入图片描述

在这里插入图片描述

宽高的设置:
在这里插入图片描述

在这里插入图片描述
弹出层坐标:
在这里插入图片描述
图标:
在这里插入图片描述

按钮:
在这里插入图片描述
这里特别注意,按钮一不论什么名字,它的回调都是yes

以下代码可以在在线调试工具中看效果:

layer.open({
  content: 'test'
  ,btn: ['按钮一', '按钮二', '按钮三']
  ,yes: function(index, layero){
    //按钮【按钮一】的回调
    layer.msg("添加成功");
  }
  ,btn2: function(index, layero){
    //按钮【按钮二】的回调
    layer.msg('删除成功',{icon:5});
    //return false 开启该代码可禁止点击该按钮关闭
  }
  ,btn3: function(index, layero){
    //按钮【按钮三】的回调
    layer.msg('取消',{icon:2});
    //return false 开启该代码可禁止点击该按钮关闭
  }
  ,cancel: function(){ 
    //右上角关闭回调
    
    //return false 开启该代码可禁止点击该按钮关闭
  }
});

确认弹出框的使用:

layer.confirm('确定删除吗?', {
  btn: ['确定', '按钮二'] //可以无限个按钮
  
}, function(index, layero){
  //按钮【按钮一】的回调
  layer.msg('确定');
}, function(index){
  //按钮【按钮二】的回调
});

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

提示:

//tips层-上

layer.tips('上', '#id或者.class', {
  tips: [1, '#0FA6D8'] //还可配置颜色
});
//tips层-右

layer.tips('默认就是向右的', '#id或者.class');
//tips层-下

layer.tips('下', '#id或者.class', {
  tips: 3
});
//tips层-左

layer.tips('左边么么哒', '#id或者.class', {
  tips: [4, '#78BA32']
});
//tips层-不销毁之前的

layer.tips('不销毁之前的', '#id或者.class', {
  tipsMore: true
});

在这里插入图片描述

核心功能:使用弹出层做增删改查:

因为layui的特性,每次不管使用哪个组件,都要先把它的模块加载出来
比如我要用layer和form
那么就需要先这样定义,你的操作都是在这个里面进行,当然页可以一次性加载所有模块,详情去看api文档https://www.layui.com/doc/

部分代码:

<script>
    layui.use(['layer','form'], function onAddBtn(){
        var $ = layui.jquery, layer = layui.layer; //独立版的layer无需执行这一句
        var form=layui.form;
        //页面层-自定义
        layer.open({
            type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
            title:"修改用户信息",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
            closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
            shift: 2,
            skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
            area: ['600px','500px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
            shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
            //time: 90000, //time - 自动关闭所需毫秒
            anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
            btn: ['新增', '取消'],//模态框自带的最下边的按钮
            //btnAlign: 'c',//btnAlign: 'c'	按钮居中对齐
            content: $("#add-main"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
            success: function(layero, index){},//success - 层弹出后的成功回调方法
            yes: function(index, layero){//yes - 确定按钮回调方法
                //do something
                //layer.close(index); //如果设定了yes回调,需进行手工关闭
            }
        });
    });

</script>

注意:上面的代码有缺陷:
我们参照修改如下:因为我在使用layui自带的导航栏的时候,她的nav中的a标签我们定义一个单击事件的时候最好使用这种形式:

//nav的a链接:
<a  href="#" onclick="adminsys()" >
//然后调用js的时候要使用如下方式:
<script>
    layui.use(['form','layer','element','carousel'],function () {
        //导航条需要的js
        var $ = layui.$;
        var layer = layui.layer; //独立版的layer无需执行这一句
        var form = layui.form;
        var element = layui.element;
        <!--轮播图的js-->
        var carousel = layui.carousel;
        //图片轮播
        carousel.render({
            elem: '#test10'
            ,width: 'auto'
            ,height: '250px'
            ,interval: 3000
        });
        //事件
        carousel.on('change(test4)', function(res){
            console.log(res)
        });
        //adminsys后台管理方法,<a  href="#" onclick="adminsys()" >这个可行
        window.adminsys =function () {
            alert("test");
            layer.open({
                type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
                title: "登录后台账号",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
                closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
                skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
                area: ['600px', '400px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
                shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
                //time: 90000, //time - 自动关闭所需毫秒
                anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
                //btn: ['新增', '取消'],//模态框自带的最下边的按钮
                //btnAlign: 'c',//btnAlign: 'c'	按钮居中对齐
                content: $("#admin-login"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
                id: 'admin',
                //success: function(layero, index){},//success - 层弹出后的成功回调方法
                yes: function (index, layero) {//yes - 确定按钮回调方法
                    //do something
                    //layer.close(index); //如果设定了yes回调,需进行手工关闭
                }
            });
        };

/*这种也可以可行,但是破坏了原有的样式,不建议*/
        $("#onAddBtn").click(function () {
            layer.open({
                type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
                title: "登录后台账号",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
                closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
                skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
                area: ['600px', '500px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
                shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
                //time: 90000, //time - 自动关闭所需毫秒
                anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
                //btn: ['新增', '取消'],//模态框自带的最下边的按钮
                //btnAlign: 'c',//btnAlign: 'c'	按钮居中对齐
                content: $("#add-main"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
                id: 'admin2',
                //success: function(layero, index){},//success - 层弹出后的成功回调方法
                yes: function (index, layero) {
                    //do something
                    //layer.close(index); //如果设定了yes回调,需进行手工关闭
                }
            });
        });

    });

</script>

在这里插入图片描述

知识拓展:a标签添加onclick事件的几种方式

我们常用的在a标签中有点击事件:

  1. a href=“javascript:js_method();”

这种方法在传递this等参数的时候很容易出问题,而且javascript:协议作为a的href属性的时候不仅会导致不 必要的触发window.onbeforeunload事件,在IE里面更会使gif动画图片停止播放。W3C标准不推荐在href里面执行 javascript语句

  1. a href=“javascript:void(0);” οnclick=“js_method()”

这种方法是很多网站最常用的方法,也是最周全的方法,onclick方法负责执行js函数,而void是一个操作符,void(0)返回undefined,地址不发生跳转。而且这种方法不会像第一种方法一样直接将js方法暴露在浏览器的状态栏。

3.a href=“javascript:;” οnclick=“js_method()”

这种方法跟跟2种类似,区别只是执行了一条空的js代码。

4.a href="#" οnclick=“js_method()”

这种方法也是网上很常见的代码,#是标签内置的一个方法,代表top的作用。所以用这种方法点击后网页后返回到页面的最顶端。

5.a href="#" οnclick=“js_method();return false;”

这种方法点击执行了js函数后return false,页面不发生跳转,执行后还是在页面的当前位置。

6.用Jquery的preventDefault()方法

$(“a”).click(function(event){
event.preventDefault();
});

综合上述,在a中调用js函数最适当的方法推荐使用:
a href=“javascript:void(0);” οnclick=“js_method()”
a href=“javascript:;” οnclick=“js_method()”

a href="#" οnclick=“js_method();return false;”

开发中遇到的bug1:
在这里插入图片描述
数据回显的方法:结合layui的弹出层:

        //数据回显的方法
         window.onUpdateBtn =function () {
            //先查找
             var name = '[[${session.loginUser.name}]]';
            alert(name);
            $.post(
                "/selectUserByName",
                {name:name},
                function (jsonData) {
                    //1.回调函数先把返回的json数据加载到form,此方法loadDatatoForm单独定义好了
                    loadDatatoForm("update-form", jsonData);
                    //2.然后打开弹出层。
                    layer.open({
                        type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
                        title: "登录后台账号",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
                        closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
                        skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
                        area: ['600px', '500px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
                        shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
                        //time: 90000, //time - 自动关闭所需毫秒
                        anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
                        //btn: ['新增', '取消'],//模态框自带的最下边的按钮
                        //btnAlign: 'c',//btnAlign: 'c'	按钮居中对齐
                        content: $("#update-main"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
                        //id: 'admin2',
                        success: function(layero, index){

                        },//success - 层弹出后的成功回调方法
                        yes: function (index, layero) {//yes - 确定按钮回调方法
                            //do something
                            //layer.close(index); //如果设定了yes回调,需进行手工关闭
                        }
                    });
                },
                "json"
            );

            /*layer.open({
                type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
                title: "登录后台账号",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
                closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
                skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
                area: ['600px', '500px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
                shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
                //time: 90000, //time - 自动关闭所需毫秒
                anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
                //btn: ['新增', '取消'],//模态框自带的最下边的按钮
                //btnAlign: 'c',//btnAlign: 'c'	按钮居中对齐
                content: $("#update-main"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
                id: 'admin2',
                success: function(layero, index){

                },//success - 层弹出后的成功回调方法
                yes: function (index, layero) {//yes - 确定按钮回调方法
                    //do something
                    //layer.close(index); //如果设定了yes回调,需进行手工关闭
                }
            });*/
        }

完整代码是放在 layui.use([‘form’,‘layer’,‘element’,‘carousel’],function () {}中的,如下:

<script>
    layui.use(['form','layer','element','carousel'],function () {
        //导航条需要的js
        var $ = layui.$;
        var layer = layui.layer; //独立版的layer无需执行这一句
        var form = layui.form;
        var element = layui.element;
        <!--轮播图的js-->
        var carousel = layui.carousel;
        //图片轮播
        carousel.render({
            elem: '#test10'
            ,width: 'auto'
            ,height: '250px'
            ,interval: 3000
        });
        //事件
        carousel.on('change(test4)', function(res){
            console.log(res)
        });
        //adminsys后台管理方法,<a  href="#" onclick="adminsys()" >这个可行
        window.adminsys =function () {
            //alert("test");
            layer.open({
                type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
                title: "登录后台账号",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
                closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
                skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
                area: ['600px', '400px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
                shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
                //time: 90000, //time - 自动关闭所需毫秒
                anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
                //btn: ['新增', '取消'],//模态框自带的最下边的按钮
                //btnAlign: 'c',//btnAlign: 'c'	按钮居中对齐
                content: $("#admin-login"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
                //id: 'admin',
                //success: function(layero, index){},//success - 层弹出后的成功回调方法
                yes: function (index, layero) {
                    //do something
                    //layer.close(index); //如果设定了yes回调,需进行手工关闭
                }
            });
        };

        //数据回显的方法
         window.onUpdateBtn =function () {
            //先查找
             var name = '[[${session.loginUser.name}]]';
            alert(name);
            $.post(
                "/selectUserByName",
                {name:name},
                function (jsonData) {
                    //1.回调函数先把返回的json数据加载到form,此方法loadDatatoForm单独定义好了
                    loadDatatoForm("update-form", jsonData);
                    //2.然后打开弹出层。
                    layer.open({
                        type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
                        title: "登录后台账号",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
                        closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
                        skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
                        area: ['600px', '500px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
                        shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
                        //time: 90000, //time - 自动关闭所需毫秒
                        anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
                        //btn: ['新增', '取消'],//模态框自带的最下边的按钮
                        //btnAlign: 'c',//btnAlign: 'c'	按钮居中对齐
                        content: $("#update-main"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
                        //id: 'admin2',
                        success: function(layero, index){

                        },//success - 层弹出后的成功回调方法
                        yes: function (index, layero) {//yes - 确定按钮回调方法
                            //do something
                            //layer.close(index); //如果设定了yes回调,需进行手工关闭
                        }
                    });
                },
                "json"
            );

            /*layer.open({
                type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
                title: "登录后台账号",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
                closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
                skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
                area: ['600px', '500px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
                shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
                //time: 90000, //time - 自动关闭所需毫秒
                anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
                //btn: ['新增', '取消'],//模态框自带的最下边的按钮
                //btnAlign: 'c',//btnAlign: 'c'	按钮居中对齐
                content: $("#update-main"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
                id: 'admin2',
                success: function(layero, index){

                },//success - 层弹出后的成功回调方法
                yes: function (index, layero) {//yes - 确定按钮回调方法
                    //do something
                    //layer.close(index); //如果设定了yes回调,需进行手工关闭
                }
            });*/
        }

    });

</script>

加载json数据到form的:

<!--加载json数据到表格loadDatatoForm-->
<script >
    /*回填controller返回的json数据到form表单,将前天数据以json格式返回, @ResponseBody: return book;*/
    function loadDatatoForm(fromId, jsonDate) {
        var obj = jsonDate;
        var key, value, tagName, type, arr;
        for (x in obj) {
            key = x;
            value = obj[x];
            $("#" + fromId + " [name='" + key + "'],#" + fromId + " [name='" + key + "[]']").each(function () {
                tagName = $(this)[0].tagName;
                type = $(this).attr('type');
                if (tagName == 'INPUT') {
                    if (type == 'radio') {
                        $(this).attr('checked', $(this).val() == value);
                    } else if (type == 'checkbox') {
                        try {
                            arr = value.split(',');
                            for (var i = 0; i < arr.length; i++) {
                                if ($(this).val() == arr[i]) {
                                    $(this).attr('checked', true);
                                    break;
                                }
                            }
                        } catch (e) {
                            $(this).attr('checked', value);
                        }
                    } else {
                        $(this).val(value);
                    }
                } else if (tagName == 'TEXTAREA') {
                    $(this).val(value);
                } else if (tagName == 'SELECT') {
                    if ($(this).hasClass("select2")) {
                        $(this).val(value).trigger("change");
                    } else {
                        $(this).val(value);
                    }

                }

            });
        }

    }

</script>

然后紧接着设计修改表单的提交:
做如下准备:将修改表单的action设计成thymleaf的形式:

<form style="margin: 15%;" 
class="layui-form" id="update-form"  th:action="@{/updateUser}">

//提交的按钮
<button type="submit" class="layui-btn"  lay-filter="save" >提交</button>

后台的修改提交:

       @RequestMapping("/updateUser")//修改提交
    public String updateUser(User user, HttpSession session){
        //System.out.println(name);
        System.out.println("前端的参数:"+user);
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("name",user.getName());
        int update = service.getBaseMapper().update(user, updateWrapper);
        if(update!= 0){
            session.setAttribute("loginUser",user);
        }
        return "front/index";
    }

最终效果如下:
在这里插入图片描述

layui的分页:

参考:https://www.cnblogs.com/laowenBlog/p/11240503.html

注意分页之前要的pom依赖和config:
在这里插入图片描述

其中mybatisplus的分页插件如下:

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }
}

1.前台页面分页的功能

后台我们使用MybatisPlus,前端使用thymleaf模板和layui的laypage分页条:

前端的分页我们后台这样写,使用LoginController:

 @RequestMapping("/index.html")//修改成带分页的
    public String toIndex(@RequestParam(required = true,defaultValue = "1",value = "pageNum")String pageNum,
                          @RequestParam(required = false,defaultValue = "4",value = "pageSize")String pageSize,
                          Model model
                          ){
        System.out.println("================"+pageNum);
        System.out.println(pageSize);
        //分页的逻辑,构建分页对对象page
        Page<Book> bookPage = new Page<Book>(Long.valueOf(pageNum),Long.valueOf(pageSize));
        //QueryWrapper<Book> wrapper = new QueryWrapper<>();
        Page<Book> page = bookService.getBaseMapper().selectPage(bookPage, null);
        System.out.println("测试后台的page分页总数:===="+page.getTotal());
        System.out.println("当前页:===="+page.getCurrent());
        System.out.println("每页的条目数:===="+page.getSize());
        System.out.println("总页数:===="+page.getPages());
        System.out.println("数据的记录:===="+page.getRecords());
        model.addAttribute("page",page);
        
        return "front/index";
    }

前端使用layui的栅格和面板来呈现数据和图片:(thymleaf模板引擎)
在这里插入图片描述

<!--栅格系统展示图书-->
<div style="margin: 0 auto; max-width: 1140px;">
    <!--分类标签-->
    <div class="layui-row">
        <div class="layui-col-xs12" style="background-color: white;padding-bottom: 10px">
            <!--分类-->
            <div style="margin-right: 5%;margin-left: 5%;padding-top: 10px" id="typeId">
                <i class="layui-icon layui-icon-template-1"></i>
                <span style="font-weight: bolder;color: #1CAF9A">精选图书</span>
            </div>
        </div>
    </div>
    <!--前端图书列表-->
    <div class="layui-row" >
        <div class="layui-col-xs3" th:each="book : ${page.records}">
            <div class="layui-card">
                <div class="layui-card-header">
                    <!--<img  th:src="@{/images/book/bk4.jpg}">-->
                    <img alt="图片" th:src="${book.getImgPath()}">
                </div>
                <div class="layui-card-body">
                    价格:[[${book.price}]]  &nbsp;&nbsp;| &nbsp;作者:[[${book.author}]]<br>
                    <a style="color: #1CAF9A" href="#">更多信息...</a>
                </div>
            </div>
        </div>

    </div>
    <!--<div class="layui-row">
        <div class="layui-col-xs3">
            <div class="layui-card">
                <div class="layui-card-header">
                    <img  th:src="@{/images/book/bk4.jpg}">
                </div>
                <div class="layui-card-body">
                    价格:99  作者:佚名<br>
                    更多信息...
                </div>
            </div>
        </div>
        <div class="layui-col-xs3">
            <div class="layui-card">
                <div class="layui-card-header">
                    <img  th:src="@{/images/book/bk1.jpg}">
                </div>
                <div class="layui-card-body">
                    价格:99  作者:佚名<br>
                    更多信息...
                </div>
            </div>
        </div>
        <div class="layui-col-xs3">
            <div class="layui-card">
                <div class="layui-card-header">
                    <img  th:src="@{/images/book/bk2.jpg}">
                </div>
                <div class="layui-card-body">
                    价格:99  作者:佚名<br>
                    更多信息...
                </div>
            </div>
        </div>
        <div class="layui-col-xs3">
            <div class="layui-card">
                <div class="layui-card-header">
                    <img  th:src="@{/images/book/bk3.jpg}">
                </div>
                <div class="layui-card-body">
                    价格:99  作者:佚名<br>
                    更多信息...
                </div>
            </div>
        </div>
    </div>-->
    <!--前端分页导航-->
    <div class="layui-row">
        <div class="layui-col-xs12" style="background-color: white">
            <!--前端分页-->
            <div style="margin-right: 10%;margin-left: 10%" id="demo7"></div>
        </div>
    </div>
    <!--底部导航-->
    <div class="layui-row">
        <div class="layui-col-xs12" style="background-color: #1CAF9A;padding-top: 20px;padding-bottom: 20px">
            <!--前端分页-->
            <div style="width: 50%;margin-left: auto;margin-right: auto" >
                <h5 style="text-align: center">© 2021 layui.com MIT license</h5>
                <h5 style="text-align: center">
                    <a href="#" class="">免责声明</a>
                    <a href="#">公众号</a>
                    <a href="#">友情链接</a>
                    <a href="#">联系我</a>
                </h5>
            </div>
        </div>
    </div>


</div>

如果是jsp页面可以这样写:

在这里插入图片描述

在这里插入图片描述

数据库中mysql图片地址格式:注意不写static前缀。
在这里插入图片描述

2.layui的跳转链接实现分页的js:

将前端的多个静态div换成后台遍历的,如下:

    <!--分类标签-->
    <div class="layui-row">
        <div class="layui-col-xs12" style="background-color: white;padding-bottom: 10px">
            <!--分类-->
            <div style="margin-right: 5%;margin-left: 5%;padding-top: 10px" id="typeId">
                <i class="layui-icon layui-icon-template-1"></i>
                <span style="font-weight: bolder;color: #1CAF9A">精选图书</span>
            </div>
        </div>
    </div>
    <!--前端图书列表-->
    <div class="layui-row" >
        <div class="layui-col-xs3" th:each="book : ${page.records}">
            <div class="layui-card">
                <div class="layui-card-header">
                    <!--<img  th:src="@{/images/book/bk4.jpg}">-->
                    <img alt="图片" th:src="${book.getImgPath()}">
                </div>
                <div class="layui-card-body">
                    价格:[[${book.price}]]  &nbsp;&nbsp;| &nbsp;作者:[[${book.author}]]<br>
                    <a style="color: #1CAF9A" href="#">更多信息...</a>
                </div>
            </div>
        </div>

    </div>
   
    <!--分页条的开始-->
    <div class="layui-row">
        <div class="layui-col-xs12" style="background-color: white">
            <!--前端分页-->
            <div style="margin-right: 10%;margin-left: 10%" id="demo7"></div>
        </div>
    </div>
    <!--分页条的结束-->

然后写分页的js代码:(用的是thymleaf模板,th:inline="javascript"用于行内取值[[]]用。)

<script th:inline="javascript">
    layui.use(['form','layer','element','carousel','laypage'],function () {
        //导航条需要的js
        var $ = layui.$;
        var layer = layui.layer; //独立版的layer无需执行这一句
        var form = layui.form;
        var element = layui.element;
       
        var carousel = layui.carousel;
        var laypage = layui.laypage;
 //前端分页完整功能开始
        var total = [[${page.total}]];//总条目数
         var limit_ = [[${page.size}]];//每页的显示条数
         var last_ = [[${page.pages}]];
         var current_ = [[${page.current}]];//当前页
        laypage.render({
            elem: 'demo7' //分页条坐在的id#demo7
            ,count: total //数据总数。一般通过服务端得到
            ,pages: [[${page.pages}]] //总页数
            ,limit: limit_ //每页显示的条数。laypage将会借助 count 和 limit 计算出分页数。
            ,limits: [4,8] //下拉选择每页展示的条目数,每页条数的选择项。
            ,groups: 4 //连续出现的页码个数
            ,curr:current_ //当前页
            ,first: 1 //不起作用
            ,last: last_ //不起效果
            ,layout: ['count', 'prev', 'page', 'next', 'limit', 'refresh', 'skip'] //自定义排版。可选值有:count(总条目输区域)、prev(上一页区域)、page(分页区域)、next(下一页区域)、limit(条目选项区域)、refresh(页面刷新区域。注意:layui 2.3.0 新增) 、skip(快捷跳页区域)
            ,jump: function(obj, first){
                console.log(obj);
                if (!first) {//如果不是第一页,跳转页面
                    var pageSize=obj.limit;得到每页显示的条数
                    var pageNum=obj.curr;//得到当前页,以便向服务端请求对应页的数据。固定写法
                    window.location.href="/index?pageNum="+pageNum+"&pageSize="+pageSize;//跳转链接
                }
            }
        });
        //前端分页完整功能结束
});

最终效果展示:
在这里插入图片描述

3.前端页面的条件查询:

注意一下form表单的数据回显:
动态条件查询的表单:

 <form class="navbar-form navbar-right" th:action="@{/index}" method="get" style="margin-right: 15%;margin-top: 14px">
     <div class="form-group">
         <input type="text" id="bookName" name="name" class="form-control" placeholder="请输入图书名" th:value="${param.name}" >
     </div>
     <button type="submit" class="btn btn-default">查找</button>
 </form>

此时将数据回显的行内写法的[[]]上的单引号去掉,script 标签上加th:inline=“javascript”

然后在原先分页的基础上修改如下代码:

window.location.href="/index?pageNum="+pageNum+"&pageSize="+pageSize+"&name="+name;//跳转链接

修改后台代码:

//定义查询全局/成员变量
QueryWrapper<Book> wrapper;
@RequestMapping({"/index.html","/index"})//修改成带分页的
    public String toIndex(
            @RequestParam(required = false,value = "name")String name,
            @RequestParam(required = true,defaultValue = "1",value = "pageNum")String pageNum,
                          @RequestParam(required = false,defaultValue = "4",value = "pageSize")String pageSize,
                          Model model
                          ){
        System.out.println("================"+pageNum);
        System.out.println("========bookname========"+name);
        System.out.println(pageSize);
        //分页的逻辑,构建分页对对象page
        Page<Book> bookPage = new Page<Book>(Long.valueOf(pageNum),Long.valueOf(pageSize));
        wrapper=null;//让查询条件为空,这一步很关键。当我们清空输入框内容,点击查询则查询所有。
        if(!"".equals(name) && name != null){
            wrapper = new QueryWrapper<>();
            wrapper.like("name",name);
        }
        System.out.println("wrapper===="+wrapper);
        Page<Book> page = bookService.getBaseMapper().selectPage(bookPage, wrapper);
        System.out.println("测试后台的page分页总数:===="+page.getTotal());

        System.out.println("当前页:===="+page.getCurrent());
        System.out.println("每页的条目数:===="+page.getSize());
        System.out.println("总页数:===="+page.getPages());
        System.out.println("数据的记录:===="+page.getRecords());
        model.addAttribute("page",page);
        
        return "front/index";
    }

效果:
在这里插入图片描述

在这里插入图片描述

登录后台管理界面:

遇到问题的解决参考链接:https://www.jb51.net/article/171150.htm

(1).利用ajax发送请求:
开发中有一个需求是:发送ajax请求并发生页面跳转:

一般情况下是不能发送ajax请求的同时并进行页面跳转的。
ajax 本身是不适用于页面跳转的;

可以借助其他方法实现:

1,window.location.href = “/home”;

2,springMVC 返回的modelAndView (redirect:xxx)

两者用一个即可。

核心代码如下:
ajax请求最好只用于发送数据,和从后端拿数据,不要做跳转页面的…如果一定要做页面的跳转,可以约定后端放回的数据为1或0,当返回的数据为1时,用Windows.location.href="index.html"来跳转

function (dat) {
                    if (dat==1){//返回一个1字符串或者0,json形式的。
                        window.location.href="/toadminHtml" ;
                    }else {
                        alert("0");
                    }
                }

否则就用submit提交,记住了,ajax用于发送请求到那个方法后,后端是跳转不了页面的,也不会报错,因为ajax用于默认是异步请求,如果要跳就在前端跳转页面也是可以的

(2)过程实现:
在这里插入图片描述
点击后台管理的nav,使用layui的弹出层弹出一个form登录表单:
form表单设置成隐藏的(dispaly:none)
后台登录系统form表单:

<!--后台登录的表单-->
<div id="admin-login"  style="display:none;">
    <form style="margin: 15%;" class="layui-form" id="admin-form"  action="">
        <div class="layui-form-item">
            <label class="layui-form-label" style="width: 100px">名字&emsp;</label>
            <div class="layui-input-block">
                <input name="name" id="admin_name" type="text"    style="width: 240px"  placeholder="请输入账户名称" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label" style="width: 100px">密码&emsp;</label>
            <div class="layui-input-block">
                <input name="password" id="admin_password" type="text"    style="width: 240px"  placeholder="请输入密码" autocomplete="off" class="layui-input">
            </div>
        </div>

        <div class="layui-form-item">
            <div class="layui-input-block">
                <button type="button" id="admin_save" class="layui-btn"   >登录</button>
                <button type="button" class="layui-btn layui-btn-primary" id="closeBtn-admin" >重置</button>
            </div>
        </div>
    </form>
</div>

js代码如下:

       //adminsys后台管理方法,<a  href="#" onclick="adminsys()" >这个可行
        window.adminsys =function () {
            //alert("test");
            layer.open({
                type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
                title: "登录后台账号",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
                closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
                skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
                area: ['600px', '400px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
                shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
                //time: 90000, //time - 自动关闭所需毫秒
                anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
                //btn: ['提交'],//模态框自带的最下边的按钮
                //btnAlign: 'c',//btnAlign: 'c'	按钮居中对齐
                content: $("#admin-login"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
                //id: 'admin',
                success: function(layero, index){//success - 层弹出后的成功回调方法
                    /*后台管理系统登录的ajax开始*/
                    $("#admin_save").click(function() {
                        //alert("后台管理系统");
                        var admin_name = $("#admin_name").val();
                        var admin_password = $("#admin_password").val();
                        $.post(
                            "/selectUserByNameAndPwd",
                            {"name":admin_name,"password":admin_password},
                            function (dat) {
                                if (dat==1){//返回一个1字符串或者0,json形式的。
                                    window.location.href="/toadminHtml" ;
                                }else {
                                    alert("1")
                                }
                            }
                        );
                        //layer.close(index);//点击登录的时候将层关闭

                    });
                    /*后台管理系统登录的ajax结束*/
                    //layer.close(index);
                },
                yes: function (index, layero) {
                    //do something
                    //layer.close(index); //如果设定了yes回调,需进行手工关闭
                }
            });
        };

后台controller的代码:

    //登录后台管理系统
    @RequestMapping("/selectUserByNameAndPwd")
    @ResponseBody
    public String selectUserByNameAndPwd( @RequestParam(required = true,value = "name") String name,
                                        @RequestParam(required = true,value = "password") String password,
                                        HttpSession session,
                                        Model model){//查找方法,只用于回显数据
        //System.out.println(name);
        System.out.println("前端的参数ajax发送的=====:"+name+",password:"+password);
        User adminUser = service.getLoginUserByNameAndPwd(name,password);
        if(adminUser != null){
            session.setAttribute("adminUser",adminUser);
            //跳转到后台页面
            System.out.println("跳转后台页面----");
            return "1";
        }else{
            model.addAttribute("admin_msg","用户名或者密码不正确");
            return "0";
        }
    }
    @RequestMapping("/toadminHtml")
    public String toadminTest(Model model){
        return "admin/adminx";
    }

效果:我们从layui的官网上找到文档–>布局–>滚轴拉到最下找到:管理系统界面布局,整个代码复制过来使用。
在这里插入图片描述

LayUI的基本使用 - Tab选项卡切换显示对应数据

参考官方链接:https://www.layui.com/doc/modules/element.html#use

基本的实现效果:
在这里插入图片描述
需求:将对应的数据表格放到选项卡内容区进行展示:
1.1 先给每一个Tab选项卡一个属性lay-id=""、用来存放id值。具体代码如下:

<!--头部tab选项卡开始-->
<div class="layui-tab layui-tab-card layui-layout-left " style="background-color: white;" lay-filter="demo" lay-allowclose="true">
    <ul class="layui-tab-title" style="height: 60px;line-height: 60px;margin-top: -10px;margin-left: -0.5px;">
        <li class="layui-this" lay-id="11" style="height: 60px;line-height: 60px">图书管理</li>
        <li lay-id="22" style="height: 60px;line-height: 60px">用户管理</li>
        <li lay-id="33" style="height: 60px;line-height: 60px">权限分配</li>
        <li lay-id="44" style="height: 60px;line-height: 60px">商品管理</li>
        <li lay-id="55" style="height: 60px;line-height: 60px">订单管理</li>
    </ul>
    <!--tab选项卡下对应的内容-->
    <div class="layui-tab-content" style="width: 1000px;height: 1500px;">
        <div class="layui-tab-item layui-show">内容1</div>
        <div class="layui-tab-item">内容2</div>
        <div class="layui-tab-item">内容3</div>
        <div class="layui-tab-item">内容4</div>
        <div class="layui-tab-item">内容5</div>
    </div>
</div>
<!--头部tab选项卡结束-->

2.2 获取对应的值。在官网手册文档上、我们可以找到监听Tab切换事件

在这里插入图片描述

在这里插入图片描述
删除商品事件:

在这里插入图片描述
在这里插入图片描述

触发选项卡切换:
对应的代码:

 //tab切换事件,触发选项卡切换
 element.on('tab(layui_tab)', function(data){
     console.log("*************");
     console.log(this); //当前Tab标题所在的原始DOM元素
     console.log(data.index); //得到当前Tab的所在下标
     console.log(data.elem); //得到当前的Tab大容器
     var lay_id = $(this).attr('lay-id');
     console.log(lay_id);
     console.log("*************");
 });

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

table数据渲染(render):

 //table渲染
 table.render({
     elem: '#book_table'//指定原始表格元素选择器(推荐id选择器)
     ,height: 400//容器高度,高度不能太高,不然影响分页条的显示
     ,url: '/getBookByPage' //数据接口,异步数据接口相关参数。其中 url 参数为必填项,相当于发送一个ajax请求
     ,limit: 3//每页显示的条数(默认 10)。值需对应 limits 参数的选项。注意:优先级低于 page 参数中的 limit 参数
     ,limits: [3,5,10,20]//每页条数的选择项,默认:[10,20,30,40,50,60,70,80,90]。注意:优先级低于 page 参数中的 limits 参数
     ,request: {
         pageName: 'pageNum' //页码的参数名称,默认:page
         ,limitName: 'pageSize' //每页数据量的参数名,默认:limit
     }
     ,page: true //开启分页
     ,cellMinWidth: 60//全局定义所有常规单元格的最小宽度
     ,skin: 'line' //行边框风格
     ,even: true //开启隔行背景
     ,cols: [[ //设置表头
          {type:'checkbox',fixed: 'left'}//左边固定多选框的设定,横向滚动条的设定.layui-body{overflow-y: scroll;}
         ,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left'}
         ,{field: 'name', title: '书名', width:100}
         ,{field: 'price', title: '价格', width:70, sort: true}
         ,{field: 'author', title: '作者', width:80}
         ,{field: 'sales', title: '销量', width: 70,sort: true}
         ,{field: 'stock', title: '库存', width: 70, sort: true}
         ,{field: 'create_time', title: '创建时间', width: 120, sort: true,templet:function(d){return util.toDateString(d.commPosttime*1000, "yyyy-MM-dd HH:mm:ss");}}
         ,{field: 'update_time', title: '修改时间', width: 120,sort: true,templet:function(d){return util.toDateString(d.commPosttime*1000, "yyyy-MM-dd HH:mm:ss");}}
         ,{fixed: 'right', title: '操作',width:170, align:'center', toolbar: '#barDemo'} //这里的toolbar值是模板元素的选择器
     ]]
 });

上面的数据表格渲染代码需要写到以下代码中:

//预先加载各种内置模块
 layui.use(['element', 'layer', 'util','table'], function(){
        var element = layui.element
            ,layer = layui.layer
            ,util = layui.util
            ,table = layui.table
            ,$ = layui.$;
}

各项参数详情请参照官网进行对应设置:
在这里插入图片描述

在这里插入图片描述
重要参数1: url: ‘/getBookByPage’ //数据接口,异步数据接口相关参数。其中 url 参数为必填项,相当于发送一个ajax请求,并收到后台的json数据

重要参数2:request参数的作用:用于对分页请求的参数:page、limit重新设定名称,如:
在这里插入图片描述
在这里插入图片描述

重要参数3:
{fixed: ‘right’, title: ‘操作’,width:170, align:‘center’, toolbar: ‘#barDemo’} //这里的toolbar值是模板元素的选择器

作用:toolbar - 绑定工具条模板:

通常你需要在表格的每一行加上 查看、编辑、删除 这样类似的操作按钮,而 tool 参数就是为此而生,你因此可以非常便捷地实现各种操作功能。tool 参数和 templet 参数的使用方式完全类似,通常接受的是一个选择器,也可以是一段HTML字符。

下述是 toolbar 对应的模板,它可以存放在页面的任意位置:

<script type="text/html" id="barDemo">
  <a class="layui-btn layui-btn-xs" lay-event="detail">查看</a>
  <a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
  <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>

</script>
 
注意:属性 lay-event="" 是模板的关键所在,值可随意定义。

后台代码(使用Mybatis-plus):


    @Resource
    private IBookService bookService;
    
    //getBookByName
    @RequestMapping("/getBookByPage")
    @ResponseBody//返回json
    public Map<String,Object> getBookByPage(
                                @RequestParam(required = true,defaultValue = "1",value = "pageNum")String pageNum,
                                @RequestParam(required = false,defaultValue = "3",value = "pageSize")String pageSize,
                                Model model
    ){
        Page<Book> bookPage = new Page<Book>(Long.valueOf(pageNum),Long.valueOf(pageSize));
        Page<Book> page = bookService.getBaseMapper().selectPage(bookPage, null);
        Map<String,Object> map = new LinkedHashMap<String,Object>();//自己设置一个map,将code,msg放进去。
        map.put("code","0");//注意状态必须是0,0代表成功
        map.put("msg","成功");
        map.put("count",page.getTotal());
        map.put("data",page.getRecords());
        return map;//返回json
    }

然后最终效果:
在这里插入图片描述
注意如果底下的分页条不显示,请重新设置height参数:

 table.render({
            elem: '#book_table'//指定原始表格元素选择器(推荐id选择器)
            ,height: 400//容器高度,高度不能太高,不然影响分页条的显示

toolbar:表格头部工具条
在这里插入图片描述
在这里插入图片描述

代码演示:
在这里插入图片描述
defaultToolbar - 头部工具栏右侧图标

注意:toolbar参数有的话,头部工具栏右侧图标默认有。
在这里插入图片描述

done - 数据渲染完的回调

在这里插入图片描述

在这里插入图片描述

是否开启合并行totalRow:true/false
在这里插入图片描述

text - 自定义文本
在这里插入图片描述

在这里插入图片描述

合计功能开启:

在这里插入图片描述

单元格可编辑开启:
在这里插入图片描述
比如:

{field: 'name', title: '书名', width:100,edit:true}

模板语法:
在这里插入图片描述

在这里插入图片描述

总结表头参数:
在这里插入图片描述

数据表格的监听事件:

1.头部监听事件:

在这里插入图片描述

2.触发复选框选择
点击复选框时触发,回调函数返回一个 object 参数:

table.on('checkbox(test)', function(obj){//test位数据表格的lay-filter
  console.log(obj); //当前行的一些常用操作集合
  console.log(obj.checked); //当前是否选中状态
  console.log(obj.data); //选中行的相关数据
  console.log(obj.type); //如果触发的是全选,则为:all,如果触发的是单选,则为:one
});

3.触发单元格编辑
前提是单元格可以被编辑,在字段设置上添加edit:true;
单元格被编辑,且值发生改变时触发,回调函数返回一个object参数,携带的成员如下:

table.on('edit(test)', function(obj){ //注:edit是固定事件名,test是table原始容器的属性 lay-filter="对应的值"
  console.log(obj.value); //得到修改后的值
  console.log(obj.field); //当前编辑的字段名
  console.log(obj.data); //所在行的所有相关数据  
});

在这里插入图片描述
4.触发行单双击事件
注意,单击事件和双击事件只能有一个
点击或双击行时触发。该事件为 layui 2.4.0 开始新增

//触发行单击事件
table.on('row(test)', function(obj){
  console.log(obj.tr) //得到当前行元素对象
  console.log(obj.data) //得到当前行数据
  //obj.del(); //删除当前行
  //obj.update(fields) //修改当前行数据
});
 
//触发行双击事件
table.on('rowDouble(test)', function(obj){
  //obj 同上
});

5.触发行中工具条点击事件

//行工具条事件
table.on('tool(test)', function(obj){ //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
  var data = obj.data; //获得当前行数据
  var layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
  var tr = obj.tr; //获得当前行 tr 的 DOM 对象(如果有的话)
 
  if(layEvent === 'detail'){ //查看
    //do somehing
  } else if(layEvent === 'del'){ //删除
    layer.confirm('真的删除行么', function(index){
      obj.del(); //删除对应行(tr)的DOM结构,并更新缓存
      layer.close(index);
      //向服务端发送删除指令
    });
  } else if(layEvent === 'edit'){ //编辑
    //do something
    
    //同步更新缓存对应的值
    obj.update({
      username: '123'
      ,title: 'xxx'
    });
  } else if(layEvent === 'LAYTABLE_TIPS'){
    layer.alert('Hi,头部工具栏扩展的右侧图标。');
  }
});

基础方法:
1.获取选中行:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
第二种表格重载:
在这里插入图片描述
在这里插入图片描述

利用弹出层做表格的增删改查:

动态查询表单的制作:

在这里插入图片描述

在这里插入图片描述
打开新增form弹出层:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

监听修改事件:注意使用lay-filter在每一行的编辑按钮上;
在这里插入图片描述
打开修改弹出层:
在这里插入图片描述
修改表单数据的回显:
在这里插入图片描述

新增表单数据的清空:
在这里插入图片描述

表单提交事件:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码演示:
前端的html

<!--user头部左边工具条,使用按钮组-->
<div style="display: none" id="user_tool_bar">
    <div >
        <button type="button" class="layui-btn layui-btn-sm" lay-event="u-add">增加</button>
        <button type="button" class="layui-btn layui-btn-sm" lay-event="u-deleteAll">批量删除</button>
    </div>
</div>
<!--user用户添加/修改的表单弹出层开始-->
<div id="add_user"  style="display:none;">
    <form style="margin: 15%;" class="layui-form" id="user-form" lay-filter="user-form"  action="">
        <input name="id" id="user_id" type="hidden"    style="width: 240px"  placeholder="id" autocomplete="off" class="layui-input">
        <div class="layui-form-item">
            <label class="layui-form-label" style="width: 100px">姓名&emsp;</label>
            <div class="layui-input-block">
                <input name="name" id="user_name" type="text"  lay-verify="required"    style="width: 240px"  placeholder="请输入用户名" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label" style="width: 100px">年龄&emsp;</label>
            <div class="layui-input-block">
                <input name="age" id="user_price" type="text" lay-verify="required" th:value="${param.age}"    style="width: 240px"  placeholder="请输入年龄" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label" style="width: 100px">邮箱&emsp;</label>
            <div class="layui-input-block">
                <input name="email" id="user_email" type="text" lay-verify="required"    style="width: 240px"  placeholder="请输入邮箱" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label" style="width: 100px">密码&emsp;</label>
            <div class="layui-input-block">
                <input name="password" id="user_password" type="text" lay-verify="required"   style="width: 240px"  placeholder="请输入密码" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label" style="width: 100px">电话&emsp;</label>
            <div class="layui-input-block">
                <input name="phone" id="user_phone" type="text" lay-verify="required"   style="width: 240px"  placeholder="请输入电话" autocomplete="off" class="layui-input">
            </div>
        </div>

        <div class="layui-form-item">
            <div class="layui-input-block">
                <button type="button" id="save_user" class="layui-btn" lay-submit="" lay-filter="save_user" >提交</button>
                <button type="reset" class="layui-btn layui-btn-primary" id="closeBtn-user" >重置</button>
            </div>
        </div>
    </form>
</div>
<!--user用户添加/修改的表单弹出层结束-->
<!--user行操作工具条开始-->
<script type="text/html" id="userbarDemo">
    <a class="layui-btn layui-btn-xs" lay-event="u-detail">查看</a>
    <a class="layui-btn layui-btn-xs" lay-event="u-edit">编辑</a>
    <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="u-del">删除</a>
</script>
<!--user行操作工具条结束-->

前端的js:

layui.use(['element', 'layer', 'util','table','form'], function(){
        var element = layui.element
            ,layer = layui.layer
            ,util = layui.util
            ,table = layui.table
            ,form = layui.form
            ,$ = layui.$;
/* ===============================用户的js开始==================================================*/
        var totalRecord ;//总记录数
        var mycurr;//当前页码
        var currPageSize ;//当前页的实际数据量
        //用户table渲染
        var userTableIns=table.render({
            id:'user_table'
            ,elem: '#user_table'//渲染的目标对象,指定原始表格元素选择器(推荐id选择器),  <table id="book_table"
            ,height: 330//容器高度,高度不能太高,不然影响分页条的显示;'full-300'可用高度减去300
            ,url: '/getUserByPage' //数据接口,异步数据接口相关参数。其中 url 参数为必填项,相当于发送一个ajax请求
            ,title : '用户数据表'//数据导出来的标题
            ,toolbar : '#user_tool_bar'//头部工具条,这里我们跟一个选择器
            //,totalRow:true //开启合并行
            ,text:{ none: '暂无相关数据' }//默认:无数据。没有数据的时候的提示信息
            ,limit: 3//每页显示的条数(默认 10)。值需对应 limits 参数的选项。注意:优先级低于 page 参数中的 limit 参数
            ,limits: [3,5,10,20]//每页条数的选择项,默认:[10,20,30,40,50,60,70,80,90]。注意:优先级低于 page 参数中的 limits 参数
            ,request: {
                pageName: 'pageNum' //页码的参数名称,默认:page
                ,limitName: 'pageSize' //每页数据量的参数名,默认:limit
            }
            ,page: true //开启分页
            ,cellMinWidth: 60//全局定义所有常规单元格的最小宽度
            ,skin: 'line' //行边框风格
            ,even: true //开启隔行背景
            ,cols: [[ //设置用户的表头
                {type:'checkbox',fixed: 'left'}//左边固定多选框的设定,横向滚动条的设定.layui-body{overflow-y: scroll;}
                ,{type:'numbers',fixed: 'left',title: '序号',totalRowText:'合计'} //numbers(序号列)
                ,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left',hide:true}
                ,{field: 'name', title: '用户名', width:100,edit:true,align: 'center'}
                ,{field: 'email', title: '邮箱', width:180, sort: true}
                ,{field: 'password', title: '密码', width:80}
                ,{field: 'phone', title: '电话', width: 170}
                ,{fixed: 'right', title: '操作',width:170, align:'center', toolbar: '#userbarDemo'} //这里的toolbar值是模板元素的选择器
            ]]
            ,done: function(res, curr, count){//数据渲染完的回调。你可以借此做一些其它的操作
            //如果是异步请求数据方式,res即为你接口返回的信息。
            //如果是直接赋值的方式,res即为:{data: [], count: 99} data为当前页数据、count为数据总长度
            console.log(res);
            console.log(res.data.length);//当前页的实际数据量
                currPageSize = res.data.length;
            //得到当前页码
            console.log(curr);
             mycurr = curr;//将后台数据赋值给前台当前页
            //得到数据总量
            console.log(count);
            totalRecord = count;//将数据总量赋值给全局的变量
        }
        });

        //user头部工具条事件
        table.on('toolbar(userTable)', function(obj) {//userTable为user数据表的filter
            var checkStatus = layui.table.checkStatus("user_table");//user表格被选中的状态,找table位置的id
            switch(obj.event){
                case 'u-add':
                    layer.msg('添加');
                    opeAddUser();//调用打开添加弹出层
                    break;
                case 'u-deleteAll':
                    layer.msg('批量删除');
                    batchDelUserByIds(checkStatus);//调用批量删除的方法
                    break;
            };

        });

        //定义批量删除的方法:
        function batchDelUserByIds(checkStatus) {//checkStatus为user表格选中状态
            alert("批量删除");
            //当一页数据全部删除,出现无数据的bug
            var ids = '';//定义一个空字符串。放id
            var data = checkStatus.data;//获取所有选中行的数据,是数组
            console.log(data);

            for (var i=0;i<data.length;i++){
                ids+= checkStatus.data[i].id + ',' ;//串联字符换id
            }
            ids = ids.substring(0,ids.length-1);//去掉做后一个,
            console.log(ids);
            if(data.length==currPageSize){//如果选中批量删除的数据量等于每页显示的条数,回到上一页
                mycurr=mycurr-1;//定位到上一页
            }
            $.post(//发送ajax的post请求
                "/batchDelUserByIds",
                {"ids":ids},//格式是key:value
                function (dat) {//成功之后的回调函数
                    console.log(dat);
                    userTableIns.reload({url:'/getUserByPage',page:{
                        curr:mycurr //重新回到前一页
                        }},true);//刷新数据
                }
            );

        };

        //user行工具条事件
        table.on('tool(userTable)', function(obj){ //注:tool 是工具条事件名,userTable 是 table 原始容器的属性 lay-filter="对应的值"
            var data = obj.data; //获得当前行数据
            var layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
            if(layEvent === 'u-detail'){ //查看
                //do somehing
                layer.msg("查看")
            } else if(layEvent === 'u-del'){ //删除,这里事件名字修改一下
                layer.confirm('真的删除吗?', function(index){//在此layer.confirm中调用删除方法
                    obj.del(); //删除对应行(tr)的DOM结构,并更新缓存
                    layer.close(index);
                    //向服务端发送删除指令
                    delById(data);//删除的方法调用,u-del
                });
            } else if(layEvent === 'u-edit'){ //编辑
                //do something
                layer.msg("编辑");
                openUpdateUser(data);//调用此方法,data参数为当前行数据,此处定义两个方法,隐藏的那个div是公用的

            } else if(layEvent === 'LAYTABLE_TIPS'){
                layer.alert('Hi,头部工具栏扩展的右侧图标。');
            }

        });

        var userurl;//动态的url
        var mainUserIndex;//定义user的form新增/修改的公共弹出层
        //打开用户添加的方法
        function opeAddUser(){//新增不需要传参数
            mainUserIndex=layer.open({
                id: 'userlayer',
                type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
                title: "添加用户",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
                closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
                skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
                area: ['600px', '500px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
                shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
                anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
                content: $("#add_user"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
                success: function(layero, index){//成功打开页面之后的回调函数
                    //新增的方法需要先清空表单数据
                    $("#user-form")[0].reset();
                    userurl="/addUser";//,成功打开弹出层之后,动态的给url赋值
                },
            });
        };
        //打开修改页面的方法
        function openUpdateUser(data){//传递的参数是修改的数据
            mainUserIndex=layer.open({
                type: 1,//type - 基本层类型,layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)。 若你采用layer.open({type: 1})方式调用,则type为必填项(信息框除外)
                title: "修改用户",//模态框的左上角的标题,如果你不想显示标题栏,你可以title: false
                closeBtn: 1,//closeBtn - 右上关闭按钮,可通过配置1和2来展示,如果不显示,则closeBtn: 0
                skin: 'layui-layer-molv',//skin - (皮肤)样式类名,两种内置的layui-layer-lan,layui-layer-molv
                area: ['600px', '500px'],//模态框的大小,在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area: '500px',高度仍然是自适应的。当你宽高都要定义时,你可以area: ['500px', '300px']
                shadeClose: true,//开启遮罩关闭,如果你的shade是存在的,那么你可以设定shadeClose来控制点击弹层外区域关闭。
                anim: 5,//anim: 0	平滑放大。默认;anim: 5	渐显;anim: 1	从上掉落等
                content: $("#add_user"),//加载的内容,这里可以是一个隐藏的div,form等,#add-main尾div的id
                success: function(layero, index){
                    form.val("user-form",data);//第一个参数是form的id的filter,给表单赋值,data为这一行的数据
                    userurl="/updateUser";//动态给url赋值,在提交的时候用
                },
            });
        };
        //删除的方法
        function delById(data){
            //alert(data.id);
            //向服务端发送删除指令
            $.get(
                '/delUserById',
                {"id":data.id},
                function (dat) {
                    if(dat==200){
                        obj.del(); //删除对应行(tr)的DOM结构,并更新缓存
                    }
                }
            );
            //layer.close(index);//不能少了这一行
        };
        //保存,用户的submit提交事件
        form.on('submit(save_user)', function(data){//form表单提交按钮的lay-filter="save_user"
            var params = $("#user-form").serialize();//序列化表单数据
            //alert(params);
            //alert(userurl);
            $.post(
                userurl,//动态的url
                params,//或者使用{"key":value}
                function (obj) {
                    layer.msg("成功");
                    //关闭弹出层
                    layer.close(mainUserIndex);
                    //获取每页显示的记录数、当前记录总数,计算新添加的记录在第几页
                    console.log("-------------------");
                    totalRecord +=1;//总记录数,totalRecord的值是在表格渲染的done回调函数中赋值的。
                    console.log(totalRecord);
                    var pageSize = $(".layui-laypage-limits").find("select").val();
                    console.log("-------------------");
                    console.log(pageSize);
                    if($.type(pageSize) == "string"){
                        pageSize = parseInt(pageSize);
                    }
                    var lastCurrPageNo = Math.ceil(totalRecord / pageSize);//计算最后一页的页码数
                    console.log("每页显示的记录数:"+pageSize+" 类型:"+$.type(pageSize)+" 总的记录数:"+totalRecord+" 类型:"+$.type(totalRecord)
                        +" 新增行所在页码:"+lastCurrPageNo+" 类型:"+$.type(lastCurrPageNo));
                    //刷新表格数据,直接定位到了当前修改的地方,厉害
                    if(userurl=="/addUser"){//如果是新增,则携带最后一个的参数
                        userTableIns.reload({url:'/getUserByPage',
                            page : {
                                curr : lastCurrPageNo//page参数中携带当前页
                            },
                        },true);
                    }else{//如果是修改,则使用默认参数
                        userTableIns.reload({url:'/getUserByPage'},true);
                    }

                }
            );

        });
    });

后台代码:

package com.fan.bookshop.controller;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fan.bookshop.entity.User;
import com.fan.bookshop.service.IUserService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author fan
 * @since 2021-05-26
 */
@Controller
public class UserController {
    @Resource
    private IUserService userservice;

    @RequestMapping("/addUser")
    public String addUser( User user){
        //System.out.println(name);
        System.out.println("前端的参数:"+user);
        int i = userservice.getBaseMapper().insert(user);
        return "front/login";
    }

    @RequestMapping("/selectUserByName")
    @ResponseBody
    public User selectUserByName( String name){//查找方法,只用于回显数据
        //System.out.println(name);
        System.out.println("前端的参数:"+name);
        User loginUserByName = userservice.getLoginUserByName(name);
        return loginUserByName;//返回json数据
    }

    //登录后台管理系统
    @RequestMapping("/selectUserByNameAndPwd")
    @ResponseBody
    public String selectUserByNameAndPwd( @RequestParam(required = true,value = "name") String name,
                                        @RequestParam(required = true,value = "password") String password,
                                        HttpSession session,
                                        Model model){//查找方法,只用于回显数据
        //System.out.println(name);
        System.out.println("前端的参数ajax发送的=====:"+name+",password:"+password);
        User adminUser = userservice.getLoginUserByNameAndPwd(name,password);
        if(adminUser != null){
            session.setAttribute("adminUser",adminUser);
            //跳转到后台页面
            System.out.println("跳转后台页面----");
            return "1";
        }else{
            model.addAttribute("admin_msg","用户名或者密码不正确");
            return "0";
        }
    }
    @RequestMapping("/toadminHtml")
    public String toadminTest(Model model){
        return "admin/adminx";
    }

    @RequestMapping("/updateUser")//修改提交,注意修改是不需要分页参数的
    public String updateUser(
            User user
    ){
        //System.out.println(name);
        System.out.println("前端的参数:"+user);
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",user.getId());
        int update = userservice.getBaseMapper().updateById(user);
        HashMap<String, Object> map = new HashMap<>();
        return "admin/adminx";
    }

    //分页getUserByPage
    @ResponseBody
    @RequestMapping("/getUserByPage")
    public Map<String,Object> getUserByPage(@RequestParam(required = true,defaultValue = "1",value = "pageNum")String pageNum
                                , @RequestParam(required = false,defaultValue = "3",value = "pageSize")String pageSize
                                ){
        Page<User> userPage = new Page<User>(Long.parseLong(pageNum), Long.parseLong(pageSize));
        Page<User> page = userservice.getBaseMapper().selectPage(userPage, null);
        HashMap<String, Object> map = new HashMap<>();
        map.put("code","0");
        map.put("msg","ok");
        map.put("count",page.getTotal());
        map.put("data",page.getRecords());
        return map;
    }
    //删除delUserById
    @RequestMapping("/delUserById")
    public String delUserById(@RequestParam("id") Integer id){
        int i = userservice.getBaseMapper().deleteById(id);
        return "admin/adminx";
    }

    //批量删除
    @RequestMapping("/batchDelUserByIds")
    public String batchDelUserByIds(@RequestParam("ids") String ids){
        System.out.println("ids:"+ids);
        String[] split = ids.split(",");
        List<String> strIds = Arrays.asList(split);//参数需要一个集合的
        int i = userservice.getBaseMapper().deleteBatchIds(strIds);
        return "admin/adminx";
    }

}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值