SpringBoot+Vue实现简单用户管理平台第一篇(后端接口设计)

news2025/2/28 2:57:13
  • 🚀 注重版权,转载请注明原作者和原文链接
  • 🥭 作者:Yuan-Programmer
  • 🍎 主页:https://blog.csdn.net/weixin_47971206/article/details/121368075?spm=1001.2014.3001.5502
  • 🍉 进来的小伙伴点点赞呀

本案例第二篇教程地址:SpringBoot+Vue实现简单用户管理平台第二篇(前端设计,接口对接)

demo地址预览(域名正在审核,将就ip访问):http://43.138.223.178/user-manager

花了几个小时做了一个SpringBoot+Vue的简单用户管理demo项目,适合新手教程,项目已在Gitee上开源,Gitee开源地址:https://gitee.com/yuandewei/Yuan-SpringBoot/tree/master

Gitee上开源的代码跟本次的案例的代码有些区别,本次案例稍微改了一点点,不过不影响Gitee上的项目运行,大致效果如下,功能可以访问demo地址测试哦

在这里插入图片描述

前言

开发环境

开发工具就不多介绍啦,就IDEA做后端,VSCode做前端,用其他的也都可以

技术

本次后端用到的技术呢: 主要就两个,SpringBoot + MyBatisPlus

前端的技术用到的技术: Vue,结合脚手架以及element ui框架开发前端

表设计

既然是用户管理嘛,肯定有用户表,我们先来设计表结构

这里说明一点,这次案例是新手教程,着重讲解功能的实现,所以用户信息参数方面就没有那么严格的校验,一般像号码这种字段肯定是设置为 char(11) 并且后端要校验的

在这里插入图片描述

创建Maven工程

创建一个空的Maven项目,大家应该都会了吧,还不会的小伙伴看之前的其他项目教程哦(我个人习惯创建maven工程,你喜欢直接创建springboot项目也可以,)

我这里创建好了一个 user-manager的maven项目,创建好项目,点击右下角选择自动导入,没有弹出来也没关系
在这里插入图片描述

引入依赖

在这里插入图片描述

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/>
    </parent>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- MyBatis-Plus依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>
        <!-- 数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- Web启动依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- SpringBoot测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 处理JSON的 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>
    </dependencies>

基本配置

创建 com.xiaoyuan.usermanager 目录,新建一个启动类 UserManagerApplication
在这里插入图片描述

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

在 resources 资源目录下新建 application.yml 配置文件
在这里插入图片描述

图片有误,少了时间格式转换三行代码,看下面

server:
  # 端口
  port: 8081

spring:
  # 数据源配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///l_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    username: xiaoyuan
    password: root
  # 时间格式转换
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
    
mybatis-plus:
  # mapper文件映射路径
  mapper-locations: classpath*:mapper/*.xml
  configuration:
    # 打印SQL语句
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

db层

entity实体类

新建 db 包,在 db 包下新建 entitymapper 两个包,在 entity 包下新建一个 User
在这里插入图片描述

注意一下,图片里 describe 有个注解忘记加上了,以下面代码为准

@Data
public class User {

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

    // 用户名
    private String username;

    // 昵称
    private String nickname;

    // 密码
    private String password;

    // 号码
    private String phone;

    // 性别
    private Character sex;

    // 描述
    @TableField(value = "`describe`") // describe属于数据库关键字,加上``区分
    private String describe;

    // 创建时间
    @TableField(fill = FieldFill.INSERT) // insert操作时自动注入时间
    private Date gmtCreate;
}

mapper数据访问层

mapper 包下新建一个 UserMapper,继承MyBatisPlus的 BaseMapper 类,作为DAO层操作数据
在这里插入图片描述

MyBaitsPlus配置

这里创建的两个包都与db包同级目录

config配置类

创建一个config包,新建一个MyBatisPlusConfig

@Configuration
public class MyBatisPlusConfig {

    /* 分页插件 */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 开启
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}

handler处理

新建一个 handler 包,包下新建一个 MyMetaObjectHandler 类,实现 MetaObjectHandler 类,改类有两个方法,一个insert…在向数据库插入数据的时候,会自动插入我们设置的值

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    /**
     * 新增数据执行
     * 
     * insert插入数据到数据库操作时执行
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        // 配置初始创建时间
        this.setFieldValByName("gmtCreate", new Date(), metaObject);
    }

    /**
     * 修改数据执行
     * 
     * update修改数据库数据操作时执行
     */
    @Override
    public void updateFill(MetaObject metaObject) {
    }
}

这里的 this.setFi… 第一个参数对应的是User实体类的名字,不是表中的字段名,第二个参数的默认值
在这里插入图片描述

Vo对象

新建一个 vo 包,用于和前端交互数据的类

统一结果返回类

vo 包下新建一个 R 类,作为我们统一返回给前端数据的类,

@Data
public class R {

    private Boolean success;

    private Integer code;

    private String message;

    private Map<String, Object> data = new HashMap<>();

    // 把构造方法私有化
    private R() {}

    // 成功静态方法
    public static R ok() {
        R r = new R();
        r.setSuccess(true);
        r.setCode(200);
        r.setMessage("成功");
        return r;
    }

    // 失败静态方法
    public static R error() {
        R r = new R();
        r.setSuccess(false);
        r.setCode(201);
        r.setMessage("失败");
        return r;
    }

    public R success(Boolean success){
        this.setSuccess(success);
        return this;
    }

    public R message(String message){
        this.setMessage(message);
        return this;
    }

    public R code(Integer code){
        this.setCode(code);
        return this;
    }

    public R data(String key, Object value){
        this.data.put(key, value);
        return this;
    }
}

vo 包下新建 QueryParam

@Data
public class QueryParam {

    // 用户名
    private String username;

    // 昵称
    private String nickname;

    // 号码
    private String phone;

    // 性别
    private String sex;

    // 创建时间
    private String time;
}

这里讲一下吧,这个类是用来干嘛的呢?我们在效果展示的时候,是不是在上面看到有5个筛选条件,这5个筛选条件参数刚好对应类中的5个属性,我们统一封装起来
在这里插入图片描述

service业务层

新建一个 service 包,包下新建一个 UserService 接口类,继承MyBatisPlus的 IService
在这里插入图片描述
service 包下新建 impl 包,新建一个 UserServiceImpl 实现类,继承MyBatisPlus的 ServiceImpl 类,实现我们自己的 UserService
在这里插入图片描述
我们先在 UserService 接口类定义五个方法,接下来我们一一实现这五个功能

public interface UserService extends IService<User> {

    /**
     * 添加用户
     * @param user
     * @return
     */
    R insertUser(User user);

    /**
     * 删除单个用户
     * @param id 用户编号
     * @return
     */
    R deleteUser(Integer id);

    /**
     * 删除多个用户
     * @param ids 用户编号集合
     * @return
     */
    R deleteUserMore(List<Integer> ids);

    /**
     * 编辑用户
     * @param user
     * @return
     */
    R modifyUser(User user);

    /**
     * 分页查询用户列表
     * @param index 当前页
     * @param size 每页显示数量
     * @param queryParam 筛选条件对象
     * @return
     */
    R findUserList(Integer index, Integer size, QueryParam queryParam);

	/**
     * 查询单个用户详细信息
     * @param id 用户编号
     * @return
     */
    R getUserInfoById(Integer id);
}

添加用户

UserServiceImpl 实现类里实现添加用户方法,这里只做了简单的非空判断,其他参数的非法性校验可以自己额外完善

@Override
public R insertUser(User user) {
	if (user == null) return R.error().message("参数错误");

    // 用户名
	String username = user.getUsername();

	// 构建条件对象, 查询是否已经存在用户名
	QueryWrapper<User> wrapper = new QueryWrapper<>();
	wrapper.select("id");
	wrapper.eq("username", username);
	wrapper.last("limit 1");

	// 查询判断, 如果查询出来有数据, 则不为null
	if (this.baseMapper.selectOne(wrapper) != null) R.error().message("该用户名已存在");

	// 执行插入数据操作
	return this.baseMapper.insert(user) == 0 ? R.error().message("添加用户失败") : R.ok();
}

删除用户

删除用户就比较简单啦,肯定有人会问,前端做了非空校验,后端怎么还要做参数校验校验呢?

其实前后端都做是最好的,有绕过前端发送请求的,就比如我们自己测试接口时用的postman, apifox,后端多做一层校验,避免直接操作数据库,我这里也是比较简单的做了校验

@Override
public R deleteUser(Integer id) {
	if (id == null || id <= 0) return R.error().message("参数错误");

	return  this.baseMapper.deleteById(id) == 0 ? R.error().message("删除失败") : R.ok();
}

一键删除多个用户

删除多个用户也没难度,将多个用户的编号放到一个集合中,一次删除多个

@Override
public R deleteUserMore(List<Integer> ids) {
	if (ids.size() == 0) return R.error().message("参数错误");

	return this.baseMapper.deleteBatchIds(ids) != ids.size() ? R.error().message("删除失败") : R.ok();
}

编辑用户

这个也没什么难度,做个简单校验,然后根据ID更新用户信息(参数其他合法性校验可以自己额外做哦)

@Override
    public R modifyUser(User user) {
        if (user == null || user.getId() == null || user.getId() <= 0) return R.error().message("参数错误");
        
        return this.baseMapper.updateById(user) == 0 ? R.error().message("编辑用户失败") : R.ok();
    }

获取单个用户信息

先实现这个吧,这个也很简单,直接通过用户编号查询用户的信息返回即可

@Override
public R getUserInfoById(Integer id) {
	if (id == null || id <= 0) return R.error().message("参数错误");
        
	return R.ok().data("userInfo", this.baseMapper.selectById(id));
}

查询用户列表

先创建编写SQL语句的文件,在 resources 下新建 mapper 包,包下新建 UserMapper.xml 文件在这里插入图片描述
代码中的SQL语句不能包含注释,所以我在图片给出了每行的注释,代码中删掉了,对应看着

<?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">
<!-- namespace路径根据自己而定 -->
<mapper namespace="com.xiaoyuan.usermanager.db.mapper.UserMapper">

    <!-- 查询用户列表(带多条件) -->
    <select id="findUserList" resultType="com.xiaoyuan.usermanager.db.entity.User">
        select *
        from user
        <where>
            1 = 1
            <if test="queryParam != null">
                <if test="queryParam.username != null and queryParam.username != ''">
                    and username = #{queryParam.username}
                </if>
                <if test="queryParam.nickname != null and queryParam.nickname != ''">
                    and nickname like CONCAT(#{queryParam.nickname}, '%')
                </if>
                <if test="queryParam.phone != null and queryParam.phone != ''">
                    and phone = #{queryParam.phone}
                </if>
                <if test="queryParam.sex != null and queryParam.sex != ''">
                    and sex = #{queryParam.sex}
                </if>
                <if test="queryParam.time != null and queryParam.time != ''">
                    and DATE_FORMAT(gmt_create,'%Y-%m-%d') = #{queryParam.time}
                </if>
            </if>
        </where>
    </select>
</mapper>

我们大致来分析一下上面的SQL语句,首先 select * from user这里没毛病吧,咋们是管理用户,所有信息都得要上,* 查询所有

后面 where 里有个 1 = 1 作用是恒等式,为了防止没有做筛选条件时,queryParam 条件对象为 null 导致 where 里面没东西,执行SQL语句的时候就会出现 where 后面没加东西,就会抛出异常

CONCAT 函数的作用是拼接,当然你直接用下面这样也行,推荐还是使用CONCAT,以后会遇到的,还有就是 % 只写右边就可以了,避免全表扫描,采用单模糊查询

and nickname like #{queryParam.nickname} '%'

DATE_FORMAT 函数作用是对时间进行格式化,2022-05-06 11:17:36 转换为 2022-05-06

SQL语句写好了,更新一下我们的 UserMapper 类,映射到 UserMapper.xml 文件的SQL语句,函数名就是 < select id=“xxxx”> 这里id的值

@Repository
public interface UserMapper extends BaseMapper<User> {

    /**
     * 查询用户列表
     * @param page 分页对象
     * @param queryParam 筛选条件
     * @return
     */
    IPage<User> findUserList(Page<User> page, QueryParam queryParam);
}

最后就是在 UserServiceImpl 实现查询用户列表的方法

@Override
public R findUserList(Integer index, Integer size, QueryParam queryParam) {
	if (index == null || size == null || index <= 0 || size <= 0) {
		return R.error().message("参数错误");
	}else if (size > 10) {
		return R.error().message("一次最多10条数据");
	}

	// 构建分页对象
	Page<User> page = new Page<>(index, size);
	// 查询
	IPage<User> iPage = this.baseMapper.findUserList(page, queryParam);

	// 回传两个数据, 一个 userList --> 用户数据列表, 一个 total -> 总页数
	return R.ok().data("userList", iPage.getRecords()).data("total", iPage.getTotal());
}

controller控制层

这里是最后一步了,处理接口,我们采用 RESTful 的风格,相同的路径处理不用的操作
在这里插入图片描述

@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController {

    @Autowired
    private UserService userService;

    // 添加用户
    @PostMapping("")
    public R insertUser(@RequestBody User user) {
        return userService.insertUser(user);
    }

    // 删除单个用户
    @DeleteMapping("{id}")
    public R deleteUser(@PathVariable(value = "id") Integer id) {
        return userService.deleteUser(id);
    }

    // 删除多个用户
    @DeleteMapping("")
    public R deleteUserMore(@RequestBody List<Integer> ids) {
        return userService.deleteUserMore(ids);
    }

    // 编辑用户
    @PutMapping("")
    public R modifyUser(@RequestBody User user) {
        return userService.modifyUser(user);
    }

    // 查询用户列表
    @PostMapping("{index}/{size}")
    public R findUserList(@PathVariable(value = "index") Integer index,
                          @PathVariable(value = "size") Integer size,
                          @RequestBody(required = false) QueryParam queryParam) {
        return userService.findUserList(index, size, queryParam);
    }

    // 根据用户编号查询用户信息
    @PostMapping("{id}")
    public R getUserInfo(@PathVariable(value = "id") Integer id) {
        return userService.getUserInfoById(id);
    }
}

接口测试

最后,在启动类加上两个注解,一个 MapperScan 扫描我们的 mapper 类,一个 ComponentScan 扫描我们的组件

@SpringBootApplication
@MapperScan(basePackages = {"com.xiaoyuan.usermanager.db.mapper"})
@ComponentScan({"com.xiaoyuan"})
public class UserManagerApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserManagerApplication.class, args);
    }
}

OK,到这里功能已经全部做好了,我们测试一下接口,运行启动类,我这里只展示部分接口的测试接口,全部接口我已经测试过,都没有问题了

大家可以自己去测试每个接口,我用的时 ApiFox 工具,非常好用,还能一键导出接口文档,可以显示接口耗时,分组分项目分接口分环境,非常的方便

添加用户,成功插入数据
在这里插入图片描述
当然,你可以在代码里面用测试,新建一个 SpringBoot 的测试类,测试业务层也可以的,如下
在这里插入图片描述
在这里插入图片描述
其他的就不一一放出来了,大伙自己去试试吧~

扩展(拦截器,权限拦截)

像管理这种一般都会有权限的,总不可能每个人都能访问自己的接口来增删改查用户吧?如何做到不给其他人访问自己的接口,判断别人是否有权限访问呢?

下面我们简单来设计一下,理解大概过程

首先,usermanager 主目录下创建两个包,一个 interceptor 拦截器,一个 WebMVCConfig MVC的配置类

interceptor 包下新建一个 PermissionInterceptor 类,实现 HandlerInterceptor

拦截器有三个阶段,preHandle -> postHandle -> afterCompletion,依次按顺序执行,只有前一个return返回true,才会执行下一个阶段方法,简单介绍三个阶段

  • preHandle:controller执行目标方法之前执行,一般用于权限验证等操作
  • postHandle:controller执行完目标方法返回(如调用service业务层的方法),在前端数据渲染之前执行,一般用于更改视图数据
  • afterCompletion:整个接口访问执行完毕,前端数据渲染完成,执行此方法,一般用于资源释放等操作

很明显,我们这个权限验证拦截就是在 preHandle 阶段去全性

这个 code 呢就是我们自己定义的权限码,我这里只是随便敲了长长的一段,反正自己知道就好,你可以做加密处理,这里我简单模拟一下

@Component
public class PermissionInterceptor implements HandlerInterceptor {

    private static final String code = "dwagfhwhgiawpfwabifpjwaidjwaidwiafihwigfhwaigwhaipgwaihiwahifhwdefef";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		// 放行OPTIONS请求
        if (HttpMethod.OPTIONS.matches(request.getMethod())) {
            return true;
        }

        // 获取请求头里面的 Authentication 属性值
        String authentication = request.getHeader("Authentication");
        // 两者相等 -> 通过放行, 两者不相等 -> 不通过不放行
        if (code.equals(authentication)) {
            // 放行
            return true;
        }else {
            // 不放行, 回传没有权限
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().println(JSON.toJSONString(R.error().message("没有操作权限")));
            return false;
        }
    }
}

config 包下新建一个 WebMVCConfig 类,实现 WebMvcConfigurer 类,设置拦截器

@Configuration
public class WebMVCConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new PermissionInterceptor()) // 添加拦截器
                .addPathPatterns("/user/**"); // 选择拦截路径,拦截/user下的所有请求
    }
}

好的,我们接下来看看效果,当然,就不适合在代码用SpringBoot测试类啦,因为校验请求头

我们采用接口测试工具,老样子,我使用的是ApiFox,你可以使用postman等其他工具

首先我们继续运行一下之前写好的请求路径(没加Authentication 权限码),可以看到,我们访问的是查询用户列表接口,显示没有权限
在这里插入图片描述
接下来我们在 header 请求头加上我们的 Authentication 的权限码,同样的路径,测试一下
在这里插入图片描述
是不是就成功访问到了
在这里插入图片描述
我们随便改错一个字母,也成功显示没有权限,除非你的权限码被别人知道了,或者被破解了(设置的复杂一点再加密基本不可能被破),不然你的接口别人访问不了
在这里插入图片描述

🌹 结束语

好了,整篇的教程呢到这也就结束,整篇教程即为原创一字一字手敲,也花了心思想怎么写怎么设计才能更好的直观简洁展示给大家,让大家能看懂

最后,关于教程还有什么不懂的可以评论区留言,我一定会回复的,或者有什么更好的建议和想法也可以在评论区留言,看到好的我会一一采纳,感谢大家的支持

再一次附上Gitee开源地址:https://gitee.com/yuandewei/Yuan-SpringBoot/tree/master 不用大伙翻上去复制了

  • 都看到这里啦,点点赞呀 😋
  • 感谢阅读 😘

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

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

相关文章

nuxt3:我们开始吧-开发-配置-部署

一、背景介绍 2022 年 11 月 16 日&#xff0c;全球最大的 Nuxt 会议 Nuxt Nation 2022 在线举行&#xff0c;并正式发布了 Nuxt.js 3.0 的第一个稳定版本。Nuxt 3 是基于 Vite、Vue3 和 Nitro 的 Nuxt 框架的现代重写&#xff0c;具有一流的 Typescript 支持&#xff0c;是两年…

前端基础从头学——VsCode使用教程+html基础(入门篇)

作者简介&#xff1a;hello&#xff01;大家好&#xff0c;初学前端知识&#xff0c;请多多指教。 希望我的分享能够帮助到更多的人&#xff0c;如果觉得我的分享有帮助的话&#xff0c;请大家一键三连支持一下哦~ 文章目录前言一、VsCode编辑器使用教程1、VsCode的下载与安装2…

HTML+CSS+JS+Jquery+练手项目+...合集(前端学习必备,持续更新中...)

非常实用的教程案例&#xff0c;均有详细的步骤讲解&#xff0c;不懂得可以私信博主&#xff0c;看到就会回的&#xff01;未来将继续更新Vue&#xff0c;React等更多前端知识&#xff0c;欢迎收藏关注&#xff01; 文章目录一、HTML二、CSS三、JavaScript四、jQuery五、 前端项…

PromiseA+规范之手写Promise

前言 1、Promise 的意义&#xff1f; 在javascript的世界中&#xff0c;所有代码都是单线程执行的&#xff0c;由于这个“缺陷”&#xff0c;导致JavaScript的所有网络操作&#xff0c;浏览器事件&#xff0c;都必须是异步执行。Ajax可以解决这个问题&#xff0c;但是并不好复用…

【flask进阶】Flask实现自定义分页(python web通用)

📋 个人简介 💖 作者简介:大家好,我是阿牛,全栈领域新星创作者。😜🎉 支持我:点赞👍+收藏⭐️+留言📝📣 系列专栏:flask框架快速入门🍁💬格言:要成为光,因为有怕黑的人!🔥 目录 📋 个人简介前言后端后端思路后端代码前端前端思路前端代码

微信小程序 - 完美解决 web-view 公众号文章或第三方网站分享转发后,打开提示 “无法打开该页面,不支持打开” 或 “页面不存在”(IOS 苹果系统打开是空白页,安卓系统会有提示)超详细排查

前言 由于出现这种问题的原因有很多种,绝对不像其他文章教程那样无效,本文提供了超级详细的排查思路与解决方案。 本文从 [初步排查] 到 [代码排查],完美解决 因各种原因导致 webview 页面分享后,用户打不开提示错误 这类问题, 您只需要按照排查步骤一步一步的走,从检查…

echarts入门教程(超级详细带案例)

一.echarts的介绍 1.echarts是一款基于JavaScript的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性化定制的数据可视化图表。ECharts最初由百度团队开源&#xff0c;并于2018年初捐赠给Apache基金会&#xff0c;成为ASF孵化级项目…

防抖、节流的介绍

目录 一、什么时候要用到防抖节流 输入框连续输入的案例 滚动条案例 二、什么是防抖、节流 使用防抖来解决输入框案例造成的浪费现象&#xff1a; 使用节流来解决滚动条案例造成的浪费现象&#xff1a; 三、总结 一、什么时候要用到防抖节流 针一类类快速连续触发和不可控…

不会前端没事,用GWT Boot和Spring Boot构建Web程序

本文介绍了一种使用Java构建Web应用程序的方式&#xff0c;其中GWT或者J2CL是必不可少的&#xff0c;另外还有多个UI框架可以配套使用&#xff0c;比如Domino UI、VueGWT、GWT Material Design (GMD)&#xff0c;React4J、WebFX&#xff0c;还有一些活跃低的框架GWTBootstrap3、…

2023前端面试题及答案整理(Vue)

watch 和 computed 区别 watch 是监听动作&#xff0c;computed 是计算属性watch 没缓存&#xff0c;只要数据变化就执行。computed 有缓存&#xff0c;只在属性变化的时候才去计算。watch 可以执行异步操作&#xff0c;而 computed 不能watch 常用于一个数据影响多个数据&…

Vue项目部署上线全过程(保姆级教程)

Vue项目部署上线全过程&#xff08;保姆级教程&#xff09; 上线前准备 1.先在vue.config.js文件中配置反向代理解决跨域请求问题 const { defineConfig } require(vue/cli-service) module.exports defineConfig({transpileDependencies: true,devServer: {proxy: {"…

web渗透测试学习路线

web渗透学习路线 文章目录*web渗透学习路线*前言一、web渗透测试是什么&#xff1f;二、web渗透步骤1.前期工作2.中期提高3.后期打牢总结前言 本文整理的学习路线&#xff0c;清晰明了&#xff0c;重点分明&#xff0c;能快速上手实践&#xff0c;相信想学的同学们都能轻松学完…

vue实现文件上传

这里使用的是vue2&#xff0c;ui用的是element ui &#xff0c;后期有时间会更新vue3版本的。前端文件上传使用的是ui框架中的Upload的图片列表缩略图&#xff0c;喜欢别的样式可以直接更改。看图注fileChange():方法可以直接获取到上传文件的状态及可以直接拿到图片的值可以新…

Redux中进行异步操作(网络请求)的方案

文章目录Redux中的异步操作组件中进行异步操作redux中进行异步操作Redux中的异步操作 在之前简单的案例中&#xff0c;redux中保存的counter是一个本地定义的数据 我们可以直接通过同步的操作来dispatch action&#xff0c;state就会被立即更新。 但是真实开发中&#xff0c;r…

Vue3 项目创建

安装 1、安装node vue 3需要node10以上版本 node官网下载地址以往的版本 | Node.js 2、安装vue/cli 如果已经全局安装过旧版本的vue-cli npm uninstall vue-cli -g //yarn global remove vue-cli 然后安装 npm install -g vue/cli //yarn global add vue/cli 为什…

使用vue,实现前端导入excel数据

文章目录 前言一、引入组件二、封装导入功能的组件 1.编写组件template2.获取数据3.调用接口把数据传给后端三、总结前言 继前边的vue的导出功能后&#xff0c;自己又去在网上搜了vue导入excel一些文章&#xff0c;自己通过对代码的整理和调整&#xff0c;实现了vue导入excel的…

Vue3报错:Property “xxx“ was accessed during render but is not defined on instance.

Vue3报错&#xff1a;Property “xxx” was accessed during render but is not defined on instance. 翻译&#xff1a;属性“xxx”在呈现期间被访问&#xff0c;但没有在实例上定义。 其实就是在模板上有&#xff0c;但是在script上没有定义 很多同学跟说这不是报错&#…

Vue2-基础知识

目录 一.vue简介 1.概念 2.特性 (1)数据驱动视图 (2)双向数据绑定 3.MVVM 4.基本使用步骤 5.调试工具 二.vue基础 1.指令 (1)内容渲染指令 (2)属性绑定指令 (3)事件绑定指令 (4)双向绑定指令 ​编辑(5)条件渲染指令 (6)列表渲染指令 2.过滤器 (1)概念 (2)分…

HTML5设计注册/登录界面

学习目标&#xff1a; 掌握 HTML5入门知识掌握 CSS入门知识学习内容&#xff1a; 掌握 HTML5基本语法掌握CSS基本语法HTML5网页设计掌握块级标签掌握行内标签表单的使用方法iput常用属性学习时间&#xff1a; 周一至周五早上 7 点—晚上9点周六上午 9 点-晚上9点周日下午 3 …

Redux的基本使用过程详解

文章目录Redux的使用过程Redux测试项目的搭建Redux的基本使用步骤Redux目录的结构划分React的三大原则Redux的使用过程 Redux测试项目的搭建 1.创建一个新的项目文件夹:learn-redux # 执行初始化操作 npm init -y或yarn init -y # 安装redux:npm install redux --save或yarn …