JavaWeb:商品管理系统(Vue版)

news2024/9/29 7:15:13

文章目录

      • 1、功能介绍
      • 2、技术栈
      • 3、环境准备
        • 3.1、数据库准备
        • 3.2、在新建web项目中导入依赖
        • 3.3、编写Mybatis文件
        • 3.4、编写pojo类
        • 3.5、编写Mybatis工具类
        • 3.6、导入前端素材(element-ui & vue.js & axios.js)
        • 3.7、前端页面
      • 4、功能实现
        • 4.1、查询所有功能
        • 4.2、添加数据功能
        • 4.3、修改数据功能
        • 4.4、删除数据功能
        • 4.5、批量删除功能
        • 4.6、条件分页查询

1、功能介绍

image-20240126100835272

以上是我们在综合案例要实现的功能。对数据的除了对数据的增删改查功能外,还有一些复杂的功能,如 批量删除分页查询条件查询 等功能

  • 批量删除 功能:每条数据前都有复选框,当我选中多条数据并点击 批量删除 按钮后,会发送请求到后端并删除数据库中指定的多条数据。
  • 分页查询 功能:当数据库中有很多数据时,我们不可能将所有的数据展示在一页里,这个时候就需要分页展示数据。
  • 条件查询 功能:数据库量大的时候,我们就需要精确的查询一些想看到的数据,这个时候就需要通过条件查询。

2、技术栈

  • servlet
  • Vue
  • axios
  • Mybatis
  • Tomcat

3、环境准备

3.1、数据库准备
use brand;
-- 删除tb_brand表
drop table if exists tb_brand;
-- 创建tb_brand表
create table tb_brand (
    -- id 主键
    id           int primary key auto_increment,
    -- 品牌名称
    brand_name   varchar(20),
    -- 企业名称
    company_name varchar(20),
    -- 排序字段
    ordered      int,
    -- 描述信息
    description  varchar(100),
    -- 状态:0:禁用  1:启用
    status       int
);
-- 添加数据
insert into tb_brand (brand_name, company_name, ordered, description, status)
values
       ('华为', '华为技术有限公司', 100, '万物互联', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
       ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
       ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
       ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
       ('华为', '华为技术有限公司', 100, '万物互联', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
       ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
       ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
       ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1),
       ('华为', '华为技术有限公司', 100, '万物互联', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
       ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
       ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
       ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
       ('华为', '华为技术有限公司', 100, '万物互联', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
       ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
       ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
       ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1),
       ('华为', '华为技术有限公司', 100, '万物互联', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
       ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
       ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
       ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
       ('华为', '华为技术有限公司', 100, '万物互联', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
       ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
       ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
       ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1);
3.2、在新建web项目中导入依赖
<dependencies>
    <!--Servlet-->
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
    </dependency>

    <!--MyBatis-->
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.5</version>
    </dependency>

    <!--MySQL-->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.46</version>
    </dependency>

    <!--fastjson-->
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.62</version>
    </dependency>
</dependencies>
3.3、编写Mybatis文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <settings>
        <!--在控制台显示SQL语句-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <typeAliases>
        <package name="com.demo.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///brand?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
       <!--扫描mapper-->
        <package name="com.demo.mapper"/>
    </mappers>
</configuration>
3.4、编写pojo类
public class Brand {
    // id 主键
    private Integer id;
    // 品牌名称
    private String brandName;
    // 企业名称
    private String companyName;
    // 排序字段
    private Integer ordered;
    // 描述信息
    private String description;
    // 状态:0:禁用  1:启用
    private Integer status;
    .....省略方法
}
3.5、编写Mybatis工具类
public class MyBatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    // 我们只需要一个SqlSessionFactory,在静态代码块中创建SqlSessionFactory
    static {
        try {
            // 编写代码让MyBatis跑起来,执行SQL语句
            String resource = "mybatis-config.xml";
            // 加载核心配置文件
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 得到SqlSession工厂,赋值给成员变量
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 返回SqlSessionFactory
    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }

    // 返回SqlSession
    public static SqlSession openSession() {
        return sqlSessionFactory.openSession();
    }

    public static SqlSession openSession(boolean autoCommit) {
        return sqlSessionFactory.openSession(autoCommit);
    }
}
3.6、导入前端素材(element-ui & vue.js & axios.js)

image-20240126102644268

3.7、前端页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>品牌列表</title>
    <script src="js/axios-0.18.0.js"></script>
    <script src="js/vue.js"></script>
    <script src="element-ui/lib/index.js"></script>
    <link rel="stylesheet" href="element-ui/lib/theme-chalk/index.css">
    <style>
        .el-table .warning-row {
            background: oldlace;
        }

        .el-table .success-row {
            background: #f0f9eb;
        }
    </style>
</head>
<body>

<div id="app">
    <!--第一行-->
    <el-row>
        <el-form :inline="true" :model="searchBrand" class="demo-form-inline">
            <el-form-item label="当前状态">
                <el-select v-model="searchBrand.status" placeholder="当前状态">
                    <el-option label="禁用" value="0"></el-option>
                    <el-option label="启用" value="1"></el-option>
                    <el-option label="所有" value=""></el-option>
                </el-select>
            </el-form-item>
            <el-form-item label="企业名称">
                <el-input v-model="searchBrand.companyName" placeholder="企业名称"></el-input>
            </el-form-item>
            <el-form-item label="品牌名称">
                <el-input v-model="searchBrand.brandName" placeholder="品牌名称"></el-input>
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="onSubmit">查询</el-button>
            </el-form-item>
        </el-form>
    </el-row>

    <!--第二行-->
    <el-row>
        <el-button type="danger" plain @click="deleteByIds()">批量删除</el-button>
        <el-button type="primary" plain @click="dialogVisible = true">新增</el-button>
        <!--添加品牌对话框-->
        <el-dialog
                title="添加品牌"
                :visible.sync="dialogVisible"
                width="30%">
            <!--对话框里面的表单-->
            <el-form :model="addBrand" :rules="rules" ref="addBrand" label-width="100px" class="demo-ruleForm">
                <el-form-item label="品牌名称" prop="brandName">
                    <el-input v-model="addBrand.brandName"></el-input>
                </el-form-item>
                <el-form-item label="企业名称" prop="companyName">
                    <el-input v-model="addBrand.companyName"></el-input>
                </el-form-item>
                <el-form-item label="排序">
                    <el-input v-model="addBrand.ordered"></el-input>
                </el-form-item>
                <el-form-item label="描述">
                    <el-input type="textarea" v-model="addBrand.description"></el-input>
                </el-form-item>
                <el-form-item label="状态">
                    <el-switch v-model="addBrand.status"
                               active-value="1"
                               inactive-value="0"></el-switch>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
                    <el-button @click="resetForm('ruleForm')">取消</el-button>
                </el-form-item>
            </el-form>
        </el-dialog>
    </el-row>

    <!--第三行-->
    <el-row>
        <template>
            <el-table
                    :data="tableData"
                    style="width: 100%"
                    :row-class-name="tableRowClassName"
                    @selection-change="handleSelectionChange">
                <el-table-column
                        type="selection"
                        width="55">
                </el-table-column>
                <el-table-column
                        type="index"
                        width="50">
                </el-table-column>
                <el-table-column
                        align="center"
                        prop="brandName"
                        label="品牌名称">
                </el-table-column>
                <el-table-column
                        align="center"
                        prop="companyName"
                        label="企业名称">
                </el-table-column>
                <el-table-column
                        prop="ordered"
                        label="排序"
                        width="150">
                </el-table-column>
                <el-table-column
                        prop="status"
                        label="当前状态"
                        width="150">
                    <template slot-scope="scope">
                        <span v-if="scope.row.status==1">启用</span>
                        <span v-else="">禁用</span>
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="250">
                    <template slot-scope="scope">
                        <el-button
                                size="mini"
                                @click="handleEdit(scope.$index, scope.row)">修改
                        </el-button>
                        <el-button
                                size="mini"
                                type="danger"
                                @click="handleDelete(scope.$index, scope.row)">删除
                        </el-button>
                    </template>
                </el-table-column>
            </el-table>
        </template>
    </el-row>
    <!--修改品牌对话框-->
    <el-dialog
            title="修改品牌"
            :visible.sync="updateDialogVisible"
            width="30%">
        <!--对话框里面的表单-->
        <el-form :model="updateBrand" :rules="rules" ref="updateBrand" label-width="100px" class="demo-ruleForm">
            <el-form-item label="品牌名称" prop="brandName">
                <el-input v-model="updateBrand.brandName"></el-input>
            </el-form-item>
            <el-form-item label="企业名称" prop="companyName">
                <el-input v-model="updateBrand.companyName"></el-input>
            </el-form-item>
            <el-form-item label="排序">
                <el-input v-model="updateBrand.ordered"></el-input>
            </el-form-item>
            <el-form-item label="描述">
                <el-input type="textarea" v-model="updateBrand.description"></el-input>
            </el-form-item>
            <el-form-item label="状态">
                <el-switch v-model="updateBrand.status"
                           :active-value="1"
                           :inactive-value="0"></el-switch>
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="submitFormUpdate('ruleForm')">提交</el-button>
                <el-button @click="resetFormUpdate('ruleForm')">取消</el-button>
            </el-form-item>
        </el-form>
    </el-dialog>
    <!--第四行-->
    <el-row>
        <div class="block" style="text-align: center; margin-top: 15px">
            <el-pagination
                    background
                    @size-change="handleSizeChange"
                    @current-change="handleCurrentChange"
                    :current-page="currentPage"
                    :page-sizes="[5, 10, 15, 20]"
                    :page-size="pageSize"
                    layout="total, sizes, prev, pager, next, jumper"
                    :total="totalCount">
            </el-pagination>
        </div>
    </el-row>
</div>

<script>
    new Vue({
        el: "#app",
        mounted() {
            this.reselectAll();
        },
        methods: {
            // 批量删除的方法
            deleteByIds() {
                this.$confirm('此操作将永久删除选中的品牌, 是否继续?', '警告', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    this.selectionIds = [];
                    // 遍历对象,取出id,放到selectionIds中;
                    for (let brand of this.multipleSelection) {
                        this.selectionIds.push(brand.id);
                    }
                    console.log(this.selectionIds);

                    // 1.点击批量删除按钮,发送ajax请求,携带被选中的id数组数据
                    axios.post("brand/deleteByIds", this.selectionIds)
                        .then(resp => {
                            // 2.获取标识,判断删除是否成功
                            if (resp.data == "success") {
                                // 给出提示
                                this.$message({
                                    showClose: true,
                                    message: '恭喜你,删除成功',
                                    type: 'success'
                                });
                                // 重新查询数据
                                this.reselectAll();
                            }
                        });
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            },
            // 重新加载所有数据
            reselectAll() {
                // 1.(查询所有数据) 页面加载完成后发送异步请求,获取列表数据
                axios.get("brand/selectAll")
                    .then(resp => {
                        // 将数据设置到模型上
                        this.tableData = resp.data;
                    });

                // 2.(分页查询) 页面加载完成后发送异步请求,携带当前页码和每页显示条数参数
                /*axios.get("brand/selectByPage?currentPage=" + this.currentPage + "&pageSize=" + this.pageSize)
                    .then(resp => {
                        // 将数据设置到模型上
                        this.tableData = resp.data.rows; // 这页的数据
                        this.totalCount = resp.data.totalCount;
                    });*/

                // 3.(条件且分页查询) 页面加载完成后发送异步请求,携带当前页码和每页显示条数参数
                // axios.get("brand/selectByPageAndCondition?currentPage=" + this.currentPage + "&pageSize=" + this.pageSize + "&brandName=" + this.searchBrand.brandName + "&companyName=" + this.searchBrand.companyName + "&status=" + this.searchBrand.status)
                //     .then(resp => {
                //         // 将数据设置到模型上
                //         this.tableData = resp.data.rows; // 这页的数据
                //         this.totalCount = resp.data.totalCount;
                //     });

            },
            tableRowClassName({row, rowIndex}) {
                if (rowIndex === 1) {
                    return 'warning-row';
                } else if (rowIndex === 3) {
                    return 'success-row';
                }
                return '';
            },
            // 多选按钮状态改变会调用
            handleSelectionChange(val) {
                this.multipleSelection = val;
                console.log(this.multipleSelection);
            },
            // 点击查询按钮时调用
            onSubmit() {
                console.log('准备查询: ' + this.searchBrand);
                // 每一次点击了查询按钮,当前页码要重置为1
                this.currentPage = 1;

                // 带条件分页查询
                this.reselectAll();
            },
            // 添加品牌
            submitForm(formName) {
                // 1.点击提交按钮,发送ajax请求,携带表单数据
                axios.post("brand/add", this.addBrand)
                    .then(resp => {
                        // 2.获取数据,判断添加是否成功
                        if (resp.data == "success") {
                            // 关闭窗口
                            this.dialogVisible = false;
                            // 重新加载数据
                            this.reselectAll();
                            // 给一个成功的提示
                            this.$message({
                                message: '恭喜你,添加品牌成功!',
                                type: 'success'
                            });
                            // 清空模型数据,否则还显示上一次的
                            this.addBrand = {
                                brandName: '',
                                companyName: '',
                                ordered: '',
                                description: '',
                                status: "0"
                            }
                        }
                    });
            },
            // 取消添加品牌
            resetForm(formName) {
                this.dialogVisible = false;
            },
            // 修改品牌
            submitFormUpdate(formName) {
                // 1.点击提交按钮,发送ajax请求,携带表单数据
                axios.post("brand/update", this.updateBrand)
                    .then(resp => {
                        // 2.获取数据,判断修改是否成功
                        if (resp.data == "success") {
                            // 关闭窗口
                            this.updateDialogVisible = false;
                            // 重新加载数据
                            this.reselectAll();
                            // 给一个成功的提示
                            this.$message({
                                message: '恭喜你,修改品牌成功!',
                                type: 'success'
                            });
                            // 清空模型数据,否则还显示上一次的
                            this.updateBrand = {
                                brandName: '',
                                companyName: '',
                                ordered: '',
                                description: '',
                                status: 0
                            }
                        }
                    });
            },
            // 取消修改品牌对话框
            resetFormUpdate(formName) {
                this.updateDialogVisible = false;
            },
            // 每页数量发生变化调用
            handleSizeChange(val) {
                console.log(`每页 ${val}`);
                this.pageSize = val;

                // 重新请求数据
                this.reselectAll();
            },
            // 页码变化调用
            handleCurrentChange(val) {
                console.log(`当前页: ${val}`);
                this.currentPage = val;

                // 重新请求数据
                this.reselectAll();
            },
            // 修改品牌
            handleEdit(index, row) {
                // 把当前行的数据赋值给修改品牌,让对话框中显示这个数据
                this.updateBrand = row;
                // 显示修改的对话框
                this.updateDialogVisible = true;
            },
            // 删除品牌
            handleDelete(index, row) {
                this.$confirm('此操作将永久删除选中的品牌, 是否继续?', '警告', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    // 根据id删除一个品牌
                    axios.post("brand/deleteOne", "id=" + row.id)
                        .then(resp => {
                            if (resp.data == "success") {
                                // 重新加载数据
                                this.reselectAll();
                                // 给一个成功的提示
                                this.$message({
                                    message: '恭喜你,删除品牌成功!',
                                    type: 'success'
                                });
                            }
                        });
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            }
        },
        data() {
            return {
                // 保存选中的要删除的id
                selectionIds: [],
                // 分页工具条,显示当前第几页
                currentPage: 1,
                // 每页显示的数量
                pageSize: 5,
                // 总数量
                totalCount: 100,
                // 添加品牌的数据
                addBrand: {
                    brandName: '',
                    companyName: '',
                    ordered: '',
                    description: '',
                    status: "0"
                },
                // 修改品牌的数据
                updateBrand: {
                    brandName: '',
                    companyName: '',
                    ordered: '',
                    description: '',
                    status: 0
                },
                // 添加和修改品牌的输入验证规则
                rules: {
                    brandName: [
                        {required: true, message: '请输入品牌名称', trigger: 'blur'},
                        {min: 1, max: 15, message: '品牌名称长度在 1 到 15 个字符', trigger: 'blur'}
                    ],
                    companyName: [
                        {required: true, message: '请输入企业名称', trigger: 'blur'},
                        {min: 2, max: 15, message: '企业名称长度在 2 到 15 个字符', trigger: 'blur'}
                    ]
                },
                // 控制添加品牌对话框是否显示true表示显示,false表示不显示
                dialogVisible: false,
                // 控制修改品牌对话框是否显示true表示显示,false表示不显示
                updateDialogVisible: false,
                // 第一行表单中查询的数据
                searchBrand: {
                    brandName: '',
                    companyName: '',
                    status: ""
                },
                // 保存多选按钮选中的数据
                multipleSelection: [],
                // 表格中的数据
                tableData: [{
                    brandName: '华为P50',
                    companyName: '华为科技有限公司',
                    ordered: '1',
                    status: '1'
                }]
            }
        }
    });
</script>
</body>
</html>

4、功能实现

4.1、查询所有功能

image-20240126132358592

如上图所示是查询所有品牌数据在页面展示的效果。要实现这个功能,要先搞明白如下问题:

  • 什么时候发送异步请求?

    页面加载完毕后就需要在页面上看到所有的品牌数据。所以在 mounted() 这个构造函数中写发送异步请求的代码。

  • 请求需要携带参数吗?

    查询所有功能不需要携带什么参数。

  • 响应的数据格式是什么样?

    后端是需要将 List<Brand> 对象转换为 JSON 格式的数据并响应回给浏览器。响应数据格式如下:

    image-20210825201634849

整体流程如下

image-20210825200332542

后端代码实现

1、在 BrandMapper 接口中定义抽象方法,并使用 @Select 注解编写 sql 语句

/**
     * 查询所有
     * @return
     */
@Select("select * from tb_brand")
List<Brand> selectAll();

2、在service包下创建接口定义查询方法

public interface BrandService {
    List<Brand> selectAll();
}

3、同时在service/impl包下创建实现类,同时创建selectAll方法

public class BrandServiceImpl implements BrandService {

    @Override
    public List<Brand> selectAll() {
        //获取Mybatis连接
        SqlSession sqlSession = MyBatisUtils.openSession();

        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
        //调用查询方法
        List<Brand> brands = mapper.selectAll();
        sqlSession.close();
        return brands;
    }
}

4、在web包下创建BrandSelectAllServlet

@WebServlet(value = "/brand/selectAll")
public class BrandSelectAllServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //调用BrandService进行查询所有
        BrandService brandService = new BrandServiceImpl();
        List<Brand> brands = brandService.selectAll();

        //设置响应格式为json,将数据转换为字符串发送
        String jsonString = JSON.toJSONString(brands);
        System.out.println(jsonString);
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write(jsonString);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        doGet(request,response);
    }
}

前端代码

前端需要在页面加载完毕后发送 ajax 请求,所以发送请求的逻辑应该放在 mounted() 钩子函数中。而响应回来的数据需要赋值给表格绑定的数据模型,从下图可以看出表格绑定的数据模型是 tableData

image-20210825220436889

前端代码如下:

reselectAll() {
    // 1.(查询所有数据) 页面加载完成后发送异步请求,获取列表数据
    axios.get("brand/selectAll")
    .then(resp => {
    // 将数据设置到模型上
    this.tableData = resp.data;
});
4.2、添加数据功能

image-20240126142628828

上图是添加数据的对话框,当点击 提交 按钮后就需要将数据提交到后端,并将数据保存到数据库中。下图是整体的流程:

image-20210825221329231

页面发送请求时,需要将输入框输入的内容提交给后端程序,而这里是以 json 格式进行传递的。而具体的数据格式如下:

image-20210826185917510

后端实现

1、在 BrandMapper 接口中定义 add() 添加方法,并使用 @Insert 注解编写sql语句

 @Insert("insert into tb_brand values (null,#{brandName},#{companyName},#{ordered},#{description},#{status});")
    void addBrand(Brand brand);

2、在 BrandService 接口中定义 add() 添加数据的业务逻辑方法

void addBrand(Brand brand);

3、在 BrandServiceImpl 类中重写 add() 方法,并进行业务逻辑实现

/**
  * 添加商品
  * @param brand
*/
@Override
public void addBrand(Brand brand) {
    //获取连接
    SqlSession sqlSession = MyBatisUtils.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

    //调用方法添加数据
    mapper.addBrand(brand);
    sqlSession.commit();

    sqlSession.close();
}

4、在 web 包写定义名为 BrandAddServlet 的 Servlet。该 Servlet 的逻辑如下:

  • 接收页面提交的数据。页面到时候提交的数据是 json 格式的数据,所以此处需要使用输入流读取数据
  • 将接收到的数据转换为 Brand 对象
  • 调用 service 的 add() 方法进行添加的业务逻辑处理
  • 给浏览器响应添加成功的标识,这里直接给浏览器响应 success 字符串表示成功

servlet 代码实现如下:

@WebServlet(value = "/brand/add")
public class BrandAddServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //接受请求数据
        String addJson = request.getReader().readLine();

        //将json转化为对象
        Brand brand = JSON.parseObject(addJson, Brand.class);

        //调用方法进行数据添加
        BrandService brandService = new BrandServiceImpl();
        brandService.addBrand(brand);

        //响应数据,响应成功标识
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write("success");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        doGet(request,response);
    }
}

前端代码实现

image-20210825223121993

上图左边是页面效果,里面的 提交 按钮可以通过上图右边看出绑定了一个 单击事件,而该事件绑定的是 addBrand 函数,所以添加数据功能的逻辑代码应该写在 addBrand() 函数中。在此方法中需要发送异步请求并将表单中输入的数据作为参数进行传递。如下

// 添加数据
addBrand() {
    var _this = this;

    // 发送ajax请求,添加数据
    axios({
        method:"post",
        url:"http://localhost:8080/brand-case/addServlet",
        data:_this.brand
    }).then(function (resp) {
       	//响应数据的处理逻辑
    })
}

then 函数中的匿名函数是成功后的回调函数,而 resp.data 就可以获取到响应回来的数据,如果值是 success 表示数据添加成功。成功后我们需要做一下逻辑处理:

  1. 关闭新增对话框窗口

    如下图所示是添加数据的对话框代码,从代码中可以看到此对话框绑定了 dialogVisible 数据模型,只需要将该数据模型的值设置为 false,就可以关闭新增对话框窗口了。

    image-20210825223933953
  2. 重新查询数据

    数据添加成功与否,用户只要能在页面上查看到数据说明添加成功。而此处需要重新发送异步请求获取所有的品牌数据,而这段代码在 查询所有 功能中已经实现,所以我们可以将此功能代码进行抽取,抽取到一个 selectAll() 函数中

    // 查询所有数据
    selectAll(){
        var _this = this;
    
        axios({
            method:"get",
            url:"http://localhost:8080/brand-case/selectAllServlet"
        }).then(function (resp) {
            _this.tableData = resp.data;
        })
    }
    

    那么就需要将 mounted() 钩子函数中代码改进为

    mounted(){
        //当页面加载完成后,发送异步请求,获取数据
        this.selectAll();
    }
    

    同时在新增响应的回调中调用 selectAll() 进行数据的重新查询。

  3. 弹出消息给用户提示添加成功

    image-20210825224958220

    上图左边就是 elementUI 官网提供的成功提示代码,而上图右边是具体的效果。

综上所述,前端代码如下:

// 添加数据
addBrand() {
    var _this = this;

    // 发送ajax请求,添加数据
    axios({
        method:"post",
        url:"http://localhost:8080/brand-case/addServlet",
        data:_this.brand
    }).then(function (resp) {
        if(resp.data == "success"){
            //添加成功
            //关闭窗口
            _this.dialogVisible = false;
            // 重新查询数据
            _this.selectAll();
            // 弹出消息提示
            _this.$message({
                message: '恭喜你,添加成功',
                type: 'success'
            });
        }
    })
}
4.3、修改数据功能

image-20240126152907794

上图是修改数据的对话框,当点击 提交 按钮后就需要将数据提交到后端,并将数据保存到数据库中。

后端实现

1、在 BrandMapper 接口中定义 updateBrand() 方法

@Update("update tb_brand set brand_name = #{brandName},company_name = #{companyName},ordered = #{ordered},description = #{description},status = #{status} where id = #{id};")
void updateBrand(Brand brand);

2、在 BrandService 接口中定义 updateBrand()

void updateBrand(Brand brand);

3、在 BrandServiceImpl 类中重写 updateBrand() 方法,并进行业务逻辑实现

/**
     * 修改数据
     * @param brand
*/
@Override
public void updateBrand(Brand brand) {
    //获取连接
    SqlSession sqlSession = MyBatisUtils.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

    //调用修改方法
    mapper.updateBrand(brand);

    sqlSession.commit();
    sqlSession.close();
}

4、在 web 包写定义名为 BrandUpdateServlet 的 Servlet。该 Servlet 的逻辑如下:

@WebServlet(value = "/brand/update")
public class BrandUpdateServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //接受数据
        String BrandJson = request.getReader().readLine();

        //将json数据转化为对象
        Brand brand = JSON.parseObject(BrandJson, Brand.class);

        //创建对象调用修改方法
        BrandService brandService = new BrandServiceImpl();
        brandService.updateBrand(brand);

        //响应数据 success
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write("success");



    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        doGet(request,response);
    }
}

前端代码实现

submitFormUpdate(formName) {
    // 1.点击提交按钮,发送ajax请求,携带表单数据
    axios.post("brand/update", this.updateBrand)
        .then(resp => {
        // 2.获取数据,判断修改是否成功
        if (resp.data == "success") {
            // 关闭窗口
            this.updateDialogVisible = false;
            // 重新加载数据
            this.reselectAll();
            // 给一个成功的提示
            this.$message({
                message: '恭喜你,修改品牌成功!',
                type: 'success'
            });
            // 清空模型数据,否则还显示上一次的
            this.updateBrand = {
                brandName: '',
                companyName: '',
                ordered: '',
                description: '',
                status: 0
            }
        }
    });
}
4.4、删除数据功能

后端实现

1、在 BrandMapper 接口中定义 deleteBrand() 方法

@Delete("delete from tb_brand where id = #{id}")
void deleteBrand(int id);

2、在 BrandService 接口中定义 deleteBrand()

void deleteBrand(int index);

3、在 BrandServiceImpl 类中重写 deleteBrand() 方法,并进行业务逻辑实现

/**
     * 删除数据
     * @param index
*/
@Override
public void deleteBrand(int index) {
    //获取连接
    SqlSession sqlSession = MyBatisUtils.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

    //调用方法
    mapper.deleteBrand(index);

    sqlSession.commit();
    sqlSession.close();

}

4、在 web 包写定义名为 BrandDeleteServlet 的 Servlet。该 Servlet 的逻辑如下:

@WebServlet(value = "/brand/deleteOne")
public class BrandDeleteServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取数据id
        String id = request.getParameter("id");
        int index = Integer.parseInt(id);

        //调用删除方法
        BrandService brandService = new BrandServiceImpl();
        brandService.deleteBrand(index);

        //响应数据  success
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write("success");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        doGet(request,response);
    }
}

前端代码实现

// 删除品牌
handleDelete(index, row) {
    this.$confirm('此操作将永久删除选中的品牌, 是否继续?', '警告', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {
        // 根据id删除一个品牌
        axios.post("brand/deleteOne", "id=" + row.id)
            .then(resp => {
            if (resp.data == "success") {
                // 重新加载数据
                this.reselectAll();
                // 给一个成功的提示
                this.$message({
                    message: '恭喜你,删除品牌成功!',
                    type: 'success'
                });
            }
        });
    }).catch(() => {
        this.$message({
            type: 'info',
            message: '已取消删除'
        });
    });
}
4.5、批量删除功能

如上图所示点击多条数据前的复选框就意味着要删除这些数据,而点击了 批量删除 按钮后,需要让用户确认一下,因为有可能是用户误操作的,当用户确定后需要给后端发送请求并携带者需要删除数据的多个id值,后端程序删除数据库中的数据。具体的流程如下:

image-20210826201651241

注意:

前端发送请求时需要将要删除的多个id值以json格式提交给后端,而该json格式数据如下:

[1,2,3,4]

后端实现

1、 BrandMapper 接口中定义 deleteByIds() 添加方法,由于这里面要用到动态 sql ,属于复杂的sql操作,建议使用映射配置文件。

接口方法声明如下:

 /**
     * 批量删除
     * @param ids
     */
void deleteByIds(@Param("ids") int[] ids);

BrandMapper.xml 映射配置文件中添加 statement

<delete id="deleteByIds">
    delete from tb_brand where id in
    <foreach collection="ids" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</delete>

2、在 BrandService 接口中定义 deleteByIds() 批量删除的业务逻辑方法

/**
     * 批量删除
     * @param ids
     */
void deleteByIds( int[] ids);

3、在 BrandServiceImpl 类中重写 deleteByIds() 方法,并进行业务逻辑实现

@Override
public void deleteByIds(int[] ids) {
    //2. 获取SqlSession对象
    SqlSession sqlSession = factory.openSession();
    //3. 获取BrandMapper
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

    //4. 调用方法
    mapper.deleteByIds(ids);

    sqlSession.commit();//提交事务

    //5. 释放资源
    sqlSession.close();
}

4、在 BrandServlet 类中定义 deleteByIds() 方法。而该方法的逻辑如下:

  • 接收页面提交的数据。页面到时候提交的数据是 json 格式的数据,所以此处需要使用输入流读取数据
  • 接收页面提交的数据。页面到时候提交的数据是 json 格式的数据,所以此处需要使用输入流读取数据
  • 将接收到的数据转换为 int[] 数组
  • 调用 service 的 deleteByIds() 方法进行批量删除的业务逻辑处理
  • 给浏览器响应添加成功的标识,这里直接给浏览器响应 success 字符串表示成功

servlet 中 deleteByIds() 方法代码实现如下:

@WebServlet(value = "/brand/deleteByIds")
public class deleteByIdsServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       // 接受数据
        String idJson = request.getReader().readLine();

        //将json数据转化为数组
        int[] ints = JSON.parseObject(idJson, int[].class);

        //调用方法
        BrandService brandService = new BrandServiceImpl();
        brandService.deleteByIds(ints);

        //响应数据
        response.setContentType("text/json;charset=utf-8");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        doGet(request,response);
    }
}

前端代码

此功能的前端代码实现稍微有点麻烦,分为以下几步实现

1、获取选中的id值

image-20210826223103884

从上图可以看出表格复选框绑定了一个 selection-change 事件,该事件是当选择项发生变化时会触发。该事件绑定了 handleSelectionChange 函数,而该函数有一个参数 val ,该参数是获取选中行的数据,如下

image-20210826223750518

而我们只需要将所有选中数据的id值提交给服务端即可,获取id的逻辑我们书写在 批量删除 按钮绑定的函数中。

批量删除 按钮绑定单击事件,并给绑定触发时调用的函数,如下

image-20210826224121445

并在Vue对象中的 methods 中定义 deleteByIds() 函数,在该函数中从 multipleSelection 数据模型中获取所选数据的id值。要完成这个功能需要在 Vue 对象中定义一个数据模型 selectedIds:[],在 deleteByIds() 函数中遍历 multipleSelection 数组,并获取到每一个所选数据的id值存储到 selectedIds 数组中,代码实现如下:

//1. 创建id数组 [1,2,3], 从 this.multipleSelection 获取即可
for (let i = 0; i < this.multipleSelection.length; i++) {
    let selectionElement = this.multipleSelection[i];
    this.selectedIds[i] = selectionElement.id;
}

2、发送异步请求

使用 axios 发送异步请求并经上一步获取到的存储所有的 id 数组作为请求参数

//2. 发送AJAX请求
var _this = this;

// 发送ajax请求,添加数据
axios({
    method:"post",
    url:"http://localhost:8080/brand-case/brand/deleteByIds",
    data:_this.selectedIds
}).then(function (resp) {
    if(resp.data == "success"){
        //删除成功
        // 重新查询数据
        _this.selectAll();
        // 弹出消息提示
        _this.$message({
            message: '恭喜你,删除成功',
            type: 'success'
        });
    }
})

由于删除操作是比较危险的;有时候可能是由于用户的误操作点击了 批量删除 按钮,所以在点击了按钮后需要先给用户确认提示。而确认框在 elementUI 中也提供了,如下图

image-20210826225742852

而在点击 确定 按钮后需要执行之前删除的逻辑。因此前端代码实现如下:

 // 批量删除
deleteByIds(){
    // 弹出确认提示框
    this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {
        //用户点击确认按钮
        //1. 创建id数组 [1,2,3], 从 this.multipleSelection 获取即可
        for (let i = 0; i < this.multipleSelection.length; i++) {
            let selectionElement = this.multipleSelection[i];
            this.selectedIds[i] = selectionElement.id;
        }
        //2. 发送AJAX请求
        var _this = this;
        // 发送ajax请求,添加数据
        axios({
            method:"post",
            url:"http://localhost:8080/brand-case/brand/deleteByIds",
            data:_this.selectedIds
        }).then(function (resp) {
            if(resp.data == "success"){
                //删除成功
                // 重新查询数据
                _this.selectAll();
                // 弹出消息提示
                _this.$message({
                    message: '恭喜你,删除成功',
                    type: 'success'
                });
            }
        })
    }).catch(() => {
        //用户点击取消按钮
        this.$message({
            type: 'info',
            message: '已取消删除'
        });
    });
}
4.6、条件分页查询

image-20240127111722362

上图就是用来输入条件查询的条件数据的。要做条件查询功能,先明确以下三个问题

  • 3个条件之间什么关系?

    同时满足,所用 SQL 中多个条件需要使用 and 关键字连接

  • 3个条件必须全部填写吗?

    不需要。想根据哪儿个条件查询就写那个,所以这里需要使用动态 sql 语句

  • 条件查询需要分页吗?

    需要

根据上面三个问题的明确,我们就可以确定sql语句了:

image-20210828213116559

整个条件分页查询流程如下

image-20240127111728773

后端实现

1、在 BrandMapper 接口中定义 selectByPageAndCondition() 方法 和 selectTotalCountByCondition 方法

/**
     * 分页条件查询
     * @param begin
     * @param size
     * @return
*/
List<Brand> selectByPageAndCondition(@Param("begin") int begin,@Param("size") int size,@Param("brand") Brand brand);

/**
     * 根据条件查询总记录数
     * @return
*/
int selectTotalCountByCondition(Brand brand);

参数:

  • begin 分页查询的起始索引
  • size 分页查询的每页条目数
  • brand 用来封装条件的对象

由于这是一个复杂的查询语句,需要使用动态sql;所以我们在映射配置文件中书写 sql 语句。brand_name 字段和 company_name 字段需要进行模糊查询,所以需要使用 % 占位符。映射配置文件中 statement 书写如下:

<!--查询满足条件的数据并进行分页-->
<select id="selectByPageAndCondition" resultMap="brandResultMap">
    select *
    from tb_brand
    <where>
        <if test="brand.brandName != null and brand.brandName != '' ">
            and  brand_name like #{brand.brandName}
        </if>

        <if test="brand.companyName != null and brand.companyName != '' ">
            and  company_name like #{brand.companyName}
        </if>

        <if test="brand.status != null">
            and  status = #{brand.status}
        </if>
    </where>
    limit #{begin} , #{size}
</select>

<!--查询满足条件的数据条目数-->
<select id="selectTotalCountByCondition" resultType="java.lang.Integer">
    select count(*)
    from tb_brand
    <where>
        <if test="brandName != null and brandName != '' ">
            and  brand_name like #{brandName}
        </if>

        <if test="companyName != null and companyName != '' ">
            and  company_name like #{companyName}
        </if>

        <if test="status != null">
            and  status = #{status}
        </if>
    </where>
</select>

2、在 BrandService 接口中定义 selectByPageAndCondition() 分页查询数据的业务逻辑方法

 /**
     * 分页条件查询
     * @param currentPage
     * @param pageSize
     * @param brand
     * @return
*/
PageBean<Brand>  selectByPageAndCondition(int currentPage,int pageSize,Brand brand);

3、在 BrandServiceImpl 类中重写 selectByPageAndCondition() 方法,并进行业务逻辑实现

@Override
public PageBean selectByPageAndCondition(int currentPage, int pageSize, Brand brand) {

    int start = (currentPage - 1) * pageSize;

    //获取连接
    SqlSession sqlSession = MyBatisUtils.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

    //调用方法,查询条件总数
    int selectByPageTotal = mapper.selectByPageAndConditionTotal(brand);
    //调用方法查询页面数据
    List<Brand> brands = mapper.selectByPageAndCondition(start,pageSize,brand);

    sqlSession.close();

    //封装数据
    PageBean pageBean = new PageBean(selectByPageTotal,brands);

    return pageBean;

}

4、在 BrandServlet 类中定义 selectByPageAndCondition() 方法。而该方法的逻辑如下:

  • 获取页面提交的 当前页码每页显示条目数 两个数据。这两个参数是在url后进行拼接的,格式是 url?currentPage=1&pageSize=5。获取这样的参数需要使用 requet.getparameter() 方法获取。

  • 获取页面提交的 条件数据 ,并将数据封装到一个Brand对象中。由于这部分数据到时候是需要以 json 格式进行提交的,所以我们需要通过流获取数据,具体代码如下:

// 获取查询条件对象
BufferedReader br = request.getReader();
String params = br.readLine();//json字符串

//转为 Brand
Brand brand = JSON.parseObject(params, Brand.class);
  • 调用 service 的 selectByPageAndCondition() 方法进行分页查询的业务逻辑处理

  • 将查询到的数据转换为 json 格式的数据

  • 响应 json 数据

servlet 中 selectByPageAndCondition() 方法代码实现如下:

@WebServlet(value = "/brand/selectByPageAndCondition")
public class SelectByPageAndCondition extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取数据
        String currentPageStr = request.getParameter("currentPage");
        String pageSizeStr = request.getParameter("pageSize");
        String brandName = request.getParameter("brandName");
        String companyName = request.getParameter("companyName");
        String status = request.getParameter("status");

        int currentPage = Integer.parseInt(currentPageStr);
        int pageSize = Integer.parseInt(pageSizeStr);

        //封装数据
        Brand brand = new Brand();
        brand.setBrandName(brandName);
        brand.setCompanyName(companyName);
        if (status != null && status.length() > 0){
            int i = Integer.parseInt(status);
            brand.setStatus(i);
        }

        //调用查询
        BrandService brandService = new BrandServiceImpl();
        PageBean pageBean = brandService.selectByPageAndCondition(currentPage,pageSize,brand);

        //转化为json
        String jsonString = JSON.toJSONString(pageBean);

        //设置响应
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write(jsonString);

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        doGet(request,response);
    }
}

前端代码

前端代码我们从以下几方面实现:

  1. 查询表单绑定查询条件对象模型

    这一步在页面上已经实现了,页面代码如下:

    image-20210828223817324
  2. 点击查询按钮查询数据

    image-20210828223952142

    从上面页面可以看到给 查询 按钮绑定了 onSubmit() 函数,而在 onSubmit() 函数中只需要调用 selectAll() 函数进行条件分页查询。

  3. 改进 selectAll() 函数

    子页面加载完成后发送异步请求,需要携带当前页码、每页显示条数、查询条件对象。接下来先对携带的数据进行说明:

    • 当前页码每页显示条数 这两个参数我们会拼接到 URL 的后面
    • 查询条件对象 这个参数需要以 json 格式提交给后端程序

    修改 selectAll() 函数逻辑为

axios.get("brand/selectByPageAndCondition?currentPage=" + this.currentPage + "&pageSize=" + this.pageSize + "&brandName=" + this.searchBrand.brandName + "&companyName=" + this.searchBrand.companyName + "&status=" + this.searchBrand.status)
    .then(resp => {
    // 将数据设置到模型上
    this.tableData = resp.data.rows; // 这页的数据
    this.totalCount = resp.data.totalCount;
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1414044.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT惊艳更新!一个@让三百万GPTs为你打工

ChatGPT悄悄更新个大功能&#xff01;看起来要把插件系统迭代掉了。 部分(灰度)用户已经收到这样的提示&#xff1a; 现在可以在对话中任意GPT商店里的GPTs&#xff0c;就像在群聊中一个人。 体验到的博主Dan Shipper第一时间录视频激动地分享&#xff1a;一个改变游戏规则的…

Jenkins邮件推送配置

目录 涉及Jenkins插件&#xff1a; 邮箱配置 什么是授权码 在第三方客户端/服务怎么设置 IMAP/SMTP 设置方法 POP3/SMTP 设置方法 获取授权码&#xff1a; Jenkins配置 从Jenkins主面板System configuration>System进入邮箱配置 在Email Extension Plugin 邮箱插件…

excel中多行合并后调整行高并打印

首先参考该文&#xff0c;调整全文的行高。 几个小技巧&#xff1a; 1.转换成pdf查看文件格式 2.通过视图--》分页预览&#xff0c;来确定每页的内容&#xff08;此时页码会以水印的形式显示&#xff09; 3. 页面布局中的&#xff0c;宽度可以选为自动&#xff0c;因为已经是…

C# .Net6搭建灵活的RestApi服务器

1、准备 C# .Net6后支持顶级语句&#xff0c;更简单的RestApi服务支持&#xff0c;可以快速搭建一个极为简洁的Web系统。推荐使用Visual Studio 2022&#xff0c;安装"ASP.NET 和Web开发"组件。 2、创建工程 关键步骤如下&#xff1a; 包添加了“Newtonsoft.Json”&…

锂电池升6V输出3A芯片。2.7v-5.5v输入,输出6v给马达供电

锂电池升压输出芯片是一种常见的电子元件&#xff0c;广泛应用于各种电子设备中。本文将介绍一款锂电池升压输出芯片&#xff0c;AH8681可以将2.7V-5.5V的输入电压升压至6V&#xff0c;电流可达3A&#xff0c;内置MOS管。 该锂电池升压输出芯片具有以下特点&#xff1a; 1. 输…

蓝桥杯备战——6.串口通讯

1.分析原理图 由上图我们可以看到串口1通过CH340接到了USB口上&#xff0c;通过串口1我们就能跟电脑进行数据交互。 另外需要注意的是STC15F是有两组高速串口的&#xff0c;而且可以切换端口。 2.配置串口 由于比赛时间紧&#xff0c;我们最好不要去现场查寄存器手册&#x…

Redis学习——入门篇③

Redis学习——入门篇③ 1. Redis事务1.1 事务实际操作1.2 watch 2. Redis管道&#xff08;pipelining&#xff09;2.1 管道简介2.2 管道实际操作2.3 管道小总结 3. Redis&#xff08;pub、sub&#xff09;发布订阅(不重要)3.1 简介3.2 发布订阅实际操作 这是一个分水岭…

uniapp 实现路由拦截,权限或者登录控制

背景&#xff1a; 项目需要判断token&#xff0c;即是否登录&#xff0c;登录之后权限 参考uni-app官方&#xff1a; 为了兼容其他端的跳转权限控制&#xff0c;uni-app并没有用vue router路由&#xff0c;而是内部实现一个类似此功能的钩子&#xff1a;拦截器&#xff0c;由…

Jmeter连接数据库报错Cannot load JDBC driver class‘com.mysql.jdbc.Driver’解决

问题产生: 我在用jmeter连接数据库查询我的接口是否添加数据成功时,结果树响应Cannot load JDBC driver class com.mysql.jdbc.Driver 产生原因: 1、连接数据库的用户密码等信息使用的变量我放在了下面,导致没有取到用户名密码IP等信息,导致连接失败 2、jmeter没有JDB…

echarts 柱状图数据过多时自动滚动

当我们柱状图中X轴数据太多的时候&#xff0c;会自动把柱形的宽度挤的很细&#xff0c;带来的交互非常不好&#xff0c;我们可以用dataZoom属性来解决 简易的版本&#xff0c;横向滚动。 option.dataZoom [{type: "slider",show: true,startValue: 0, //数据窗口范…

对接京东SDK踩坑

背景 最近刚好需要对接京东本地生活&#xff0c;部分接口和数据可以直接对接京东的开放平台&#xff0c;有一些敏感数据需要在京东云鼎上面入驻&#xff0c;然后在鼎内做一些业务逻辑&#xff0c;然后再将数据做一个转发&#xff0c;然后踩了一个坑就是京东SDK打包时未打包依赖…

C语言第十弹---函数(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 函数 1、函数的概念 2、库函数 2.1、标准库和头文件 2.2、库函数的使用方法 2.2.1、功能 2.2.2、头文件包含 2.2.3、实践 2.2.4、库函数文档的⼀般格式 …

C++实现推箱子游戏

推箱子游戏 运行之后的效果如视频所示&#xff0c;在完成游戏后播放音乐 准备工作&#xff1a;建立一个新的文件夹&#xff0c;并在文件夹中任意增加一张背景图片&#xff0c;以及各个部件的照片文件 因为这里用到了贴图技术&#xff0c;要使用graphic.h这个函数&#xff0c…

【DeepLearning-8】MobileViT模块配置

完整代码&#xff1a; import torch import torch.nn as nn from einops import rearrange def conv_1x1_bn(inp, oup):return nn.Sequential(nn.Conv2d(inp, oup, 1, 1, 0, biasFalse),nn.BatchNorm2d(oup),nn.SiLU()) def conv_nxn_bn(inp, oup, kernal_size3, stride1):re…

C/C++:混肴点分析

C中的常量介绍 字面常量 字面常量是指直接出现在代码中的常量值。例如&#xff0c;整数常量10、浮点数常量3.14、字符常量A等都属于字面常量。字面常量的值在编译时就已经确定&#xff0c;并且不能被修改。 字面常量存在类型&#xff0c;但没有地址 注意字符常量和只包含一个字…

关于我写过那些MySQL专栏

写在文章开头 这是截至今日写过的文章汇总&#xff0c;对于关注笔者公众号有一段时间的读者都知道&#xff0c;笔者会每周对自己写过的文章整理至相关专栏&#xff0c;以便读者可以按需进行检索阅读。 你好&#xff0c;我叫sharkchili&#xff0c;目前还是在一线奋斗的Java开…

免费开源的微信小程序源码、小游戏源码精选70套!

微信小程序已经成为我们日常的一部分了&#xff0c;也基本是每个程序员都会涉及的内容&#xff0c;今天给大家分享从网络收集的70个小程序源码。其中这些源码包含&#xff1a;小游戏到商城小程序&#xff0c;再到实用的工具小程序&#xff0c;以及那些令人惊叹的防各大站点的小…

Docker数据卷操作 Docker挂载Nginx、MySQL数据卷

容器与数据&#xff08;容器内文件&#xff09;耦合&#xff1a; 不便于修改&#xff1a;如果需要修改配置文件&#xff0c;需要进入容器的内部。数据不可复用&#xff1a;容器内的修改对外不可见&#xff0c;无法复用。升级维护困难&#xff1a;如果想要升级容器&#xff0c;…

pinia实现todos

store/todos.js //导入defineStore import {defineStore} from pinia const userTodosStoredefineStore(todos,{ state:()>({// list:[// {id:1,name:吃饭,done:false},// {id:2,name:睡觉,done:true},// {id:3,name:打豆豆,done:false}// ],list:JSON.parse(l…

wireshark利用sshdump自身组件进行远程实时抓包过滤

引言 以前在不了解wireshark可以远程抓包的时间&#xff0c;经常通过tcpdump在远程linux主机将抓包文件保存下来后&#xff0c;然后拖拽入windows中再打开&#xff0c;进行分析查看。 此过程比较繁琐&#xff0c;也不够实时。比较常用的抓包动作是仅出现某特征的报文后&#…