京淘项目第四天

实现用户新增

当点击新增用户按钮进行添加,并填写添加相应的信息;
编辑新增页面
官网API

Dialog 对话框

请添加图片描述

在这里插入图片描述

定义对话框

第一步

  <!--
    :visible.sync  控制对话框是否展现
  -->
  <el-dialog title="用户新增" :visible.sync="addUserDialogVisible" width="65%"
      @close="closeAddUserDialog">

    <el-form :model="addUserForm" :rules="rules" ref="addUserRuleForm" label-width="100px" class="demo-ruleForm">
      
    </el-form>

    <span slot="footer" class="dialog-footer">
      <el-button @click="addUserDialogVisible = false">取 消</el-button>
      <el-button type="primary" @click="addUserBtn">确 定</el-button>
    </span>
  </el-dialog>

第二步

请添加图片描述

第三步

请添加图片描述

第四步

在这里插入图片描述

第五步

请添加图片描述

关于正则表达式

正则表达式

正则介绍
正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

正则语法
{固定次数} [取值的范围] (分组)
demo: “[a-z]+.(jpg|png|gif)”

在这里插入图片描述

完成用户校验
请添加图片描述

<script>
  export default {
    data(){

      //自定义校验规则 rule:当前规则对象一般不用  value: 当前校验的数据  callback:回调函数
      //校验邮箱规则
      const checkEmail = (rule, value, callback) => {
        //定义邮箱的正则表达式  JS中用/来表示正则表达式的开始和结束
        const emailRege = /^[a-zA-Z0-9-_]+@[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+$/
        if (emailRege.test(value)) {
          //表示邮箱合法 正确返回  通过返回true   失败返回false
          return callback() //自定义规则执行成功,之后后续操作
        }
        callback(new Error('请填写正确的邮箱地址'))
      }

      //校验手机号的邮箱规则
      const checkPhone = (rule, value, callback) => {

        //定义校验手机号的正则语法
        const phoneRege = /^1[3456789][0-9]{9}$/
        if (phoneRege.test(value)) {

          return callback()
        }
        callback(new Error('请填写正确的手机号'))

      }

      //密码确认  判断与password是否相同
      const checkPassword = (rule, value, callback) => {

        if(value !== this.addUserForm.password){
           return callback(new Error('2次密码填写不一致'))
        }
        //如果相同,则调用回调函数
        callback()
      }

      return {
        //定义分页查询对象
        queryInfo: {
          query: '',    //用户查询的数据
          pageNum: 1,   //默认第一页
          pageSize: 5   //每页5条
        },
        userList: [],   //获取分页后的结果
        total: 0,
        addUserDialogVisible: false,
        //设定新增用户的对象
        addUserForm: {
          username: '',
          password: '',
          password2:  '',
          phone:  '',
          email:  ''
        },
        rules: {
           username: [
                      { required: true, message: '请输入用户名', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' }
                    ],
           password: [
                      { required: true, message: '请输入密码', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' }
                    ],
           password2: [
                      { required: true, message: '请输入密码', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' },
                      { validator: checkPassword, trigger: 'blur' }
                    ],
           phone: [
                      { required: true, message: '请输入电话', trigger: 'blur' },
                      { min: 11, max: 11, message: '长度必须11个字符', trigger: 'blur' },
                      //  //validator与正则表达式的电话校验进行绑定                     
                       { validator: checkPhone, trigger: 'blur' }
                    ],
           email: [
                      { required: true, message: '请输入邮箱地址', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' },
                      //validator与正则表达式的邮箱校验进行绑定
                      { validator: checkEmail, trigger: 'blur' }
                    ],
        }
      }
    }
    ....后边省略

密码校验

 //密码确认  判断与password是否相同
      const checkPassword = (rule, value, callback) => {
        //如果两次密码不相同
        if(value !== this.addUserForm.password){
           return callback(new Error('2次密码填写不一致'))
        }
        //如果相同,则调用回调函数
        callback()
      }

效果展示

请添加图片描述

<template>
  <!-- 准备根标签-->
  <div>

      <!-- 1.编辑面包屑导航 -->
      <el-breadcrumb separator-class="el-icon-arrow-right">
        <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
        <el-breadcrumb-item>用户管理</el-breadcrumb-item>
        <el-breadcrumb-item>用户列表</el-breadcrumb-item>
      </el-breadcrumb>

      <!-- 2.定义卡片标签 -->
      <el-card class="box-card">

        <!-- 2.1 定义一行元素 -->
        <el-row :gutter="20">

          <el-col :span="9">
            <!-- 2.2定义用户的输入框 -->
             <el-input placeholder="请输入内容" v-model="queryInfo.query" class="input-with-select"
             clearable @clear="getUserList">
                <el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
             </el-input>
          </el-col>

          <el-col :span="4">
            <!-- 2.2 定义新增用户按钮-->
            <el-button type="primary" @click="addUserDialogVisible = true">添加用户</el-button>
          </el-col>
        </el-row>



        <!-- 定义表格数据
           :data: 表格的数据来源
           prop:  从userList中获取的属性值
           label: 字段名称
           stripe: 斑马纹效果
           border:-->
         <el-table :data="userList" style="width: 100%" stripe  border>
            <!-- 定义表格的序号 -->
            <el-table-column type="index" label="序号"></el-table-column>
            <el-table-column prop="username" label="用户名"></el-table-column>
            <el-table-column prop="phone" label="电话"></el-table-column>
            <el-table-column prop="email" label="邮箱"></el-table-column>
            <el-table-column prop="status" label="状态">
              <template slot-scope="scope">
                  <!-- scope封装的对象 获取行级元素 row属性实现 -->
                  <el-switch v-model="scope.row.status" @change="updateStatus(scope.row)"
                    active-color="#13ce66"  inactive-color="#ff4949">
                  </el-switch>
              </template>
            </el-table-column>
            <el-table-column label="操作">
              <template slot-scope="scope">
                <el-button type="primary" icon="el-icon-edit" size="small"></el-button>
                <el-button type="danger" icon="el-icon-delete" size="small" @click="deleteUser(scope.row)"></el-button>
              </template>
            </el-table-column>
         </el-table>

        <!-- 3.定义分页功能
           1.@size-change  当页面的条数变化时触发
           2.@current-change  当页数改变时触发
           3.current-page  显示当前的页数 ??
           4.:page-sizes   显示页数的数组
           5.page-size     初始条件下每页的条数
           6.layout        显示分页的样式种类 全部显示
           7.total         数据的总数
         -->
        <el-pagination
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
              :current-page="queryInfo.pageNum"
              :page-sizes="[5, 10, 20, 40]"
              :page-size="queryInfo.pageSize"
              layout="total, sizes, prev, pager, next, jumper"
              :total="total">
        </el-pagination>

      </el-card>

      <!--
        :visible.sync  控制对话框是否展现
      -->
      <el-dialog title="用户新增" :visible.sync="addUserDialogVisible" width="65%"
          @close="closeAddUserDialog">

        <el-form :model="addUserForm" :rules="rules" ref="addUserRuleForm" label-width="100px" class="demo-ruleForm">
          <el-form-item label="用户名" prop="username">
            <el-input v-model="addUserForm.username"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input v-model="addUserForm.password" type="password"></el-input>
          </el-form-item>
          <el-form-item label="密码确认" prop="password2">
            <el-input v-model="addUserForm.password2" type="password"></el-input>
          </el-form-item>
          <el-form-item label="电话" prop="phone">
            <el-input v-model="addUserForm.phone"></el-input>
          </el-form-item>
          <el-form-item label="邮箱" prop="email">
            <el-input v-model="addUserForm.email"></el-input>
          </el-form-item>
        </el-form>

        <span slot="footer" class="dialog-footer">
          <el-button @click="addUserDialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="addUserBtn">确 定</el-button>
        </span>
      </el-dialog>


  </div>
</template>

<script>
  export default {
    data(){

      //自定义校验规则 rule:当前规则对象一般不用  value: 当前校验的数据  callback:回调函数
      //校验邮箱规则
      const checkEmail = (rule, value, callback) => {
        //定义邮箱的正则表达式  JS中用/来表示正则表达式的开始和结束
        const emailRege = /^[a-zA-Z0-9-_]+@[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+$/
        if (emailRege.test(value)) {
          //表示邮箱合法 正确返回  通过返回true   失败返回false
          return callback() //自定义规则执行成功,之后后续操作
        }
        callback(new Error('请填写正确的邮箱地址'))
      }

      //校验手机号的邮箱规则
      const checkPhone = (rule, value, callback) => {

        //定义校验手机号的正则语法
        const phoneRege = /^1[3456789][0-9]{9}$/
        if (phoneRege.test(value)) {

          return callback()
        }
        callback(new Error('请填写正确的手机号'))

      }

      //密码确认  判断与password是否相同
      const checkPassword = (rule, value, callback) => {

        if(value !== this.addUserForm.password){
           return callback(new Error('2次密码填写不一致'))
        }
        //如果相同,则调用回调函数
        callback()
      }

      return {
        //定义分页查询对象
        queryInfo: {
          query: '',    //用户查询的数据
          pageNum: 1,   //默认第一页
          pageSize: 5   //每页5条
        },
        userList: [],   //获取分页后的结果
        total: 0,
        addUserDialogVisible: false,
        //设定新增用户的对象
        addUserForm: {
          username: '',
          password: '',
          password2:  '',
          phone:  '',
          email:  ''
        },
        rules: {
           username: [
                      { required: true, message: '请输入用户名', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' }
                    ],
           password: [
                      { required: true, message: '请输入密码', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' }
                    ],
           password2: [
                      { required: true, message: '请输入密码', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' },
                      { validator: checkPassword, trigger: 'blur' }
                    ],
           phone: [
                      { required: true, message: '请输入电话', trigger: 'blur' },
                      { min: 11, max: 11, message: '长度必须11个字符', trigger: 'blur' },
                      { validator: checkPhone, trigger: 'blur' }
                    ],
           email: [
                      { required: true, message: '请输入邮箱地址', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' },
                      { validator: checkEmail, trigger: 'blur' }
                    ]
        }
      }
    },
    methods: {
      //1.动态获取userList数据
      async getUserList(){
       const {data: result} = await this.$http.get("/user/list",{params: this.queryInfo})
       if(result.status !== 200) return this.$message.error("获取列表失败")
       //为total属性赋值
       this.total = result.data.total
       this.userList = result.data.rows
      },
      handleSizeChange(pageSize){
        //查询的条件需要变化
        this.queryInfo.pageSize = pageSize
        //重新查询数据
        this.getUserList()
      },
      handleCurrentChange(pageNum){
        this.queryInfo.pageNum = pageNum
        this.getUserList()
      },
      async updateStatus(user){
        //获取用户的Id号/状态信息 发起restFul请求.
        //this.$http.put("/user/status/"+user.id+"/"+user.status)
        //模板字符串写法 `` 可以编辑多行,可以直接对象取值${key}
        //es6的高端写法
        const {data: result} =
        await this.$http.put(`/user/status/${user.id}/${user.status}`)
        if(result.status !== 200) return this.$message.error("更新操作失败")
        this.$message.success("更新操作成功!")
      },
      closeAddUserDialog(){
        //当对话框关闭时,应该重置表单
        this.$refs.addUserRuleForm.resetFields()
      },
      addUserBtn(){
        //对整个表单重新进行校验  1.获取表单的对象  2.进行数据校验
        this.$refs.addUserRuleForm.validate(async valid => {
          if(!valid) return this.$message.error("请正确填写数据")
          //之后发起ajax请求实现用户新增
          const {data: result} = await this.$http.post('/user/addUser',this.addUserForm)
          if(result.status !== 200) return this.$message.error("新增用户失败")
          this.$message.success("新增用户成功")
          //将对话框关闭
          this.addUserDialogVisible = false
          //重新刷新列表页面
          this.getUserList()
        })
      }
    
    },
    //当页面加载完成之后 调用该函数
    mounted(){
      //获取userList列表数据
      this.getUserList()
    }
  }
</script>

<!--
  当前样式是否支持less语法 样式的一种语言
  scoped 让样式只对当前组件有效 防止样式击穿
 -->
<style lang="less" scoped>

</style>

重置表单

官网API
说明: 当用户点击取消/关闭对话框时,触发关闭回调操作.即就是点击取消按钮之后,再次点击添加用户需要重新输入相应信息;

在这里插入图片描述

编辑页面
第一步
在这里插入图片描述

第二步

在这里插入图片描述

请添加图片描述

用户最终校验

问题:由于当先输入第一次密码之后在输入第二次确认密码会进行校验,但是反过来先输入确认密码在输入密码就不会进行校验;
解决:当点击确认提交之后再次进行提交;
编辑页面JS

在这里插入图片描述

  closeAddUserDialog(){
        //当对话框关闭时,应该重置表单
        this.$refs.addUserRuleForm.resetFields()
      },
      addUserBtn(){
        //对整个表单重新进行校验  1.获取表单的对象  2.进行数据校验
        this.$refs.addUserRuleForm.validate(async valid => {
          if(!valid) return this.$message.error("请正确填写数据")
          //之后发起ajax请求实现用户新增
          const {data: result} = await this.$http.post('/user/addUser',this.addUserForm)
          if(result.status !== 200) return this.$message.error("新增用户失败")
          this.$message.success("新增用户成功")
          //将对话框关闭
          this.addUserDialogVisible = false
          //重新刷新列表页面
          this.getUserList()
        })
      },

用户新增业务接口

在这里插入图片描述

编辑页面JS

在这里插入图片描述

  closeAddUserDialog(){
        //当对话框关闭时,应该重置表单
        this.$refs.addUserRuleForm.resetFields()
      },
      addUserBtn(){
        //对整个表单重新进行校验  1.获取表单的对象  2.进行数据校验
        this.$refs.addUserRuleForm.validate(async valid => {
          if(!valid) return this.$message.error("请正确填写数据")
          //之后发起ajax请求实现用户新增
          const {data: result} = await this.$http.post('/user/addUser',this.addUserForm)
          if(result.status !== 200) return this.$message.error("新增用户失败")
          this.$message.success("新增用户成功")
          //将对话框关闭
          this.addUserDialogVisible = false
          //重新刷新列表页面
          this.getUserList()
        })
      },

用户新增的后端的操作

编辑UserController

在这里插入图片描述

  /**
     * 业务分析: 实现用户新增 注意密码加密
     * URL: /user/addUser
     * 请求参数: 用户的form表单
     * 返回值: SysResult对象
     */
     @PostMapping("/addUser")
     public SysResult addUser(@RequestBody User user){

         userService.addUser(user);
         return SysResult.success();
     }
package com.jt.controller;

import com.jt.pojo.User;
import com.jt.service.UserService;
import com.jt.vo.PageResult;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author 
 * 时间 2021/5/11
 */
@RestController
@CrossOrigin
@RequestMapping("/user")    //抽取公共的请求
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 1.url地址: /user/login
     * 2.请求参数: 用户表单对象的JSON串   post类型
     * 3.返回值结果 SysResult  token?有值 正确        null 错误
     */
    @PostMapping("/login")
    public SysResult login(@RequestBody User user){
        String token = userService.findUserByUP(user);
        if(StringUtils.hasLength(token)){
            return SysResult.success(token);
        }else{
            return SysResult.fail();
        }

        /*try {
            String token = userService.findUserByUP(user);
            if(StringUtils.hasLength(token)){
                return SysResult.success(token);
            }else{
                return SysResult.fail();
            }
        }catch (Exception e){
            e.printStackTrace();
            return SysResult.fail();
        }*/
    }


    /**
     * 需求: 进行分页查询
     * URL地址:  /user/list
     * 请求参数: 使用PageResult对象接收
     * 请求返回值: SysResult对象
     * 请求类型: get请求
     */
    @GetMapping("/list")
    public SysResult findUserByPage(PageResult pageResult){//只有3个参数
        //携带所有的数据返回
        pageResult = userService.findUserByPage(pageResult);
        return SysResult.success(pageResult);
    }

    /**
     * 更新状态信息
     * URL: /user/status/{id}/{status}
     * 参数:  id/status
     * 返回值: SysResult对象
     */
    @PutMapping("/status/{id}/{status}")
    public SysResult updateStatus(User user){

        userService.updateStatus(user);
        return SysResult.success();
    }

    /**
     * 业务分析: 实现用户新增 注意密码加密
     * URL: /user/addUser
     * 请求参数: 用户的form表单
     * 返回值: SysResult对象
     */
     @PostMapping("/addUser")
     public SysResult addUser(@RequestBody User user){

         userService.addUser(user);
         return SysResult.success();
     }

编辑UserService

接口代码

package com.jt.service;

import com.jt.pojo.User;
import com.jt.vo.PageResult;

import java.util.List;

/**
 * @author 刘昱江
 * 时间 2021/5/11
 */
public interface UserService {
    List<User> findAll();

    String findUserByUP(User user);

    PageResult findUserByPage(PageResult pageResult);

    void updateStatus(User user);

    void addUser(User user);

}

实现类代码
在这里插入图片描述

package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import com.jt.vo.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.UUID;


@Service
public class UserServiceImpl implements UserService{

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.selectList(null);
    }

    /**
     * user对象: username/password 明文
     * 业务思路:
     *  1.将密码进行加密处理  md5加密方式
     *  2.根据新的用户名和密码查询数据
     *  3. 结果:null 没查到  u/p错误
     *          不为null u/p正确  返回令牌 token  UUID算法
     *
     *  * @param user
     * @return
     *
     * 数据库信息:   用户名 :admin    密码:admin123456
     */
    @Override
    public String findUserByUP(User user) {
        //1.将密码加密 一般可能添加  盐值: 由公司域名构成
        // hash(md5(www.baidu.com12345))
      //  getBytes() 是Java编程语言中将一个字符串转化为一个字节数组byte[]的方法。
        String md5Pass =DigestUtils
                        .md5DigestAsHex(user.getPassword().getBytes());
        //2.根据用户名/密码查询数据库.
        user.setPassword(md5Pass);
        //根据对象中不为null的属性当做where条件
        QueryWrapper queryWrapper = new QueryWrapper(user);
        User userDB = userMapper.selectOne(queryWrapper);
        //3.返回密钥token
        String token = UUID.randomUUID().toString()
                       .replace("-", "");
        return userDB==null?null:token;
    }

    /**
     * 业务说明: 将后台数据实现分页查询
     * 分页Sql:
     *      select * from user limit 起始位置,查询记录数
     * 查询第一页 每页20条
     *      select * from user limit 0,20
     * @param pageResult
     * @return
     *
     * MP实现分页查询
     *  MP通过分页对象进行查询,获取所有的分页相关的数据.
     *
     * 参数说明:
     *  page: 定义当前的分页对象 页面/每页的条数
     *  queryWrapper: 条件构造器 只有query属性不为null 才会拼接where条件.
     */

    @Override
    public PageResult findUserByPage(PageResult pageResult) {
        //1.定义分页对象  2个参数
        IPage<User> page = new Page<>(pageResult.getPageNum(),
                              pageResult.getPageSize());
        //2.定义查询条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //3.判断用户是否有参数
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        queryWrapper.like(flag,"username", pageResult.getQuery());

        //page 参数4个
        page = userMapper.selectPage(page,queryWrapper);
        //4.获取总记录数
        long total = page.getTotal();
        //5.获取分页后的结果
        List<User> userList = page.getRecords();
        return pageResult.setTotal(total).setRows(userList);
    }

    @Override
    public void updateStatus(User user) {   //id/status

        userMapper.updateById(user);
    }

    @Override
    public void addUser(User user) {
        //1.密码加密
        String md5Pass =
                DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        user.setPassword(md5Pass).setStatus(true);

        userMapper.insert(user);
    }

}

数据自动填充

业务说明
由于架构设计通常会添加一些必要的属性,但是该属性每次都要写,造成重复. 代码冗余,能否优化?

自动填充

自动填充:
在对数据可进行一些操作的时候,有些字段基本是固定,比如创建时间和修改时间,我们可以利用mybatisplus的自动填充功能来实现。即也就是我们所说的相应的操作的时间记录;
所以使用自动填充,就不需要我们手动的进行实现,而是自动的会进行实现;

请添加图片描述

编辑POJO
说明: 将公共的属性进行抽取,之后根据MP的自动填充的机制,挑选合适的操作(CRUD)进行填充

在这里插入图片描述

编辑自动填充代码(编辑配置类)

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    //入库操作时,需要更新 创建事件/更新时间
    @Override
    public void insertFill(MetaObject metaObject) {
        Date date = new Date();
        this.setFieldValByName("created",date,metaObject);
        this.setFieldValByName("updated",date,metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updated",new Date(),metaObject);
    }
}
package com.jt.config;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    //入库操作时,需要更新 创建事件/更新时间
    @Override
    public void insertFill(MetaObject metaObject) {
        Date date = new Date();
        this.setFieldValByName("created",date,metaObject);
        this.setFieldValByName("updated",date,metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updated",new Date(),metaObject);
    }
}

效果展现

请添加图片描述

用户数据删除

绑定某一行的数据使用作用域插槽
官网API

消息弹框
在这里插入图片描述

编辑前端JS

async deleteUser(user){
        //定义消息确认框 promise对象 如果从中获取用户的选项 不方便
        const result = await this.$confirm('此操作将永久删除'+user.username+', 是否继续?', '提示', {
                  confirmButtonText: '确定',
                  cancelButtonText: '取消',
                  type: 'warning'
        
                //发生报错则可以进行抛出报错信息,同时有报错则不会执行下面的代码。
              }).catch(error => error)

        //当点击确定按钮时会输出  确定: confirm    ,当点击取消按钮时会输出 取消 cancel
        if(result !== 'confirm') return this.$message.info("用户取消操作")

        //发起ajax请求实现数据的删除...
        const {data: resultDB} = await this.$http.delete('/user/'+user.id)
        if(resultDB.status !== 200) return this.$message.error("用户删除失败!")
        this.$message.success("用户删除成功!")
        //重新加载用户列表
        this.getUserList()
      }

编辑删除的后端的代码

编辑UserController

/**
     * 删除用户
     * URL: /user/{id}
     * 参数: 用户的ID号
     * 返回值: SysResult对象
     * 关于ajax说明:
     *      @RequestBody PUT/POST  要求将前端的json转换为对象,所以在后端添加注解
     *      GET/DELETE   数据都是普通数据  后端正常接收可以
     *
     */
    @DeleteMapping("/{id}")
    public SysResult deleteUserById(@PathVariable Integer id){

        userService.deleteUserById(id);
        return SysResult.success();
    }
package com.jt.controller;

import com.jt.pojo.User;
import com.jt.service.UserService;
import com.jt.vo.PageResult;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author 刘昱江
 * 时间 2021/5/11
 */
@RestController
@CrossOrigin
@RequestMapping("/user")    //抽取公共的请求
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 1.url地址: /user/login
     * 2.请求参数: 用户表单对象的JSON串   post类型
     * 3.返回值结果 SysResult  token?有值 正确        null 错误
     */
    @PostMapping("/login")
    public SysResult login(@RequestBody User user){
        String token = userService.findUserByUP(user);
        if(StringUtils.hasLength(token)){
            return SysResult.success(token);
        }else{
            return SysResult.fail();
        }

        /*try {
            String token = userService.findUserByUP(user);
            if(StringUtils.hasLength(token)){
                return SysResult.success(token);
            }else{
                return SysResult.fail();
            }
        }catch (Exception e){
            e.printStackTrace();
            return SysResult.fail();
        }*/
    }


    /**
     * 需求: 进行分页查询
     * URL地址:  /user/list
     * 请求参数: 使用PageResult对象接收
     * 请求返回值: SysResult对象
     * 请求类型: get请求
     */
    @GetMapping("/list")
    public SysResult findUserByPage(PageResult pageResult){//只有3个参数
        //携带所有的数据返回
        pageResult = userService.findUserByPage(pageResult);
        return SysResult.success(pageResult);
    }

    /**
     * 更新状态信息
     * URL: /user/status/{id}/{status}
     * 参数:  id/status
     * 返回值: SysResult对象
     */
    @PutMapping("/status/{id}/{status}")
    public SysResult updateStatus(User user){

        userService.updateStatus(user);
        return SysResult.success();
    }

    /**
     * 业务分析: 实现用户新增 注意密码加密
     * URL: /user/addUser
     * 请求参数: 用户的form表单
     * 返回值: SysResult对象
     */
     @PostMapping("/addUser")
     public SysResult addUser(@RequestBody User user){

         userService.addUser(user);
         return SysResult.success();
     }

    /**
     * 删除用户
     * URL: /user/{id}
     * 参数: 用户的ID号
     * 返回值: SysResult对象
     * 关于ajax说明:
     *      @RequestBody PUT/POST  要求ajax传递的对象 自己封装为JSON 所以在后端添加注解
     *      GET/DELETE   数据都是普通数据  后端正常接收可以
     *
     */
    @DeleteMapping("/{id}")
    public SysResult deleteUserById(@PathVariable Integer id){

        userService.deleteUserById(id);
        return SysResult.success();
    }
}

编辑UserService

接口代码

package com.jt.service;

import com.jt.pojo.User;
import com.jt.vo.PageResult;

import java.util.List;

/**
 * @author 
 * 时间 2021/5/11
 */
public interface UserService {
    List<User> findAll();

    String findUserByUP(User user);

    PageResult findUserByPage(PageResult pageResult);

    void updateStatus(User user);

    void addUser(User user);

    void deleteUserById(Integer id);
}

实现类代码

@Override
    public void deleteUserById(Integer id) {

        userMapper.deleteById(id);
    }
package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import com.jt.vo.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @author 
 * 时间 2021/5/11
 */
@Service
public class UserServiceImpl implements UserService{

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.selectList(null);
    }

    /**
     * user对象: username/password 明文
     * 业务思路:
     *  1.将密码进行加密处理  md5加密方式
     *  2.根据新的用户名和密码查询数据
     *  3. 结果:null 没查到  u/p错误
     *          不为null u/p正确  返回令牌 token  UUID算法
     *
     *  * @param user
     * @return
     *
     * 数据库信息:   用户名 :admin    密码:admin123456
     */
    @Override
    public String findUserByUP(User user) {
        //1.将密码加密 一般可能添加  盐值: 由公司域名构成
        // hash(md5(www.baidu.com12345))
        String md5Pass =DigestUtils
                        .md5DigestAsHex(user.getPassword().getBytes());
        //2.根据用户名/密码查询数据库.
        user.setPassword(md5Pass);
        //根据对象中不为null的属性当做where条件
        QueryWrapper queryWrapper = new QueryWrapper(user);
        User userDB = userMapper.selectOne(queryWrapper);
        //3.返回密钥token
        String token = UUID.randomUUID().toString()
                       .replace("-", "");
        return userDB==null?null:token;
    }

    /**
     * 业务说明: 将后台数据实现分页查询
     * 分页Sql:
     *      select * from user limit 起始位置,查询记录数
     * 查询第一页 每页20条
     *      select * from user limit 0,20
     * @param pageResult
     * @return
     *
     * MP实现分页查询
     *  MP通过分页对象进行查询,获取所有的分页相关的数据.
     *
     * 参数说明:
     *  page: 定义当前的分页对象 页面/每页的条数
     *  queryWrapper: 条件构造器 只有query属性不为null 才会拼接where条件.
     */

    @Override
    public PageResult findUserByPage(PageResult pageResult) {
        //1.定义分页对象  2个参数
        IPage<User> page = new Page<>(pageResult.getPageNum(),
                              pageResult.getPageSize());
        //2.定义查询条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //3.判断用户是否有参数
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        queryWrapper.like(flag,"username", pageResult.getQuery());

        //page 参数4个
        page = userMapper.selectPage(page,queryWrapper);
        //4.获取总记录数
        long total = page.getTotal();
        //5.获取分页后的结果
        List<User> userList = page.getRecords();
        return pageResult.setTotal(total).setRows(userList);
    }

    @Override
    public void updateStatus(User user) {   //id/status

        userMapper.updateById(user);
    }

    @Override
    public void addUser(User user) {
        //1.密码加密
        String md5Pass =
                DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        user.setPassword(md5Pass).setStatus(true);

        userMapper.insert(user);
    }

    @Override
    public void deleteUserById(Integer id) {

        userMapper.deleteById(id);
    }
}

知识总结

usermapper的代码

package com.jt.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jt.pojo.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;

import java.util.List;

/**
 * @author 
 * 时间 2021/2/2
 */
public interface UserMapper extends BaseMapper<User> {

}

usercontroller的代码

package com.jt.controller;

import com.jt.pojo.User;
import com.jt.service.UserService;
import com.jt.vo.PageResult;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author 
 * 时间 2021/5/11
 */
@RestController
@CrossOrigin
@RequestMapping("/user")    //抽取公共的请求
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 1.url地址: /user/login
     * 2.请求参数: 用户表单对象的JSON串   post类型
     * 3.返回值结果 SysResult  token?有值 正确        null 错误
     */
    @PostMapping("/login")
    public SysResult login(@RequestBody User user){
        String token = userService.findUserByUP(user);
        if(StringUtils.hasLength(token)){
            return SysResult.success(token);
        }else{
            return SysResult.fail();
        }

        /*try {
            String token = userService.findUserByUP(user);
            if(StringUtils.hasLength(token)){
                return SysResult.success(token);
            }else{
                return SysResult.fail();
            }
        }catch (Exception e){
            e.printStackTrace();
            return SysResult.fail();
        }*/
    }


    /**
     * 需求: 进行分页查询
     * URL地址:  /user/list
     * 请求参数: 使用PageResult对象接收
     * 请求返回值: SysResult对象
     * 请求类型: get请求
     */
    @GetMapping("/list")
    public SysResult findUserByPage(PageResult pageResult){//只有3个参数
        //携带所有的数据返回
        pageResult = userService.findUserByPage(pageResult);
        return SysResult.success(pageResult);
    }

    /**
     * 更新状态信息
     * URL: /user/status/{id}/{status}
     * 参数:  id/status
     * 返回值: SysResult对象
     */
    @PutMapping("/status/{id}/{status}")
    public SysResult updateStatus(User user){

        userService.updateStatus(user);
        return SysResult.success();
    }

    /**
     * 业务分析: 实现用户新增 注意密码加密
     * URL: /user/addUser
     * 请求参数: 用户的form表单
     * 返回值: SysResult对象
     */
     @PostMapping("/addUser")
     public SysResult addUser(@RequestBody User user){

         userService.addUser(user);
         return SysResult.success();
     }

    /**
     * 删除用户
     * URL: /user/{id}
     * 参数: 用户的ID号
     * 返回值: SysResult对象
     * 关于ajax说明:
     *      @RequestBody PUT/POST  要求ajax传递的对象 自己封装为JSON 所以在后端添加注解
     *      GET/DELETE   数据都是普通数据  后端正常接收可以
     *
     */
    @DeleteMapping("/{id}")
    public SysResult deleteUserById(@PathVariable Integer id){

        userService.deleteUserById(id);
        return SysResult.success();
    }
}

userservice的代码

接口的代码

package com.jt.service;

import com.jt.pojo.User;
import com.jt.vo.PageResult;

import java.util.List;

/**
 * @author 
 * 时间 2021/5/11
 */
public interface UserService {
    List<User> findAll();

    String findUserByUP(User user);

    PageResult findUserByPage(PageResult pageResult);

    void updateStatus(User user);

    void addUser(User user);

    void deleteUserById(Integer id);
}

实现类的代码

package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import com.jt.vo.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @author 刘昱江
 * 时间 2021/5/11
 */
@Service
public class UserServiceImpl implements UserService{

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.selectList(null);
    }

    /**
     * user对象: username/password 明文
     * 业务思路:
     *  1.将密码进行加密处理  md5加密方式
     *  2.根据新的用户名和密码查询数据
     *  3. 结果:null 没查到  u/p错误
     *          不为null u/p正确  返回令牌 token  UUID算法
     *
     *  * @param user
     * @return
     *
     * 数据库信息:   用户名 :admin    密码:admin123456
     */
    @Override
    public String findUserByUP(User user) {
        //1.将密码加密 一般可能添加  盐值: 由公司域名构成
        // hash(md5(www.baidu.com12345))
        String md5Pass =DigestUtils
                        .md5DigestAsHex(user.getPassword().getBytes());
        //2.根据用户名/密码查询数据库.
        user.setPassword(md5Pass);
        //根据对象中不为null的属性当做where条件
        QueryWrapper queryWrapper = new QueryWrapper(user);
        User userDB = userMapper.selectOne(queryWrapper);
        //3.返回密钥token
        String token = UUID.randomUUID().toString()
                       .replace("-", "");
        return userDB==null?null:token;
    }

    /**
     * 业务说明: 将后台数据实现分页查询
     * 分页Sql:
     *      select * from user limit 起始位置,查询记录数
     * 查询第一页 每页20条
     *      select * from user limit 0,20
     * @param pageResult
     * @return
     *
     * MP实现分页查询
     *  MP通过分页对象进行查询,获取所有的分页相关的数据.
     *
     * 参数说明:
     *  page: 定义当前的分页对象 页面/每页的条数
     *  queryWrapper: 条件构造器 只有query属性不为null 才会拼接where条件.
     */

    @Override
    public PageResult findUserByPage(PageResult pageResult) {
        //1.定义分页对象  2个参数
        IPage<User> page = new Page<>(pageResult.getPageNum(),
                              pageResult.getPageSize());
        //2.定义查询条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //3.判断用户是否有参数
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        queryWrapper.like(flag,"username", pageResult.getQuery());

        //page 参数4个
        page = userMapper.selectPage(page,queryWrapper);
        //4.获取总记录数
        long total = page.getTotal();
        //5.获取分页后的结果
        List<User> userList = page.getRecords();
        return pageResult.setTotal(total).setRows(userList);
    }

    @Override
    public void updateStatus(User user) {   //id/status

        userMapper.updateById(user);
    }

    @Override
    public void addUser(User user) {
        //1.密码加密
        String md5Pass =
                DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        user.setPassword(md5Pass).setStatus(true);

        userMapper.insert(user);
    }

    @Override
    public void deleteUserById(Integer id) {

        userMapper.deleteById(id);
    }
}

user.vue 即user页面的代码

<template>
  <!-- 准备根标签-->
  <div>

      <!-- 1.编辑面包屑导航 -->
      <el-breadcrumb separator-class="el-icon-arrow-right">
        <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
        <el-breadcrumb-item>用户管理</el-breadcrumb-item>
        <el-breadcrumb-item>用户列表</el-breadcrumb-item>
      </el-breadcrumb>

      <!-- 2.定义卡片标签 -->
      <el-card class="box-card">

        <!-- 2.1 定义一行元素 -->
        <el-row :gutter="20">

          <el-col :span="9">
            <!-- 2.2定义用户的输入框 -->
             <el-input placeholder="请输入内容" v-model="queryInfo.query" class="input-with-select"
             clearable @clear="getUserList">
                <el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
             </el-input>
          </el-col>

          <el-col :span="4">
            <!-- 2.2 定义新增用户按钮-->
            <el-button type="primary" @click="addUserDialogVisible = true">添加用户</el-button>
          </el-col>
        </el-row>



        <!-- 定义表格数据
           :data: 表格的数据来源
           prop:  从userList中获取的属性值
           label: 字段名称
           stripe: 斑马纹效果
           border: 列
        -->
         <el-table :data="userList" style="width: 100%" stripe  border>
            <!-- 定义表格的序号 -->
            <el-table-column type="index" label="序号"></el-table-column>
            <el-table-column prop="username" label="用户名"></el-table-column>
            <el-table-column prop="phone" label="电话"></el-table-column>
            <el-table-column prop="email" label="邮箱"></el-table-column>
            <el-table-column prop="status" label="状态">
              <template slot-scope="scope">
                  <!-- scope封装的对象 获取行级元素 row属性实现 -->
                  <el-switch v-model="scope.row.status" @change="updateStatus(scope.row)"
                    active-color="#13ce66"  inactive-color="#ff4949">
                  </el-switch>
              </template>
            </el-table-column>
            <el-table-column label="操作">
              <template slot-scope="scope">
                <el-button type="primary" icon="el-icon-edit" size="small"></el-button>
                <el-button type="danger" icon="el-icon-delete" size="small" @click="deleteUser(scope.row)"></el-button>
              </template>
            </el-table-column>
         </el-table>

        <!-- 3.定义分页功能
           1.@size-change  当页面的条数变化时触发
           2.@current-change  当页数改变时触发
           3.current-page  显示当前的页数 ??
           4.:page-sizes   显示页数的数组
           5.page-size     初始条件下每页的条数
           6.layout        显示分页的样式种类 全部显示
           7.total         数据的总数
         -->
        <el-pagination
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
              :current-page="queryInfo.pageNum"
              :page-sizes="[5, 10, 20, 40]"
              :page-size="queryInfo.pageSize"
              layout="total, sizes, prev, pager, next, jumper"
              :total="total">
        </el-pagination>

      </el-card>

      <!--
        :visible.sync  控制对话框是否展现
      -->
      <el-dialog title="用户新增" :visible.sync="addUserDialogVisible" width="65%"
          @close="closeAddUserDialog">

        <el-form :model="addUserForm" :rules="rules" ref="addUserRuleForm" label-width="100px" class="demo-ruleForm">
          <el-form-item label="用户名" prop="username">
            <el-input v-model="addUserForm.username"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input v-model="addUserForm.password" type="password"></el-input>
          </el-form-item>
          <el-form-item label="密码确认" prop="password2">
            <el-input v-model="addUserForm.password2" type="password"></el-input>
          </el-form-item>
          <el-form-item label="电话" prop="phone">
            <el-input v-model="addUserForm.phone"></el-input>
          </el-form-item>
          <el-form-item label="邮箱" prop="email">
            <el-input v-model="addUserForm.email"></el-input>
          </el-form-item>
        </el-form>

        <span slot="footer" class="dialog-footer">
          <el-button @click="addUserDialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="addUserBtn">确 定</el-button>
        </span>
      </el-dialog>


  </div>
</template>

<script>
  export default {
    data(){

      //自定义校验规则 rule:当前规则对象一般不用  value: 当前校验的数据  callback:回调函数
      //校验邮箱规则
      const checkEmail = (rule, value, callback) => {
        //定义邮箱的正则表达式  JS中用/来表示正则表达式的开始和结束
        const emailRege = /^[a-zA-Z0-9-_]+@[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+$/
        if (emailRege.test(value)) {
          //表示邮箱合法 正确返回  通过返回true   失败返回false
          return callback() //自定义规则执行成功,之后后续操作
        }
        callback(new Error('请填写正确的邮箱地址'))
      }

      //校验手机号的邮箱规则
      const checkPhone = (rule, value, callback) => {

        //定义校验手机号的正则语法
        const phoneRege = /^1[3456789][0-9]{9}$/
        if (phoneRege.test(value)) {

          return callback()
        }
        callback(new Error('请填写正确的手机号'))

      }

      //密码确认  判断与password是否相同
      const checkPassword = (rule, value, callback) => {

        if(value !== this.addUserForm.password){
           return callback(new Error('2次密码填写不一致'))
        }
        //如果相同,则调用回调函数
        callback()
      }

      return {
        //定义分页查询对象
        queryInfo: {
          query: '',    //用户查询的数据
          pageNum: 1,   //默认第一页
          pageSize: 5   //每页5条
        },
        userList: [],   //获取分页后的结果
        total: 0,
        addUserDialogVisible: false,
        //设定新增用户的对象
        addUserForm: {
          username: '',
          password: '',
          password2:  '',
          phone:  '',
          email:  ''
        },
        rules: {
           username: [
                      { required: true, message: '请输入用户名', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' }
                    ],
           password: [
                      { required: true, message: '请输入密码', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' }
                    ],
           password2: [
                      { required: true, message: '请输入密码', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' },
                      { validator: checkPassword, trigger: 'blur' }
                    ],
           phone: [
                      { required: true, message: '请输入电话', trigger: 'blur' },
                      { min: 11, max: 11, message: '长度必须11个字符', trigger: 'blur' },
                      { validator: checkPhone, trigger: 'blur' }
                    ],
           email: [
                      { required: true, message: '请输入邮箱地址', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' },
                      { validator: checkEmail, trigger: 'blur' }
                    ]
        }
      }
    },
    methods: {
      //1.动态获取userList数据
      async getUserList(){
       const {data: result} = await this.$http.get("/user/list",{params: this.queryInfo})
       if(result.status !== 200) return this.$message.error("获取列表失败")
       //为total属性赋值
       this.total = result.data.total
       this.userList = result.data.rows
      },
      handleSizeChange(pageSize){
        //查询的条件需要变化
        this.queryInfo.pageSize = pageSize
        //重新查询数据
        this.getUserList()
      },
      handleCurrentChange(pageNum){
        this.queryInfo.pageNum = pageNum
        this.getUserList()
      },
      async updateStatus(user){
        //获取用户的Id号/状态信息 发起restFul请求.
        //this.$http.put("/user/status/"+user.id+"/"+user.status)
        //模板字符串写法 `` 可以编辑多行,可以直接对象取值${key}
        //es6的高端写法
        const {data: result} =
        await this.$http.put(`/user/status/${user.id}/${user.status}`)
        if(result.status !== 200) return this.$message.error("更新操作失败")
        this.$message.success("更新操作成功!")
      },
      closeAddUserDialog(){
        //当对话框关闭时,应该重置表单
        this.$refs.addUserRuleForm.resetFields()
      },
      addUserBtn(){
        //对整个表单重新进行校验  1.获取表单的对象  2.进行数据校验
        this.$refs.addUserRuleForm.validate(async valid => {
          if(!valid) return this.$message.error("请正确填写数据")
          //之后发起ajax请求实现用户新增
          const {data: result} = await this.$http.post('/user/addUser',this.addUserForm)
          if(result.status !== 200) return this.$message.error("新增用户失败")
          this.$message.success("新增用户成功")
          //将对话框关闭
          this.addUserDialogVisible = false
          //重新刷新列表页面
          this.getUserList()
        })
      },
      async deleteUser(user){
        //定义消息确认框 promise对象 如果从中获取用户的选项 不方便
        const result = await this.$confirm('此操作将永久删除'+user.username+', 是否继续?', '提示', {
                  confirmButtonText: '确定',
                  cancelButtonText: '取消',
                  type: 'warning'
              }).catch(error => error)

        //确定: confirm   取消 cancel
        if(result !== 'confirm') return this.$message.info("用户取消操作")

        //发起ajax请求实现数据的删除...
        const {data: resultDB} = await this.$http.delete('/user/'+user.id)
        if(resultDB.status !== 200) return this.$message.error("用户删除失败!")
        this.$message.success("用户删除成功!")
        //重新加载用户列表
        this.getUserList()
      }

    },
    //当页面加载完成之后 调用该函数
    mounted(){
      //获取userList列表数据
      this.getUserList()
    }
  }
</script>

<!--
  当前样式是否支持less语法 样式的一种语言
  scoped 让样式只对当前组件有效 防止样式击穿
 -->
<style lang="less" scoped>

</style>

关于知识点梳理
列表页面结构

在这里插入图片描述

新增用户页面

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值