springboot+vue小白升级之路04-实现登录注册功能和springboot+vue小白升级之路05-实现JWT用户登录鉴权

661 篇文章 4 订阅
112 篇文章 0 订阅

我们接着上一课的内容继续

我还是尽量把全部代码都贴出来,方便大家学习。

项目结构截图

springboot后端

pom.xml

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.30</version>
        </dependency>

        <!--swagger依赖-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!--swagger ui-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <!-- jwt验证       -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.7</version>
        </dependency>
    </dependencies>

application.properties

server.port=8089

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimeZone=UTC
spring.datasource.username=root
spring.datasource.password=mysql123
#日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#配置别名
mybatis-plus.type-aliases-package=com.shrimpking.pojo
#开启逻辑删除,标识字段
mybatis-plus.global-config.db-config.logic-delete-field=is_deleted
#删除
mybatis-plus.global-config.db-config.logic-delete-value=1
#未删除
mybatis-plus.global-config.db-config.logic-not-delete-value=0
#swagger
spring.mvc.pathmatch.matching-strategy=ant_path_matcher

pojo

TestOne.java

package com.shrimpking.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/11/9 20:51
 */
@Data
@AllArgsConstructor
public class TestOne
{
    private int id;
    private String name;
    private String sex;
    private String phone;
}


User.java

package com.shrimpking.pojo;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * <p>
 * 用户表
 * </p>
 *
 * @author shrimpking
 * @since 2023-11-09
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("an_user")
@ApiModel(value="User对象", description="用户表")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键id")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty(value = "姓名")
    private String name;

    @ApiModelProperty(value = "密码")
    private String password;

    @ApiModelProperty(value = "年龄")
    private Integer age;

    @ApiModelProperty(value = "性别")
    private String sex;

    @ApiModelProperty(value = "电话")
    private String phone;

    @TableField(exist = false)
    private String token;
}

mapper

userMapper.java

package com.shrimpking.mapper;

import com.shrimpking.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.shrimpking.req.QueryParams;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * <p>
 * 用户表 Mapper 接口
 * </p>
 *
 * @author shrimpking
 * @since 2023-11-09
 */
public interface UserMapper extends BaseMapper<User> {

    /**
     * 基于注解的方式
     * @return
     */
    @Select("select * from an_user")
    List<User> getUsers();

    /**
     * 基于MapperXml的方式
     * @return
     */
    List<User> getAllUsers();

    /**
     * 基于MapperXml的,有条件,获取全部数据
     * @param queryParams
     * @return
     */
    List<User> findBySearch2(@Param("queryParams") QueryParams queryParams);
}

MapperXml

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.shrimpking.mapper.UserMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.shrimpking.pojo.User">
        <id column="id" property="id" />
        <result column="name" property="name" />
        <result column="password" property="password" />
        <result column="age" property="age" />
        <result column="sex" property="sex" />
        <result column="phone" property="phone" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, name, password, age, sex, phone
    </sql>

    <!-- 基于MapperXml的方式   -->
    <select id="getAllUsers" resultType="com.shrimpking.pojo.User">
        select <include refid="Base_Column_List"/> from an_user
    </select>

    <!-- 基于MapperXml的方式,有条件时,获取全部数据   -->
    <select id="findBySearch2" resultType="com.shrimpking.pojo.User">
        select <include refid="Base_Column_List"/> from an_user
        <where>
            <if test="queryParams != null and queryParams.name != null and queryParams.name != ''">
                or name like concat('%',#{queryParams.name},'%')
            </if>
            <if test="queryParams != null and queryParams.phone != null and queryParams.phone != ''">
                or phone like concat('%',#{queryParams.phone},'%')
            </if>
        </where>

    </select>

</mapper>

service

UserService.java

package com.shrimpking.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.shrimpking.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;
import com.shrimpking.req.QueryParams;
import com.shrimpking.res.Result;

import java.util.List;

/**
 * <p>
 * 用户表 服务类
 * </p>
 *
 * @author shrimpking
 * @since 2023-11-09
 */
public interface UserService extends IService<User> {

    /**
     * 基础注解的方式
     * @return
     */
    List<User> getUsers();

    /**
     * 基于MapperXml的方式
     * @return
     */
    List<User> getAllUsers();

    /**
     * 有查询条件,获取全部数据
     * @param queryParams
     * @return
     */
    List<User> findBySearch(QueryParams queryParams);

    /**
     * 基于MapperXml的,有条件,获取全部数据
     * @param queryParams
     * @return
     */
    List<User> findBySearch2(QueryParams queryParams);

    /**
     * 有查询条件时,获取分页数据
     * @param queryParams
     * @return
     */
    IPage<User> findBySearchPage(QueryParams queryParams);

    User login(User user);
}

serviceImpl

UserServiceImpl.java

package com.shrimpking.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shrimpking.exception.CustomException;
import com.shrimpking.pojo.User;
import com.shrimpking.mapper.UserMapper;
import com.shrimpking.req.QueryParams;
import com.shrimpking.res.Result;
import com.shrimpking.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shrimpking.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author shrimpking
 * @since 2023-11-09
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    /**
     * 基于注解的方式
     * @return
     */
    @Override
    public List<User> getUsers()
    {
        return this.userMapper.getUsers();
    }

    /**
     * 基于MapperXml的方式
     * @return
     */
    @Override
    public List<User> getAllUsers()
    {
        return this.userMapper.getAllUsers();
    }

    /**
     * 有查询条件,获取全部数据
     * @param queryParams
     * @return
     */
    @Override
    public List<User> findBySearch(QueryParams queryParams)
    {
        //声明查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        //姓名不为空,有条件值时,加入此条件
        queryWrapper.like(
                StringUtils.isNotBlank(queryParams.getName()),
                User::getName,queryParams.getName())
        //电话不为空,有条件值时,加入此条件
                .or().like(
                StringUtils.isNotBlank(queryParams.getPhone()),
                User::getPhone,queryParams.getPhone());
        //返回结果
        return this.baseMapper.selectList(queryWrapper);
    }

    /**
     * 基于MapperXml的,有条件,获取全部数据
     * @param queryParams
     * @return
     */
    @Override
    public List<User> findBySearch2(QueryParams queryParams)
    {
        return this.userMapper.findBySearch2(queryParams);
    }

    /**
     * 有查询条件时,获取分页数据
     * @param queryParams
     * @return
     */
    @Override
    public IPage<User> findBySearchPage(QueryParams queryParams)
    {
        //声明分页
        IPage<User> page = new Page<>(queryParams.getCurrentPage(),queryParams.getPageSize());
        //声明查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        //姓名不为空,有条件值时,加入此条件
        queryWrapper.like(
                StringUtils.isNotBlank(queryParams.getName()),
                User::getName,queryParams.getName())
                //电话不为空,有条件值时,加入此条件
                .or().like(
                StringUtils.isNotBlank(queryParams.getPhone()),
                User::getPhone,queryParams.getPhone())
                .orderByDesc(User::getId);
        //返回结果
        return this.baseMapper.selectPage(page, queryWrapper);
    }

    @Override
    public User login(User user)
    {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getName,user.getName());
        User one = this.baseMapper.selectOne(queryWrapper);
        if(one  == null || !one.getPassword().equals(user.getPassword())){
            throw new CustomException("用户名或密码错误");
        }
        //如果查询出来,有用户,生成token,与user一起返回
        String token = JwtUtils.createToken(one.getId().toString(), one.getPassword());
        one.setToken(token);
        //屏蔽密码
        one.setPassword("***");
        return one;
    }

}

controller

TsetController.java

package com.shrimpking.controller;

import com.shrimpking.pojo.TestOne;
import com.shrimpking.res.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/11/9 20:45
 */
@RestController
@RequestMapping("/test")
public class TestController
{

    @RequestMapping(value = "/start",method = RequestMethod.GET)
    public String start(){
        return "这是你的第一个springboot工程项目!已经启动!";
        //http://localhost:8089/test/start
    }

    @GetMapping("/getOne")
    public TestOne getTestOne(){
        return new TestOne(1,"tom","男","13000000000");
        //http://localhost:8089/test/getOne
        //{"id":1,"name":"tom","sex":"男","phone":"13000000000"}
    }

    @GetMapping("/start2")
    public Result start2(){
        return Result.success("这是你的第一个springboot工程项目!已经启动!");
        //http://localhost:8089/test/start2
        //{"code":"200","msg":"成功","data":"这是你的第一个springboot工程项目!已经启动!"}
    }

    @GetMapping("/getOne2")
    public Result getTestOne2(){
        return Result.success(new TestOne(2,"jerry","女","138999988888"));
        //http://localhost:8089/test/getOne2
        //{"code":"200","msg":"成功","data":{"id":2,"name":"jerry","sex":"女","phone":"138999988888"}}
    }
}

UserController.java

package com.shrimpking.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.shrimpking.exception.CustomException;
import com.shrimpking.pojo.User;
import com.shrimpking.req.QueryParams;
import com.shrimpking.res.Result;
import com.shrimpking.service.UserService;
import net.bytebuddy.implementation.bytecode.Throw;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

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

import java.util.List;


/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author shrimpking
 * @since 2023-11-09
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 3基于mybatisplus的方式
     * @return
     */
    @GetMapping("/getList")
    public List<User> getUserList(){
        return  this.userService.list();
        //http://localhost:8089/user/getList
    }

    /**
     * 2基于注解的方式
     *
     * @return
     */
    @GetMapping("/getUsers")
    public List<User> getUsers(){
        return  this.userService.getUsers();
        //http://localhost:8089/user/getUsers
        //[{"id":1,"name":"zhangsan","password":"1234","age":33,"sex":"男","phone":"13300000000"},
        // {"id":2,"name":"lisi","password":"1234","age":13,"sex":"女","phone":"13400000000"}]
    }

    /**
     * 1基于MapperXml的方式
     * @return
     */
    @GetMapping("/getAll")
    public List<User> getAllUsers(){
        return this.userService.getAllUsers();
        //http://localhost:8089/user/getAll
        //[{"id":1,"name":"zhangsan","password":"1234","age":33,"sex":"男","phone":"13300000000"},
        // {"id":2,"name":"lisi","password":"1234","age":13,"sex":"女","phone":"13400000000"}]
    }

    /**
     * 3基于mybatisplus的方式
     * @return
     */
    @GetMapping("/getList2")
    public Result getUserList2(){
        return  Result.success(this.userService.list());
        //http://localhost:8089/user/getList2
        //{"code":"200","msg":"成功","data":[
        // {"id":1,"name":"zhangsan","password":"1234","age":33,"sex":"男","phone":"13300000000"},
        // {"id":2,"name":"lisi","password":"1234","age":13,"sex":"女","phone":"13400000000"}]}
    }

    /**
     * 2基于注解的方式
     *
     * @return
     */
    @GetMapping("/getUsers2")
    public Result getUsers2(){
        return  Result.success(this.userService.getUsers());
        //http://localhost:8089/user/getUsers2
        //{"code":"200","msg":"成功","data":[
        // {"id":1,"name":"zhangsan","password":"1234","age":33,"sex":"男","phone":"13300000000"},
        // {"id":2,"name":"lisi","password":"1234","age":13,"sex":"女","phone":"13400000000"}]}
    }

    /**
     * 1基于MapperXml的方式
     * @return
     */
    @GetMapping("/getAll2")
    public Result getAllUsers2(){
        return Result.success(this.userService.getUsers());
        //http://localhost:8089/user/getAll2
        //{"code":"200","msg":"成功","data":[
        // {"id":1,"name":"zhangsan","password":"1234","age":33,"sex":"男","phone":"13300000000"},
        // {"id":2,"name":"lisi","password":"1234","age":13,"sex":"女","phone":"13400000000"}]}
    }

    /**
     * 获取全部数据
     * @return
     */
    @GetMapping("/findAll")
    public Result findAll(){
        return Result.success(this.userService.list());
    }


    /**
     * 有查询条件时,获取全部数据
     * @param queryParams
     * @return
     */
    @GetMapping("/search")
    public Result findBySearch(QueryParams queryParams){
        List<User> list = this.userService.findBySearch(queryParams);
        return Result.success(list);
    }

    /**
     * 基于MapperXml的,有条件,获取全部数据
     * @param queryParams
     * @return
     */
    @GetMapping("/search2")
    public Result findBySearch2(QueryParams queryParams){
        List<User> list = this.userService.findBySearch2(queryParams);
        return Result.success(list);
    }

    /**
     * 有查询条件时,获取分页数据
     * @param queryParams
     * @return
     */
    @GetMapping("/searchPage")
    public Result findBySearchPage(QueryParams queryParams){
        IPage<User> list = this.userService.findBySearchPage(queryParams);
        return Result.success(list);
    }

    @PostMapping("/save")
    public Result save(@RequestBody User user){
        //先查询有无同名用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getName,user.getName());
        int count = this.userService.count(queryWrapper);
        if(count > 0) return Result.error("此用户名已存在");

        boolean save = this.userService.save(user);
        if(!save) return Result.error("保存失败");
        return Result.success("保存成功");
    }

    @PostMapping("/update")
    public Result update(@RequestBody User user){
        //先查询有无同名用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getName,user.getName());
        User one = this.userService.getOne(queryWrapper);
        if(one != null && !one.getId().equals(user.getId())){
            return Result.error("此用户名已存在");
        }

        boolean save = this.userService.updateById(user);
        if(!save) return Result.error("更新失败");
        return Result.success("更新成功");
    }

    @DeleteMapping("/delete")
    public Result delete(@RequestParam("id") Integer id){
        boolean remove = this.userService.removeById(id);
        if(!remove) return Result.error("删除失败");
        return Result.success("删除成功");
    }

    @PostMapping("/login")
    public Result login(@RequestBody User user){
        User login = this.userService.login(user);
        return Result.success(login);
    }

    @PostMapping("/register")
    public Result register(@RequestBody User user){
        //先查询有无同名用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getName,user.getName());
        int count = this.userService.count(queryWrapper);
        if(count > 0) {
            throw new CustomException("此用户已经存在,请重新注册!");
        }

        boolean save = this.userService.save(user);
        if(!save) return Result.error("注册失败");
        return Result.success("注册成功");
    }
}

config

apiConfig.java

package com.shrimpking.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/11/12 14:39
 */
@Configuration
public class ApiConfig implements WebMvcConfigurer
{
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer)
    {
        //指定controller的统一接口前缀,增加接口前缀
        configurer.addPathPrefix("/api",clazz-> clazz.isAnnotationPresent(RestController.class));
    }
}

corsConfig.java

package com.shrimpking.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

// 案例 一
@Configuration
public class CorsConfig implements WebMvcConfigurer
{

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                //是否发送Cookie
                .allowCredentials(true)
                //放行哪些原始域
                .allowedOriginPatterns("*")
                .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
                .allowedHeaders("*")
                .exposedHeaders("*");
    }

    /**
     * 增加了自定义拦截器后,需要使用此方法,才可以解决跨域,
     * 前一个方法maps,自动失效了。
     * @return
     */
    @Bean
    public CorsFilter corsFilter(){
        //添加cors配置
        CorsConfiguration config = new CorsConfiguration();
        //允许的域,不要写*号
        config.addAllowedOrigin("http://localhost:8080");
        //是否发送cookie
        config.setAllowCredentials(true);
        //允许的请求方式
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        //允许的头信息
        config.addAllowedHeader("*");
        //添加映射路径
        UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
        configurationSource.registerCorsConfiguration("/**",config);

        return new CorsFilter(configurationSource);

    }
}

jwtCofig.java

package com.shrimpking.config;

import com.shrimpking.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/11/12 14:39
 */
@Configuration
public class JwtConfig implements WebMvcConfigurer
{

    @Autowired
    private JwtInterceptor jwtInterceptor;
    /**
     * 添加jwt拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry)
    {
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/user/login")
                .excludePathPatterns("/api/user/register");
    }


}

mybatisplusConfig.java

package com.shrimpking.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.shrimpking.mapper")
public class MybatisPlusConfig
{
    /**
     * 配置分页插件的
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor()
    {
        MybatisPlusInterceptor interceptor
                = new MybatisPlusInterceptor();
        //分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //防止全表更新插件
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        return interceptor;
    }
}

swaggerConfig.java

package com.shrimpking.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/9/10 14:58
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig
{
    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any()).build();
        
    }

    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("系统接口文档")
                .description("接口文档的描述")
                .version("1.0")
                .contact(new Contact("weixin","http://www.baidu.com","1@1.com"))
                .build();
    }
}

exception

CustomException.java

package com.shrimpking.exception;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/11/11 11:04
 */
public class CustomException extends RuntimeException
{
    private String message;

    public CustomException(String message)
    {
        this.message = message;
    }

    @Override
    public String getMessage()
    {
        return this.message;
    }


}

globalException.java

package com.shrimpking.exception;

import com.shrimpking.res.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/11/11 11:01
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler
{
    @ExceptionHandler(Exception.class)
    public Result error(HttpServletRequest request,Exception e){
        log.error("异常信息:",e);
        return Result.error("系统异常");
    }

    @ExceptionHandler(CustomException.class)
    public Result customException(HttpServletRequest request,CustomException e){
        log.error("异常信息:",e);
        return Result.error(e.getMessage());
    }
}

interceptor

jwtInterceptor.java

package com.shrimpking.interceptor;


import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.shrimpking.exception.CustomException;
import com.shrimpking.service.UserService;
import com.shrimpking.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/11/12 16:21
 */
@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor
{
    @Autowired
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
    {
        //获取token,从请求头部获取
        String token = request.getHeader("z-token");
        if(StringUtils.isBlank(token)){
            //token为空,从请求参数获取
            token = request.getParameter("token");
        }

        //token为空,重新登录
        if(StringUtils.isBlank(token)){
            throw new CustomException("获取token失败,请重新登录!");
        }
        //验证解析token
        return JwtUtils.verify(token);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception
    {

    }
}

req

QueryParams.java

package com.shrimpking.req;

import lombok.Data;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/11/10 12:27
 */
@Data
public class QueryParams
{
    private String name;
    private String phone;
    private Long currentPage;
    private Long pageSize;
}

res

result.java

package com.shrimpking.res;

import lombok.Data;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/11/10 11:03
 */
@Data
public class Result
{
    public static final String SUCCESS = "200";
    public static final String ERROR = "400";

    private String code;
    private String msg;
    private Object data;

    public static Result success(){
        Result result = new Result();
        result.setCode(SUCCESS);
        result.setMsg("成功");
        return result;
    }

    public static Result success(Object data){
        Result result = new Result();
        result.setCode(SUCCESS);
        result.setMsg("成功");
        result.setData(data);
        return result;
    }

    public static Result error(String msg){
        Result result = new Result();
        result.setCode(ERROR);
        result.setMsg(msg);
        return result;
    }



}

utils

jwtUtils.java

package com.shrimpking.utils;

import ch.qos.logback.classic.turbo.TurboFilter;
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.shrimpking.exception.CustomException;
import com.shrimpking.pojo.User;
import com.shrimpking.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Objects;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/11/12 14:49
 */
@Slf4j
@Component
public class JwtUtils
{
    private static UserService staticUserService;

    @Autowired
    private UserService userService;

    @PostConstruct
    public void setUserService(){
        staticUserService = userService;
    }

    /**
     * 生成token
     * @param adminId
     * @param sign
     * @return
     */
    public static String createToken(String userId,String pwdToSign){
        return JWT.create()
                //将user id保存到里面,作为载荷
                .withAudience(userId)
                //2个小时以后过期
                .withExpiresAt(DateUtil.offsetHour(new Date(),2))
                //以password作为签名
                .sign(Algorithm.HMAC256(pwdToSign));
    }

    /**
     * 获取当前用户
     * @return
     */
    public static User getCurrentUser(){
        //声明token
        String token = null;
        try
        {
            //获取请求
            HttpServletRequest request
                    = ((ServletRequestAttributes)Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            //从请求头部获取token
            token = request.getHeader("z-token");

            //如果头部没有,请请求参数获取token
            if(StringUtils.isBlank(token)){
                token = request.getParameter("token");
            }

            //如果token没有,返回null
            if(StringUtils.isBlank(token)){
                log.error("获取当前登录用户信息失败,token={}",token);
                return null;
            }
            //解析token
            String userId = JWT.decode(token).getAudience().get(0);
            //返回用户
            return staticUserService.getById(userId);
        }catch (Exception e){
            log.error("获取当前登录用户信息失败,token={}",token,e);
            return null;
        }
    }

    /**
     * 验证token
     * @param token
     * @return
     */
    public static Boolean verify(String token){

        //用户id
        String userId;
        //用户
        User user;
        try
        {
            //解析token,获取id
            userId = JWT.decode(token).getAudience().get(0);
            //根据id,获取用户
            user = staticUserService.getById(userId);
        }catch (Exception e){
            String errorMsg = "非法token,验证失败,请重新登录!";
            log.error(errorMsg + ",token=" + token ,e);
            throw  new CustomException(errorMsg);
        }
        //未查到用户
        if(user == null){
            throw new CustomException("用户不存在,请重新登录!");
        }

        try
        {
            //解析过程中,无异常,说明验证成功
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
            verifier.verify(token);
        }catch (JWTVerificationException e){
            throw new CustomException("token验证失败,请重新登录");
        }

        return true;
    }
}

启动类

package com.shrimpking;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.shrimpking.mapper")
public class SpringbootVueTest31Application
{

    public static void main(String[] args)
    {
        SpringApplication.run(SpringbootVueTest31Application.class, args);
    }

}

数据库

drop table if exists an_user;
create table an_user(
	id int not null auto_increment primary key comment '主键id',
	name varchar(255) not null unique comment '姓名',
	`password` varchar(255) not null comment '密码',
	age int(3) default null comment '年龄',
	sex varchar(10) default null comment '性别',
	phone varchar(20) default null comment '电话'
) comment '用户表';
insert into an_user values (1,'zhangsan','1234',33,'男','13300000000');
insert into an_user values (2,'lisi','1234',13,'女','13400000000');

Vue前端

vue.config.js

module.exports = {
  transpileDependencies: true
}

package.json

{
  "name": "vueweb",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build"
  },
  "dependencies": {
    "axios": "^1.6.1",
    "core-js": "^3.8.3",
    "echarts": "^5.1.2",
    "element-ui": "^2.15.14",
    "mockjs": "^1.1.0",
    "vue": "^2.6.14",
    "vue-router": "^3.5.1",
    "vuex": "^3.6.2"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^5.0.0",
    "@vue/cli-service": "^5.0.0",
    "sass": "^1.32.7",
    "sass-loader": "^12.0.0",
    "vue-template-compiler": "^2.6.14"
  }
}

global.css


html,body{
    margin: 0;
    padding: 0;
}

* {
    box-sizing: border-box;
}

router.js

import Vue from 'vue'
import VueRouter from 'vue-router'


Vue.use(VueRouter)

const routes = [
  {
    path: '/login',
    name:'LoginView',
    component: ()=> import('@/views/LoginView.vue'),
  },
  {
    path:'/register',
    name: 'Register',
    component: ()=> import('@/views/RegisterView.vue'),
  },
  {
    path: '/',
    redirect: '/home',
    name: 'Layout',
    component: ()=> import('@/views/Layout.vue'),
    children:[
      {
        path: 'home',
        name: 'HomeView',
        component: ()=> import('@/views/HomeView.vue')
      },
      {
        path: 'admin',
        name: 'AdminView',
        component: ()=> import('@/views/User/AdminView.vue'),
      },
      {
        path:'user',
        name:'UserView',
        component: ()=> import('@/views/User/UserView.vue'),
      },
    ]
  },
]

const router = new VueRouter({
  routes
})

//白名单
const IGNORE_URLS = ['/login','/register'];

//前置守卫
router.beforeEach((to, from, next) => {
  //在白名单中,放行
  if(IGNORE_URLS.includes(to.path)){
    next();
  }
  //获取用户
  let admin = JSON.parse(window.localStorage.getItem('access-admin'));
  if(!admin && !IGNORE_URLS.includes(to.path)){
    //没有登录 ,没有在白名单中,跳转登录
    return next('/login');
  }

  next();
});

export default router

store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
  },
  getters: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

utils

request.js

import axios from 'axios'

const request  = axios.create({
    baseURL: 'http://localhost:8089/api',  //
    timeout: 5000,
});

//request 拦截器
request.interceptors.request.use( config =>{
    config.headers['Content-Type'] =  'application/json;charset=utf-8';
    //获取token
    const admin = JSON.parse(window.localStorage.getItem('access-admin'));
    if(admin){
        config.headers['z-token'] = admin.token;
    }
    return config;
},error => {
    return Promise.reject(error);
});

//respose 拦截器
request.interceptors.response.use( response => {
    //response.data即为后端返回的result, 也就是脱壳
    let res = response.data;

    //兼容服务端返回的字符串数据
    if(typeof res === 'string'){
        res = res ? JSON.parse(res) : res;
    }
    return res;
},error => {
    console.log('error:' + error);
    return Promise.reject(error);
});

export default request;

main.js

import Vue from 'vue'
import App from './App.vue'
import store from '@/store'
import router from "@/router";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import axios from "axios";
import * as echarts from 'echarts'
import '@/assets/global.css'

Vue.prototype.$echarts = echarts;
axios.defaults.baseURL='http://localhost:8089';
Vue.prototype.$http = axios;
Vue.use(ElementUI,{size:'small'});
Vue.config.productionTip = false;

new Vue({
  render: h => h(App),
  store,
  router
}).$mount('#app');

app.vue

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<style lang="scss">

</style>

register.vue

<template>
    <div class="register-area">
        <h1 class="title">注册用户</h1>
        <el-form
                :model="registerForm"
                :rules="rules"
                ref="registerForm"
                class="form-demo"
                label-width="100px;"
                label-postion="left">
            <el-form-item prop="name">
                <el-input
                        v-model="registerForm.name"
                        placeholder="用户名"
                        clearable>
                    <template slot="prepend"><i class="el-icon-user-solid"></i></template>
                </el-input>
            </el-form-item>
            <el-form-item prop="password">
                <el-input
                        v-model="registerForm.password"
                        placeholder="密码"
                        show-password
                        clearable>
                    <template slot="prepend"><i class="el-icon-lock"></i></template>
                </el-input>
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="resetBtn" class="reset-btn">重 置</el-button>
            </el-form-item>
            <el-button type="primary" @click="register" class="register-btn">注 册</el-button>
            <el-button type="text" @click="toLogin" class="login-btn">返回登录</el-button>
        </el-form>

    </div>
</template>

<script>
    import request from "@/utils/request";

    export default {
        name: "RegisterView",
        data(){
            return {
                registerForm: {
                    name:'',
                    password:''
                },
                rules: {
                    name: [{ required: true ,message: '请输入用户名', trigger: 'blur'}],
                    password: [{ required: true ,message: '请输入密码', trigger: 'blur'}],
                }
            }
        },
        methods: {
            //重置
            resetBtn(){
                this.$refs.registerForm.resetFields();
            },
            //返回登录
            toLogin(){
                this.$router.replace('/login');
            },
            //注册
            register(){
                this.$refs.registerForm.validate((valid)=>{
                    if(valid){
                        request.post('/user/register',this.registerForm)
                            .then(res=>{
                                if(res.code === '200'){
                                    this.$message.success(res.msg);
                                    this.$router.replace('/login');
                                }else {
                                    this.$message.error(res.msg);
                                }
                            })
                    }
                })
            }
        }
    }
</script>

<style lang="scss" scoped>
    .register-area{
        width: 400px;
        height: 500px;
        border: 1px solid rgba(107,149,224,0.5);
        border-radius: 15px;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%,-75%);
        padding: 10px;

        .title{
            text-align: center;
            margin-bottom: 30px;

        }

        .form-demo{
            width: 80%;
            margin: 0 auto;

            .reset-btn{
                width: 100%;
                margin-top: 24px;
                height: 40px;
            }

            .register-btn{
                width: 100%;
                height: 40px;
            }

            .login-btn{
                width: 100%;
                margin-top: 5px;
                text-align: center;
            }
        }


    }
</style>

login.vue

<template>
    <div class="register-area">
        <h1 class="title">手牵手带小白做毕设</h1>
        <el-form
                :model="loginForm"
                :rules="rules"
                ref="loginForm"
                class="form-demo"
                label-width="100px;"
                label-postion="left">
            <el-form-item prop="name">
                <el-input
                        v-model="loginForm.name"
                        placeholder="用户名"
                        clearable>
                    <template slot="prepend"><i class="el-icon-user-solid"></i></template>
                </el-input>
            </el-form-item>
            <el-form-item prop="password">
                <el-input
                        v-model="loginForm.password"
                        placeholder="密码"
                        show-password
                        clearable>
                    <template slot="prepend"><i class="el-icon-lock"></i></template>
                </el-input>
            </el-form-item>

            <el-button type="primary" @click="login" class="login-btn">登 录</el-button>
            <el-button type="text" @click="toRegister" class="register-btn">没有账号,注册一下</el-button>
        </el-form>
        <div>

        </div>
    </div>
</template>

<script>
    import request from "@/utils/request";

    export default {
        name: "LoginView",
        data(){
            return {
                loginForm: {
                    name:'',
                    password:''
                },
                rules: {
                    name: [{ required: true ,message: '请输入用户名', trigger: 'blur'}],
                    password: [{ required: true ,message: '请输入密码', trigger: 'blur'}],
                }
            }
        },
        methods: {
            //注册
            toRegister(){
                this.$router.replace('/register');
            },
            login(){
                this.$refs.loginForm.validate((valid)=>{
                    if(valid){
                        request.post('/user/login',this.loginForm)
                            .then(res=>{
                                if(res.code === '200'){
                                    this.$message.success(res.msg);
                                    window.localStorage.setItem('access-admin',JSON.stringify(res.data));
                                    this.$router.replace('/home');
                                }else {
                                    this.$message.error(res.msg);
                                }
                            })
                    }
                })
            }
        }
    }
</script>

<style lang="scss" scoped>
    .register-area{
        width: 400px;
        height: 310px;
        border-radius: 15px;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%,-75%);
        padding: 10px;
        background-color: rgba(107,149,224,0.5);

        .title{
            text-align: center;
            margin-bottom: 30px;

        }

        .form-demo{
            width: 80%;
            margin: 0 auto;

            .login-btn{
                width: 100%;
                margin-top: 24px;
                height: 40px;
            }

            .register-btn{
                width: 100%;
                margin-top: 5px;
                text-align: center;
                color: #ffffff;
            }
        }


    }
</style>

layout.vue

<template>
    <div>
        <el-container class="container">
            <el-header class="header-area">
                <img src="@/assets/logo.png" alt="logo" class="logo">
                <span class="title">手牵手带小白做毕设</span>
                <span class="admin-info">
                <el-dropdown @command="handleCommand">
                    <span class="el-dropdown-link">
                        用户:&nbsp;&nbsp; <strong>{{ admin.name }}</strong>
                        <i class="el-icon-arrow-down el-icon--right"></i>
                    </span>
                    <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item command="logout">退出</el-dropdown-item>
                    </el-dropdown-menu>
                    </el-dropdown>
                </span>
            </el-header>
            <el-container class="middle-area">
                <el-aside  class="left-aside">
                    <el-menu
                            :default-active="$route.path"
                            class="el-menu-vertical-demo"
                            background-color="#545c64"
                            text-color="#fff"
                            active-text-color="#ffd04b"
                            router>
                        <el-menu-item index="/home">
                            <i class="el-icon-menu"></i>
                            <span slot="title">系统首页</span>
                        </el-menu-item>
                        <el-submenu index="/admin">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span>用户管理</span>
                            </template>
                            <el-menu-item-group>
                                <el-menu-item index="/admin">管理员信息</el-menu-item>
                                <el-menu-item index="/user">用户信息</el-menu-item>
                            </el-menu-item-group>
                        </el-submenu>
                        <el-submenu index="/3-1">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span>信息管理</span>
                            </template>
                            <el-menu-item-group>
                                <el-menu-item index="3-1">xxx信息</el-menu-item>
                                <el-menu-item index="3-2">yyy信息</el-menu-item>
                            </el-menu-item-group>
                        </el-submenu>
                    </el-menu>
                </el-aside>
                <el-main>
                    <router-view/>
                </el-main>
            </el-container>
        </el-container>
    </div>
</template>

<script>
    export default {
        name: "Layout",
        computed: {
            admin(){
                return JSON.parse(window.localStorage.getItem('access-admin')) || { name: '未登录'};
            }
        },
        methods: {
            //下拉菜单命令
            handleCommand(command){
                if (command === 'logout') {
                    this.logout();
                }
            },
            //退出
            logout(){
                window.localStorage.clear();
                this.$message.success('退出成功!');
                this.$router.replace('/login');
            }
        }
    }
</script>

<style lang="scss" scoped>
    .container{
        height: 100vh;

        .header-area{
            background-color: #4c535a;

            .logo {
                width: 40px;
                position: relative;
                top: 10px;
            }

            .title{
                font-size: 20px;
                margin-left: 15px;
                color: white;
            }

            .admin-info{
                float: right;
                margin-right: 30px;
                line-height: 60px;
                .el-dropdown-link{
                    color: #cccccc;
                }
            }

        }

        .middle-area{

            .left-aside{
                overflow: hidden;
                height: 100%;
                /*background-color: #545c64;*/
                width:230px  !important;

                .el-menu-vertical-demo{
                    height: 100%;
                }


            }



        }

    }
</style>

home.vue

<template>
    <div>
        <div style="font-size: 18px;margin: 15px 0;">手牵手教小白做毕设</div>
        <div style="font-size: 18px;margin: 15px 0;">大家给个一键三连</div>
        <div style="font-size: 18px;margin: 15px 0;">感谢大家</div>
    </div>
</template>

<script>
    export default {
        name: "HomeView"
    }
</script>

<style scoped>

</style>

adminview.vue

<template>
    <div>
        <!-- 搜索区域       -->
        <div style="margin-bottom:15px;">
            <el-input
                    v-model="searchForm.name"
                    style="width:200px;"
                    placeholder="请输入姓名"
                    @clear="doSearch"
                    @keypress.native.enter="doSearch"
                    clearable>
            </el-input>
            <el-input
                    v-model="searchForm.phone"
                    style="width:200px;margin-left: 10px;"
                    placeholder="请输入电话"
                    @clear="doSearch"
                    @keypress.native.enter="doSearch"
                    clearable>
            </el-input>
            <el-button
                    type="warning"
                    style="margin-left: 10px;"
                    icon="el-icon-search"
                    @click="doSearch">查询</el-button>
            <el-button
                    type="primary"
                    style="margin-left: 10px;"
                    icon="el-icon-toilet-paper"
                    @click="clearSearch">清空</el-button>
            <el-button
                    type="primary"
                    style="margin-left: 10px;"
                    icon="el-icon-plus" @click="addBtn">新增</el-button>
        </div>
        <!-- 表格区域       -->
        <el-table
                :data="tableData"
                style="width: 100%">
            <el-table-column
                    prop="id"
                    label="ID">
            </el-table-column>
            <el-table-column
                    prop="name"
                    label="姓名">
            </el-table-column>
            <el-table-column
                    prop="password"
                    label="密码">
            </el-table-column>
            <el-table-column
                    prop="age"
                    label="年龄">
            </el-table-column>
            <el-table-column
                    prop="sex"
                    label="性别">
            </el-table-column>
            <el-table-column
                    prop="phone"
                    label="电话">
            </el-table-column>
            <el-table-column label="操作">
                <template slot-scope="scope">
                    <el-button type="primary" icon="el-icon-edit" @click="editBtn(scope.row)">编辑</el-button>
                    <el-button type="danger" icon="el-icon-delete" @click="deleteBtn(scope.row)">删除</el-button>
                </template>
            </el-table-column>
        </el-table>
        <!-- 分页区域       -->
        <div style="margin-top:15px;">
            <el-pagination
                    @size-change="handleSizeChange"
                    @current-change="handleCurrentChange"
                    :current-page="searchForm.currentPage"
                    :page-sizes="[2, 5, 10, 20]"
                    :page-size="searchForm.pageSize"
                    layout="total, sizes, prev, pager, next, jumper"
                    :total="total">
            </el-pagination>
        </div>
        <!--  对话框      -->
        <div>
            <el-dialog
                    :title="dialogTitle"
                    :visible.sync="dialogFormVisible"
                    :close-on-click-modal="false"
                    @close="closeDialog"
                    width="35%">
                <el-form
                        :model="addForm"
                        :rules="rules"
                        ref="addForm"
                        :label-width="formLabelWidth"
                        label-postion="left">
                    <el-form-item label="姓名" prop="name">
                        <el-input v-model="addForm.name" clearable></el-input>
                    </el-form-item>
                    <el-form-item label="密码" prop="password">
                        <el-input v-model="addForm.password" clearable></el-input>
                    </el-form-item>
                    <el-form-item label="年龄" prop="age">
                        <el-input-number v-model="addForm.age" :max="199" :min="1" label="描述文字"></el-input-number>
                    </el-form-item>
                    <el-form-item label="性别" prop="sex">
                        <el-radio v-model="addForm.sex" label="男">男</el-radio>
                        <el-radio v-model="addForm.sex" label="女">女</el-radio>
                    </el-form-item>
                    <el-form-item label="电话" prop="phone">
                    <el-input v-model="addForm.phone" clearable></el-input>
                </el-form-item>
                </el-form>
                <div slot="footer" class="dialog-footer">
                    <el-button @click="resetBtn" v-show="dialogTitle === '新增用户'">重 置</el-button>
                    <el-button type="primary" @click="submitBtn">确 定</el-button>
                </div>
            </el-dialog>
        </div>
    </div>
</template>

<script>
    import request from "@/utils/request";

    export default {
        name: "AdminView",
        data() {
            return {
                //添加表单
                addForm:{
                    name:'',
                    password:'',
                    age:'',
                    sex:'',
                    phone:''
                },
                rules:{
                    name:[{required: true, message: '请输入姓名', trigger: 'blur'}],
                    password:[{required: true, message: '请输入密码', trigger: 'blur'}],
                    age:[{required: true, message: '请输入年龄', trigger: 'blur'}],
                    sex:[{required: true, message: '请选择性别', trigger: 'blur'}],
                    phone:[{required: true, message: '请输入电话', trigger: 'blur'}],
                },
                //表单标题宽度
                formLabelWidth:'80px',
                //对话框标题
                dialogTitle:'',
                //对话框
                dialogFormVisible: false,
                //搜索条件
                searchForm:{
                    name: '',
                    phone: '',
                    currentPage: 1,
                    pageSize: 5
                },
                tableData: [],
                total:0
            }
        },
        methods: {
            //删除
            deleteBtn(row){
                this.$confirm(`您确定要删除【${row.name}】吗`,'删除提示',{
                    confirmButtonText:'删除',
                    cancelButtonText:'取消',
                    type:'warning',
                }).then(()=>{
                    request.delete('/user/delete',{
                        params:{ id : row.id}
                    }).then(res => {
                        if(res.code === '200'){
                            this.$message.success(res.data);
                            this.doSearch();
                        }
                    })
                }).catch(_=>{
                    this.$message.warning('已取消删除');
                })
            },
            //编辑
            editBtn(row){
                let obj = JSON.parse(JSON.stringify(row));
                this.addForm = obj;
                this.dialogTitle = "编辑用户";
                this.dialogFormVisible = true;
            },
            //关闭对话框
            closeDialog(){
                this.resetBtn();
                this.dialogFormVisible = false;
            },
            //新增保存
            submitBtn(){
                this.$refs.addForm.validate((valid)=>{
                    if(valid){
                        //校验通过
                        //有id,编辑,没有id是新增
                        request.post(this.addForm.id ? '/user/update':'/user/save',this.addForm)
                            .then(res=>{
                                if(res.code === '200'){
                                    this.$message.success(res.data);
                                    this.resetBtn();
                                    this.dialogFormVisible = false;
                                    this.doSearch();
                                }else {
                                    this.$message.error(res.msg);
                                }
                            })
                    }
                })
            },
            //新增重置
            resetBtn(){
                this.$refs.addForm.resetFields();
                this.addForm = {};
              
            },
            addBtn(){
                this.dialogTitle = '新增用户';
                this.dialogFormVisible = true;
            },
            clearSearch(){
                this.searchForm.name = '';
                this.searchForm.phone = '';
                this.doSearch();
            },
            //搜索
            doSearch(){
                // request.get('/user/search',{
                //     params: this.searchForm
                // }).then(res=>{
                //     if(res.code === '200'){
                //         this.tableData = res.data;
                //     }else {
                //         this.$message.error("查询失败");
                //     }
                // })

                //修复bug
                this.searchForm.currentPage = 1;
                this.getData();

            },
            handleSizeChange(val) {
                this.searchForm.pageSize = val;
                this.getData();
            },
            handleCurrentChange(val) {
                this.searchForm.currentPage = val;
                this.getData();
            },
            //获取数据
            getData(){
                // request.get('/user/findAll')
                //     .then(res => {
                //         if(res.code === '200'){
                //             this.tableData = res.data;
                //         }else {
                //             this.$message.error('获取数据失败');
                //         }
                //     });
                request.get('/user/searchPage',{
                    params: this.searchForm
                }).then(res=>{
                    if(res.code === '200'){
                        //console.log(res)
                        this.tableData = res.data.records; //数据
                        this.searchForm.currentPage = res.data.current; //当前页
                        this.searchForm.pageSize = res.data.size; //页条数
                        this.total = res.data.total; //总条数
                    }else {
                        this.$message.error(res.msg);
                    }
                });
            }
        },
        created(){
            //获取数据
            this.getData();
        }
    }
</script>

<style scoped>

</style>

userview.vue

<template>
    <div>UserView</div>
</template>

<script>
    export default {
        name: "UserView"
    }
</script>

<style scoped>

</style>

测试

登录

 注册

 首页

 管理员信息

 非法token

退出

  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虾米大王

有你的支持,我会更有动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值