您的位置:首页 > 娱乐 > 明星 > web前端开发工程师是做什么的_西安做网站南通公司_宁波seo服务推广_优化关键词推广

web前端开发工程师是做什么的_西安做网站南通公司_宁波seo服务推广_优化关键词推广

2024/12/22 0:16:48 来源:https://blog.csdn.net/qq_40878316/article/details/144200894  浏览:    关键词:web前端开发工程师是做什么的_西安做网站南通公司_宁波seo服务推广_优化关键词推广
web前端开发工程师是做什么的_西安做网站南通公司_宁波seo服务推广_优化关键词推广

技术栈

前端技术说明
Vue前端框架
Vuex全局状态管理框架
ElementUI前端UI框架
Axios前端HTTP框架
vue-element-admin项目脚手架
后端技术说明
SpringBoot容器+MVC框架
MyBatisORM框架
MyBatis-plusMyBatis增强工具
Redis非关系型数据库

数据库准备

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu`  (`menu_id` int(11) NOT NULL AUTO_INCREMENT,`component` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`path` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`redirect` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`parent_id` int(11) NULL DEFAULT NULL,`is_leaf` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`hidden` tinyint(1) NULL DEFAULT NULL,PRIMARY KEY (`menu_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of sys_menu
-- ----------------------------
INSERT INTO `sys_menu` VALUES (1, 'Layout', '/user', '/user/list', 'userManage', '用户管理', 'userManage', 0, 'N', 0);
INSERT INTO `sys_menu` VALUES (2, 'user/user', 'list', NULL, 'userList', '用户列表', 'userList', 1, 'Y', 0);
INSERT INTO `sys_menu` VALUES (3, 'user/role', 'role', NULL, 'roleList', '角色列表', 'role', 1, 'Y', 0);
INSERT INTO `sys_menu` VALUES (4, 'user/permission', 'permission', NULL, 'permissionList', '权限列表', 'permission', 1, 'Y', 0);-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (`role_id` int(11) NOT NULL AUTO_INCREMENT,`role_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`role_desc` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,PRIMARY KEY (`role_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, 'admin', '超级管理员');
INSERT INTO `sys_role` VALUES (2, 'hr', '人事专员');
INSERT INTO `sys_role` VALUES (3, 'normal', '普通员工');-- ----------------------------
-- Table structure for sys_role_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu`  (`id` int(11) NOT NULL AUTO_INCREMENT,`role_id` int(11) NULL DEFAULT NULL,`menu_id` int(11) NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of sys_role_menu
-- ------------------------------ ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`phone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`status` int(1) NULL DEFAULT NULL,`avater` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`deleted` int(1) NULL DEFAULT 0,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, 'admin1', '$2a$10$QSDIu2LNrHsj.YqC2rrwEOtTCcoZWUphwRbwe0VIKVkJXaMD2Qo8y', '123456', '12345456', 1, '', 0);-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role`  (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) NULL DEFAULT NULL,`role_id` int(11) NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1, 1);SET FOREIGN_KEY_CHECKS = 1;

后端框架装备

1.项目框架搭建

创建springboot 2.6项目

在这里插入图片描述

编辑pom.xml文件导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.cyfy</groupId><artifactId>x-admin-serve</artifactId><version>0.0.1-SNAPSHOT</version><name>x-admin-serve</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.7.6</spring-boot.version></properties><dependencies><!-- web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mysql --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency><!--   mybatis-plus     --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.2</version></dependency><!-- freemarker --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- fastjson --><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.7</version></dependency><!--    密码加密工具    --><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-core</artifactId><version>3.1.0.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.cyfy.XAdminServeApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

编辑src/main/resources目录下的application.yml配置文件(没有就创建)

server:port:8080spring:datasource:username: rootpassword: 123456url: jdbc:mysql:///my_demoredis:port: 6379host: localhostlogging:level:com.cyfy: debug#  设置逻辑删除字段
mybatis-plus:global-config:db-config:logic-delete-field: deletedlogic-delete-value: 1logic-not-delete-value: 0

在这里插入图片描述

运行项目。查看是否可正常启动

在这里插入图片描述

2.代码生成器

在src/test/java目录下,创建CodeGenerator.java文件,编写引用mybatis-plus代码生成器生成代码

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;import java.util.Collections;public class CodeGenerator {public static void main(String[] args) {String url = "jdbc:mysql:///my_demo";   // 数据库链接地址String username = "root";               // 数据库用户名String password = "123456";             // 数据库密码String moduleName = "sys";              // 父包模块String project_abs_path = "E:\\项目\\神盾管理系统\\x-admin\\x-admin-serve\\src\\main\\";  // 项目绝对路径String mapperLocation = project_abs_path + "resources\\mapper\\" + moduleName;   // xxxMapper.xml文件输出地址String tables = "sys_user,sys_role,sys_menu,sys_user_role,sys_role_menu";     // 需要生成代码的表FastAutoGenerator.create(url, username, password).globalConfig(builder -> {builder.author("cyfy") // 设置作者// .enableSwagger() // 开启 swagger 模式.outputDir(project_abs_path + "java"); // 指定输出目录}).packageConfig(builder ->builder.parent("com.cyfy") // 设置父包名.moduleName(moduleName) // 设置父包模块名.pathInfo(Collections.singletonMap(OutputFile.xml, mapperLocation)) // 设置mapperXml生成路径).strategyConfig(builder ->builder.addInclude(tables) // 设置需要生成的表名.addTablePrefix("sys_") // 设置过滤表前缀).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();}
}

执行生成器代码后,项目新增对应代码文件

在这里插入图片描述

测试

编辑UserController.java文件,编写获取用户表数据接口

import com.cyfy.sys.entity.User;
import com.cyfy.sys.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate IUserService userService;@GetMapping("/all")public List<User> getAllUser(){List<User> list = userService.list();return list;}
}

修改项目启动器文件,增加@MapperScan注解

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.cyfy.*.mapper")
public class XAdminServeApplication {public static void main(String[] args) {SpringApplication.run(XAdminServeApplication.class, args);}
}

运行项目,访问接口是否正常

在这里插入图片描述

后端开发

1.公共响应类

在com/xxx目录下新建common/vo目录,并新建Result.java文件处理返回给前端的数据

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {private Integer code;private String message;private T data;public static<T> Result<T> success(){return new Result<>(20000,"success",null);}public static<T> Result<T> success(T data){return new Result<>(20000,"success",data);}public static<T> Result<T> success(T data, String Message){return new Result<>(20000,Message,data);}public static<T> Result<T> success( String Message){return new Result<>(20000,Message,null);}public static<T> Result<T> fail(){return new Result<>(20001,"fail",null);}public static<T> Result<T> fail(Integer code){return new Result<>(code,"success",null);}public static<T> Result<T> fail(Integer code, String Message){return new Result<>(code,Message,null);}public static<T> Result<T> fail( String Message){return new Result<>(20001,Message,null);}
}

测试:修改getAllUser()方法

    @GetMapping("/all")public Result<List<User>> getAllUser(){List<User> list = userService.list();return Result.success(list,"查询成功");}

运行效果

在这里插入图片描述

2.Redis配置

在common目录下新建tools目录,并新建MyRedisConfig.java文件

package com.cyfy.common.tools;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.TimeZone;@Configurable
public class MyRedisConfig {@Resourceprivate RedisConnectionFactory factory;@Beanpublic RedisTemplate redisTemplate(){RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(factory);// 设置键的序列化方法redisTemplate.setKeySerializer(new StringRedisSerializer());Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);// 设置字符串的序列化方法redisTemplate.setValueSerializer(serializer);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));om.setTimeZone(TimeZone.getDefault());om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);om.configure(MapperFeature.USE_ANNOTATIONS,false);om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);om.setSerializationInclusion(JsonInclude.Include.NON_NULL);serializer.setObjectMapper(om);return redisTemplate;}
}

3.跨域处理

在common/tools目录下,新建MyCorsConfig.java文件,用于处理跨域请求问题

package com.cyfy.common.tools;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;/*** 跨域请求处理*/
@Configuration
public class MyCorsConfig {@Beanpublic CorsFilter corsFilter(){// 1.添加CORS配置信息CorsConfiguration config = new CorsConfiguration();// 1.1. 允许的域,不要写*,否则cookie就无法使用config.addAllowedOrigin("http://localhost:8888"); // 这里填写请求的前端服务器// 1.2. 是否发送cookie信息config.setAllowCredentials(true);// 1.3. 允许的请求方式,常用方式有GET、POSTconfig.addAllowedMethod("OPTIONS");config.addAllowedMethod("HEAD");config.addAllowedMethod("GET");config.addAllowedMethod("PUT");config.addAllowedMethod("POST");config.addAllowedMethod("DELETE");config.addAllowedMethod("PATCH");// 1.4. 允许的头信息config.addAllowedHeader("*");// 2.添加映射路径,这里拦截一切请求UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();configSource.registerCorsConfiguration("/**",config);// 3.返回新的CorsFilterreturn new CorsFilter(configSource);}
}

也可在控制器类上加@CrossOrigin注解处理,减少配置类

4.mybatis-plus拦截器

在common/tools目录下,新建MpConfig.java文件

package com.cyfy.common.tools;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MpConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}

5.用户相关接口

编写UserController.java文件

package com.cyfy.sys.controller;import com.cyfy.common.vo.Result;
import com.cyfy.sys.entity.User;
import com.cyfy.sys.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Map;/***  前端控制器*/
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate IUserService userService;/*** 用户登录接口*/@PostMapping("/login")public Result<Map<String,Object>> login(@RequestBody User user){Map<String, Object> data = userService.login(user);if(data != null){return Result.success(data);}return Result.fail(20002,"用户名或密码错误");}/*** 用户信息查询接口*/@GetMapping("/info")public Result<Map<String,Object>> getUserInfo(@RequestParam("token") String token){Map<String,Object> data = userService.getUserInfo(token);if(data != null){return Result.success(data);}return Result.fail(20003,"登录信息已失效,请重新登录");}/*** 用户注销接口*/@PostMapping("/logout")public Result<?> logout(@RequestHeader("X-Token") String token){userService.logout(token);return Result.success();}/*** 获取用户列表接口*/@GetMapping("/list")public Result<Map<String,Object>> getUserList(@RequestParam(value = "username",required = false) String username,@RequestParam(value = "phone",required = false) String phone,@RequestParam(value = "pageNo") Long pageNo,@RequestParam(value = "pageSize") Long pageSize){Map<String, Object> data = userService.getUserList(username,phone,pageNo,pageSize);return Result.success(data);}@PostMapping("/add")public Result<?> addUser(@RequestBody User user){if(userService.addUser(user)) {return Result.success("新增用户成功");}return Result.fail("新增用户失败");}@PutMapping("/upd")public Result<?> updateUser(@RequestBody User user){if(userService.updateUser(user)) {return Result.success("修改用户成功");}return Result.fail("修改用户失败");}@GetMapping("/{id}")public Result<User> getUserById(@PathVariable("id")Integer id){User data = userService.getUserById(id);return Result.success(data);}@DeleteMapping("/{id}")public Result<User> deleteUserById(@PathVariable("id")Integer id){if(userService.deleteUserById(id)){return Result.success("删除用户成功");}return Result.fail("删除用户失败");}
}

编写IUserService.java文件

package com.cyfy.sys.service;import com.cyfy.sys.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;import java.util.Map;/***  服务类*/
public interface IUserService extends IService<User> {// 用户登录Map<String,Object> login(User user);// 根据token获取用户信息Map<String, Object> getUserInfo(String token);// 注销登录void logout(String token);// 获取用户列表Map<String, Object> getUserList(String username,String phone,Long pageNo,Long pageSize);// 添加用户boolean addUser(User user);// 修改用户boolean updateUser(User user);// 根据id查询用户User getUserById(Integer id);// 根据id删除指定用户boolean deleteUserById(Integer id);
}

编写UserServiceImpl.java文件

package com.cyfy.sys.service.impl;import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cyfy.sys.entity.User;
import com.cyfy.sys.mapper.UserMapper;
import com.cyfy.sys.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;/***  服务实现类*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@Resourceprivate RedisTemplate redisTemplate;@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic Map<String, Object> login(User user) {// 根据用户名查询LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getUsername,user.getUsername());// 根据username查询是否存在对应用户User loginUser = this.baseMapper.selectOne(wrapper);System.out.println(user.getPassword());System.out.println(loginUser.getPassword());// 结果不为空时,且加密密码正确:生成token,并将用户信息存入redisif(loginUser != null && passwordEncoder.matches(user.getPassword(),loginUser.getPassword())){// 这里暂时使用UUID,最终需要使用jwtString key = "user" + UUID.randomUUID();loginUser.setPassword(null);    // 将密码设置为空,不存入redis// 存入redisredisTemplate.opsForValue().set(key,loginUser,30, TimeUnit.MINUTES);// 返回处理好的tokenMap<String,Object> data = new HashMap<>();data.put("token",key);return data;}return null;}@Overridepublic Map<String, Object> getUserInfo(String token) {// 根据Token从Redis中获取用户信息Object obj = redisTemplate.opsForValue().get(token);if(obj != null){// 将字符串转为User对象User loginUser = JSON.parseObject(JSON.toJSONString(obj),User.class);Map<String,Object> data = new HashMap<>();data.put("name",loginUser.getUsername());data.put("avatar",loginUser.getAvater());// 通过ID查询用户角色List<String> roleList = this.baseMapper.getRoleNameByUserId(loginUser.getId());data.put("roles",roleList);return data;}return null;}@Overridepublic void logout(String token) {// 从redis中清除指定tokenredisTemplate.delete(token);}@Overridepublic Map<String, Object> getUserList(String username,String phone,Long pageNo,Long pageSize) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(StringUtils.hasLength(username),User::getUsername,username);wrapper.eq(StringUtils.hasLength(phone),User::getPhone,phone);// 分页处理Page<User> page = new Page<>(pageNo,pageSize);this.page(page,wrapper);Map<String,Object> data = new HashMap<>();data.put("total",page.getTotal());data.put("row",page.getRecords());return data;}@Overridepublic boolean addUser(User user) {// 根据用户名查询LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getUsername,user.getUsername());// 根据username查询是否存在对应用户User loginUser = this.baseMapper.selectOne(wrapper);// 如果用户名存在,返回falseif(loginUser != null){return false;}//  加密密码user.setPassword(passwordEncoder.encode(user.getPassword()));return this.save(user);}@Overridepublic boolean updateUser(User user) {//  加密密码user.setPassword(null);return this.updateById(user);}@Overridepublic User getUserById(Integer id) {User user = this.getById(id);user.setPassword(null);return user;}@Overridepublic boolean deleteUserById(Integer id) {// 先查询用户是否存在if(this.getById(id) != null){return this.removeById(id);}return false;}
}

编写UserMapper.java文件

package com.cyfy.sys.mapper;import com.cyfy.sys.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;import java.util.List;/***  Mapper 接口*/
public interface UserMapper extends BaseMapper<User> {List<String> getRoleNameByUserId(Integer id);
}

编写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.cyfy.sys.mapper.UserMapper"><select id="getRoleNameByUserId" parameterType="Integer" resultType="String">SELECTb.`role_name`FROM  sys_user_role a, sys_role bWHEREa.role_id = b.`role_id` AND a.user_id = #{userId}</select>
</mapper>

修改XAdminServeApplication.java文件,加个加密方法

package com.cyfy;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;@SpringBootApplication
@MapperScan("com.cyfy.*.mapper")
public class XAdminServeApplication {public static void main(String[] args) {SpringApplication.run(XAdminServeApplication.class, args);}@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}
}

使用Postman测试接口(记得开启redis

在这里插入图片描述

前端框架准备

1.脚手架搭建

详见【Vue】vue-admin-template项目搭建,需保持node版本一致,可以使用nvm进行版本管理

2.使用VS Code打开项目

在这里插入图片描述

安装依赖:npm install --no-fund

在这里插入图片描述

运行项目:npm run dev

在这里插入图片描述

在这里插入图片描述

3.修改后端请求接口

修改.env.development文件

# just a flag
ENV = 'development'# base api
VUE_APP_BASE_API = 'http://localhost:8080'

修改vue.config.js文件,注释使用模拟数据

// before: require('./mock/mock-server.js')  // 模拟数据

测试:修改src/api/user.js文件,更正请求url

import request from '@/utils/request'export function login(data) {return request({url: '/user/login',method: 'post',data})
}export function getInfo(token) {return request({url: '/user/info',method: 'get',params: { token }})
}export function logout() {return request({url: '/user/logout',method: 'post'})
}

运行效果:可通过数据库的账号登录

在这里插入图片描述

前端开发

1.登录页修改

修改src/views/login目录下的index.vue文件(没啥修改内容,就是将英文内容改为中文,稍微调整一下布局)

<template><div class="login-container"><el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left"><div class="title-container"><h3 class="title">欢迎登录神盾局管理系统</h3></div><el-form-item prop="username"><span class="svg-container"><svg-icon icon-class="user" /></span><el-inputref="username"v-model="loginForm.username"placeholder="用户名"name="username"type="text"tabindex="1"auto-complete="on"/></el-form-item><el-form-item prop="password"><span class="svg-container"><svg-icon icon-class="password" /></span><el-input:key="passwordType"ref="password"v-model="loginForm.password":type="passwordType"placeholder="密码"name="password"tabindex="2"auto-complete="on"@keyup.enter.native="handleLogin"/><span class="show-pwd" @click="showPwd"><svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" /></span></el-form-item><el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">登录</el-button></el-form></div>
</template><script>
import { validUsername } from '@/utils/validate'export default {name: 'Login',data() {const validateUsername = (rule, value, callback) => {if (!validUsername(value)) {callback(new Error('请输入正确的用户名'))} else {callback()}}const validatePassword = (rule, value, callback) => {if (value.length < 6) {callback(new Error('密码不能少于6位'))} else {callback()}}return {loginForm: {username: '',password: ''},loginRules: {username: [{ required: true, trigger: 'blur', validator: validateUsername }],password: [{ required: true, trigger: 'blur', validator: validatePassword }]},loading: false,passwordType: 'password',redirect: undefined}},watch: {$route: {handler: function(route) {this.redirect = route.query && route.query.redirect},immediate: true}},methods: {showPwd() {if (this.passwordType === 'password') {this.passwordType = ''} else {this.passwordType = 'password'}this.$nextTick(() => {this.$refs.password.focus()})},handleLogin() {this.$refs.loginForm.validate(valid => {if (valid) {this.loading = truethis.$store.dispatch('user/login', this.loginForm).then(() => {this.$router.push({ path: this.redirect || '/' })this.loading = false}).catch(() => {this.loading = false})} else {console.log('error submit!!')return false}})}}
}
</script><style lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */$bg:#283443;
$light_gray:#fff;
$cursor: #fff;@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {.login-container .el-input input {color: $cursor;}
}/* reset element-ui css */
.login-container {.el-input {display: inline-block;height: 47px;width: 85%;input {background: transparent;border: 0px;-webkit-appearance: none;border-radius: 0px;padding: 12px 5px 12px 15px;color: $light_gray;height: 47px;caret-color: $cursor;&:-webkit-autofill {box-shadow: 0 0 0px 1000px $bg inset !important;-webkit-text-fill-color: $cursor !important;}}}.el-form-item {border: 1px solid rgba(255, 255, 255, 0.1);background: rgba(0, 0, 0, 0.1);border-radius: 5px;color: #454545;}
}
</style><style lang="scss" scoped>
$bg:#2d3a4b;
$dark_gray:#889aa4;
$light_gray:#eee;.login-container {min-height: 100%;width: 100%;background-color: $bg;overflow: hidden;display: flex;                    // 布局类型:弹性布局align-items: center;              // 调整元素在侧轴的对齐方式:居中.login-form {position: relative;width: 520px;max-width: 100%;padding: 35px 50px 20px;        // 内边距:上 中 下margin: 0 auto;                 // 外边距overflow: hidden;background-color: #283443;  // 设置背景色border-radius: 8px;             // 设置边框圆角opacity: 0.9;                   // 设置透明度}.tips {font-size: 14px;color: #fff;margin-bottom: 10px;span {&:first-of-type {margin-right: 16px;}}}.svg-container {padding: 6px 5px 6px 15px;color: $dark_gray;vertical-align: middle;width: 30px;display: inline-block;}.title-container {position: relative;.title {font-size: 26px;color: $light_gray;margin: 0px auto 40px auto;text-align: center;font-weight: bold;}}.show-pwd {position: absolute;right: 10px;top: 7px;font-size: 16px;color: $dark_gray;cursor: pointer;user-select: none;}
}
</style>

运行效果

在这里插入图片描述

2.菜单初始化

在src/views目录下创建sys模块目录、test模块目录(充数,暂不实现)

在sys模块目录下创建user/index.vuerole/index.vue两个组件文件,test模块目录下创建test1.vuetest2.vuetest3.vue

在这里插入图片描述

修改src/router/index.js文件,修改路由配置

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '@/layout'export const constantRoutes = [{path: '/login',component: () => import('@/views/login/index'),hidden: true},{path: '/404',component: () => import('@/views/404'),hidden: true},{path: '/',component: Layout,redirect: '/dashboard',children: [{path: 'dashboard',name: 'Dashboard',component: () => import('@/views/dashboard/index'),meta: { title: '首页', icon: 'dashboard' }}]},{path: '/sys',component: Layout,redirect: '/sys/user',name: 'sysMange',meta: { title: '系统管理', icon: 'el-icon-s-help' },children: [{path: 'user',name: 'User',component: () => import('@/views/sys/user/index'),meta: { title: '用户管理', icon: 'table' }},{path: 'role',name: 'Role',component: () => import('@/views/sys/role/index'),meta: { title: '角色管理', icon: 'tree' }}]},{path: '/test',component: Layout,redirect: '/test/test1',name: 'test',meta: { title: '测试模块', icon: 'form' },children: [{path: 'test1',name: 'Test1',component: () => import('@/views/test/test1'),meta: { title: '功能点一', icon: 'form' }},{path: 'test2',name: 'Test2',component: () => import('@/views/test/test2'),meta: { title: '功能点二', icon: 'form' }},{path: 'test3',name: 'Test3',component: () => import('@/views/test/test3'),meta: { title: '功能点三', icon: 'form' }},]},// 404 page must be placed at the end !!!{ path: '*', redirect: '/404', hidden: true }
]const createRouter = () => new Router({// mode: 'history', // require service supportscrollBehavior: () => ({ y: 0 }),routes: constantRoutes
})const router = createRouter()// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {const newRouter = createRouter()router.matcher = newRouter.matcher // reset router
}export default router

运行效果

在这里插入图片描述

3.标签栏导航

3.1.复制对应文件到对应目录

@/layout/components/TagsView

@/store/modules/tagsView.js

@/store/modules/permission.js

3.2.修改@/layoutcomponents/AppMain.vue文件

<template><section class="app-main"><transition name="fade-transform" mode="out-in"><!-- 加入标签栏组件  --><keep-alive :include="cachedViews"><router-view :key="key" /></keep-alive></transition></section>
</template><script>
export default {name: 'AppMain',computed: {key() {return this.$route.path},cachedViews(){return this.$store.state.tagsView.cachedViews}}
}
</script>

3.3.修改@store/getters.js文件

const getters = {sidebar: state => state.app.sidebar,device: state => state.app.device,token: state => state.user.token,avatar: state => state.user.avatar,name: state => state.user.name,visitedViews: state => state.tagsView.visitedViews,cachedViews: state => state.tagsView.cachedViews,permission_routes: state => state.permission.routes,
}export default getters

3.4.修改@layout/components/index.js文件

export { default as Navbar } from './Navbar'
export { default as Sidebar } from './Sidebar'
export { default as AppMain } from './AppMain'
export { default as TagsView } from './TagsView/index.vue'

3.5.修改@store/index.js文件

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import app from './modules/app'
import settings from './modules/settings'
import user from './modules/user'
import tagsView from './modules/tagsView'
import permission from './modules/permission'Vue.use(Vuex)const store = new Vuex.Store({modules: {app,settings,user,tagsView,permission},getters
})export default store

3.6.Affix固钉

修改@/router/index.js文件,在需要固定的标签页中添加affix: true属性

  {path: '/',component: Layout,redirect: '/dashboard',children: [{path: 'dashboard',name: 'Dashboard',component: () => import('@/views/dashboard/index'),meta: { title: '首页', icon: 'dashboard' ,affix: true }}]},

运行效果

在这里插入图片描述

4.用户管理页实现

编写views/sys/user/index.vue文件

<template><div><!-- 搜索栏 --><el-card class="search"><el-row><el-col :span="20"><el-input v-model="searchModel.username" placeholder="用户名" clearable /><el-input v-model="searchModel.phone" placeholder="电话" clearable /><el-button @click="getUserList" type="primary" round icon="el-icon-search">查询</el-button></el-col><el-col :span="4" align="right"><el-button @click="openUserVisible(null)" type="primary" icon="el-icon-plus" circle></el-button></el-col></el-row></el-card><!-- 结果列表 --><el-card><el-table :data="userList" stripe style="width:100%"><el-table-column label="#" width="80"><template slot-scope="scope">{{ (searchModel.pageNo - 1) * searchModel.pageSize + scope.$index + 1 }}</template></el-table-column><el-table-column prop="id" label="用户ID" width="80" /><el-table-column prop="username" label="用户名" width="180" /><el-table-column prop="phone" label="电话" width="180" /><el-table-column prop="status" label="状态" width="180" ><template slot-scope="scope"><el-tag v-if="scope.row.status === 1">正常</el-tag><el-tag v-else type="danger">禁用</el-tag></template></el-table-column><el-table-column prop="email" label="电子邮件" /><el-table-column label="操作" width="180"><template slot-scope="scope"><el-button @click="openUserVisible(scope.row.id)" type="primary" icon="el-icon-edit" size="mini" circle /><el-button @click="deleteUser(scope.row)" type="danger" icon="el-icon-delete" size="mini" circle /></template></el-table-column></el-table></el-card><!-- 分页组件 --><el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange":current-page="searchModel.pageNo" :page-sizes="[5, 10, 20, 50]" :page-size="searchModel.pageSize"layout="total, sizes, prev, pager, next, jumper" :total="total"></el-pagination><!-- 用户信息编辑对话框 --><el-dialog @close="clearUserForm" :title="title" :visible.sync="userFormVisible"><el-form :model="userForm" ref="userForm" :rules="rules"><el-form-item label="用户名" prop="username" :label-width="formLabelWidth"><el-input v-model="userForm.username" autocomplete="off"></el-input></el-form-item><el-form-item v-if="userForm.id == null || userForm.id === undefined" label="登录密码" prop="password" :label-width="formLabelWidth"><el-input type="password" v-model="userForm.password" autocomplete="off"></el-input></el-form-item><el-form-item label="联系电话" :label-width="formLabelWidth"><el-input v-model="userForm.phone" autocomplete="off"></el-input></el-form-item><el-form-item label="状态" :label-width="formLabelWidth"><el-switchv-model="userForm.status":active-value="1":inactive-value="0"></el-switch></el-form-item><el-form-item label="电子邮件" prop="email" :label-width="formLabelWidth"><el-input v-model="userForm.email" autocomplete="off"></el-input></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="userFormVisible = false">取 消</el-button><el-button type="primary" @click="saveUserFrom">确 定</el-button></div></el-dialog></div>
</template><script>
import userApi from '@/api/userManage'
export default {components: {},data() {// 自定义验证规则var checkEmail = (rule, value, callback)=>{var reg = /^[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*@[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*\.[a-z]{2,}$/if(!reg.test(value)){return callback(new Error('电子邮箱格式错误'));}callback();}return {total: 0,searchModel: {username: "",phone: "",pageNo: 1,pageSize: 10,},userList: [],title:"",userFormVisible: false,userForm:{},formLabelWidth: '130px',rules:{username:[{required:true, message: '请输入用户名', trigger: 'blur'},{min:5,max: 12, message: '长度在5到12个字符', trigger: 'blur'},],password:[{required:true, message: '请输入初始登录密码', trigger: 'blur'},{min:6,max: 16, message: '长度在6到16个字符', trigger: 'blur'},],email:[{required:true, message: '请输入电子邮箱', trigger: 'blur'},{validator:checkEmail, trigger: 'blur'},],}}},methods: {// 删除用户deleteUser(user){this.$confirm(`你确认删除用户${user.username}?`, '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {userApi.deleteUserById(user.id).then(response => {this.$message({type: 'success',message: response.message});this.getUserList();})}).catch(() => {this.$message({type: 'info',message: '已取消删除'});          });},// 添加用户saveUserFrom(){// 触发表单验证this.$refs.userForm.validate((valid)=>{if(valid){// 提交请求给后台userApi.saveUser(this.userForm).then(response =>{// 成功提示this.$message({message: response.message,type: 'success'});// 关闭对话框this.userFormVisible = false;// 刷新表格this.getUserList();})}else{this.$message({message: "数据提交错误",type: 'error'});return false;}})},handleSizeChange(pageSize) {this.searchModel.pageSize = pageSize;this.getUserList();},handleCurrentChange(pageNo) {this.searchModel.pageSize = pageNo;this.getUserList();},getUserList() {userApi.getUserList(this.searchModel).then(response => {this.userList = response.data.row;this.total = response.data.total;});},openUserVisible(id) {if(id === null){this.title = "新增用户";}else{this.title = "修改用户";// 根据id查询用户userApi.getUserById(id).then(response =>{this.userForm = response.data})}this.userFormVisible = true;},clearUserForm(){this.userForm = {}this.$refs.userForm.clearValidate();}},created() {this.getUserList();}
}
</script><style scoped>
.search .el-input {width: 200px;margin-right: 10px;
}
.el-dialog .el-input{width: 85%;
}
</style>

在src/api目录下新建userManage.js文件

import request from '@/utils/request'export default{getUserList(searchModel){return request({url: '/user/list',method: 'get',params :{pageNo: searchModel.pageNo,pageSize: searchModel.pageSize,username: searchModel.username,phone: searchModel.phone,}})},addUser(user){return request({url: '/user/add',method: 'post',data:user})},saveUser(user){if(user.id === null || user.id === undefined){return this.addUser(user)}else{return this.updateUser(user);}},updateUser(user){return request({url: '/user/upd',method: 'put',data: user})},getUserById(id){return request({url: `/user/${id}`,method: 'get'})},deleteUserById(id){return request({url: `/user/${id}`,method: 'delete'})},
}

5.用户管理页组件优化

当前页面所有内容都集中在index.vue中,代码多看起码繁杂,不适合后续拓展及优化,所有需内容按模块拆分成组件文件

在src/utils目录下新建eventbus.js文件,实现组件之间数据交互的方法

import Vue from "vue"
const EventBus = new Vue();
Object.defineProperties(Vue.prototype,{$bus:{get(){return EventBus;}}
})

main.js文件中引入eventbus

// 引入eventbus
import "./utils/eventbus"

在src/views/sys/user目录下新建components目录,用于存放当前页面的组件文件

新建SearchBar.vue文件,用于存放搜索框部分

<template><!-- 搜索栏 --><el-card class="search"><el-row><el-col :span="20"><el-input v-model="searchContext.username" placeholder="用户名" clearable /><el-input v-model="searchContext.phone" placeholder="电话" clearable /><el-button @click="searchUser" type="primary" round icon="el-icon-search">查询</el-button></el-col><el-col :span="4" align="right"><el-button @click="openUserVisible" type="primary" icon="el-icon-plus" circle></el-button></el-col></el-row></el-card>
</template><script>
export default {data(){return {searchContext: {username: "",phone: "",},}},methods:{searchUser(){this.$bus.$emit("searchUser",this.searchContext)},openUserVisible(){this.$bus.$emit("openUserVisible",null)}}
}
</script><style scoped>
.search .el-input {width: 200px;margin-right: 10px;
}
</style>

新建ResultList.vue文件,用于存放结果展示部分

<template><!-- 结果列表 --><el-card><el-table :data="userList" stripe style="width:100%"><el-table-column label="#" width="80"><template slot-scope="scope">{{ (searchModel.pageNo - 1) * searchModel.pageSize + scope.$index + 1 }}</template></el-table-column><el-table-column prop="id" label="用户ID" width="80" /><el-table-column prop="username" label="用户名" width="180" /><el-table-column prop="phone" label="电话" width="180" /><el-table-column prop="status" label="状态" width="180"><template slot-scope="scope"><el-tag v-if="scope.row.status === 1">正常</el-tag><el-tag v-else type="danger">禁用</el-tag></template></el-table-column><el-table-column prop="email" label="电子邮件" /><el-table-column label="操作" width="180"><template slot-scope="scope"><el-button @click="openUserVisible(scope.row.id)" type="primary" icon="el-icon-edit" size="mini" circle /><el-button @click="deleteUser(scope.row)" type="danger" icon="el-icon-delete" size="mini" circle /></template></el-table-column></el-table></el-card>
</template><script>
import userApi from '@/api/userManage'
export default {data() {return {userList: [],searchModel: {pageNo: 1,pageSize: 10,},}},methods: {// 删除用户deleteUser(user) {this.$confirm(`你确认删除用户${user.username}?`, '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {userApi.deleteUserById(user.id).then(response => {this.$message({type: 'success',message: response.message});this.getUserList();})}).catch(() => {this.$message({type: 'info',message: '已取消删除'});});},// 获取数据getUserList() {userApi.getUserList(this.searchModel).then(response => {this.userList = response.data.row;this.$bus.$emit("getTotal",response.data.total)});},// 修改用户openUserVisible(id){console.log(1111111111111);this.$bus.$emit("openUserVisible",id)}},mounted(){// 查询数据this.$bus.$on("searchUser",searchContext =>{this.searchModel.username = searchContext.username;this.searchModel.phone = searchContext.phone;this.getUserList();})// 更新页面this.$bus.$on("refresh",() =>{this.getUserList();})// 分页this.$bus.$on("page_turning",searchModel =>{this.searchModel.pageNo = searchModel.pageNo;this.searchModel.pageSize = searchModel.pageSize;this.getUserList();})},created() {this.getUserList();}
}
</script>

新建ResultPage.vue文件,用于存放分页部分

<template><!-- 分页组件 --><el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange":current-page="searchModel.pageNo" :page-sizes="[5, 10, 20, 50]" :page-size="searchModel.pageSize"layout="total, sizes, prev, pager, next, jumper" :total="total"></el-pagination>
</template><script>
export default {data() {return {total: 0,searchModel: {pageNo: 1,pageSize: 10,}}},methods: {handleSizeChange(pageSize) {this.searchModel.pageSize = pageSize;this.$bus.$emit("page_turning",this.searchModel)},handleCurrentChange(pageNo) {this.searchModel.pageNo = pageNo;this.$bus.$emit("page_turning",this.searchModel)},},mounted(){this.$bus.$on("getTotal",total =>{this.total = total})}
}
</script>

新建UserDialog.vue文件,用于存放用户信息编辑对话框部分

<template><div><!-- 用户信息编辑对话框 --><el-dialog @close="clearUserForm" :title="title" :visible.sync="userFormVisible"><el-form :model="userForm" ref="userForm" :rules="rules"><el-form-item label="用户名" prop="username" :label-width="formLabelWidth"><el-input v-model="userForm.username" autocomplete="off"></el-input></el-form-item><el-form-item v-if="userForm.id == null || userForm.id === undefined" label="登录密码" prop="password":label-width="formLabelWidth"><el-input type="password" v-model="userForm.password" autocomplete="off"></el-input></el-form-item><el-form-item label="联系电话" :label-width="formLabelWidth"><el-input v-model="userForm.phone" autocomplete="off"></el-input></el-form-item><el-form-item label="状态" :label-width="formLabelWidth"><el-switch v-model="userForm.status" :active-value="1" :inactive-value="0"></el-switch></el-form-item><el-form-item label="电子邮件" prop="email" :label-width="formLabelWidth"><el-input v-model="userForm.email" autocomplete="off"></el-input></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="userFormVisible = false">取 消</el-button><el-button type="primary" @click="saveUserFrom">确 定</el-button></div></el-dialog></div>
</template><script>
import userApi from '@/api/userManage'
export default {data() {// 自定义验证规则var checkEmail = (rule, value, callback) => {var reg = /^[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*@[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*\.[a-z]{2,}$/if (!reg.test(value)) {return callback(new Error('电子邮箱格式错误'));}callback();}return {title: "",userFormVisible: false,userForm: {},formLabelWidth: '130px',rules: {username: [{ required: true, message: '请输入用户名', trigger: 'blur' },{ min: 5, max: 12, message: '长度在5到12个字符', trigger: 'blur' },],password: [{ required: true, message: '请输入初始登录密码', trigger: 'blur' },{ min: 6, max: 16, message: '长度在6到16个字符', trigger: 'blur' },],email: [{ required: true, message: '请输入电子邮箱', trigger: 'blur' },{ validator: checkEmail, trigger: 'blur' },],}}},methods: {// 添加或修改用户saveUserFrom() {// 触发表单验证this.$refs.userForm.validate((valid) => {if (valid) {// 提交请求给后台userApi.saveUser(this.userForm).then(response => {// 成功提示this.$message({message: response.message,type: 'success'});// 关闭对话框this.userFormVisible = false;// 刷新表格this.$bus.$emit("refresh")})} else {this.$message({message: "数据提交错误",type: 'error'});return false;}})},// 根据是否存在id显示弹出信息openUserVisible(id) {if (id === null) {this.title = "新增用户";} else {this.title = "修改用户";// 根据id查询用户userApi.getUserById(id).then(response => {this.userForm = response.data})}this.userFormVisible = true;},// 清除弹窗内容clearUserForm() {this.userForm = {}this.$refs.userForm.clearValidate();}},mounted(){this.$bus.$on("openUserVisible",id =>{console.log(22222222);this.openUserVisible(id)})}
}
</script><style scoped>
.el-dialog .el-input{width: 85%;
}
</style>

修改user/index.vue文件

<template><div><SearchBar/><ResultList/><ResultPage/><UserDialog/></div>
</template><script>
import SearchBar from './components/SearchBar'
import ResultList from './components/ResultList'
import ResultPage from './components/ResultPage'
import UserDialog from './components/UserDialog'
export default {components: {SearchBar,ResultList,ResultPage,UserDialog}
}
</script>

运行效果正常

在这里插入图片描述

报错处理

1.使用TagsView组件控制台报错

报错截图

在这里插入图片描述

报错原因

未将TagsView所依赖的组件permission组件注册到store中,导致TagsView组件在找permission.routes时没找到

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com