Vue实战之使用Vue CLI 脚手架开发前后端分离项目之员工列表实现

文章目录

      • 案例演示
      • 创建数据库
      • 创建后端项目
        • pom.xml 文件中引入依赖坐标
        • application.properties
        • 实现用户登录、用户退出登录功能
        • 使用 Vue Cli 创建前端项目
        • 实现员工列表(增删改查)功能
        • vue cli 公共组件的提取
      • 代码仓库


案例演示

Vue实战之使用Vue CLI 脚手架开发前后端分离项目之员工列表实现_第1张图片

创建数据库

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50731
 Source Host           : localhost:3306
 Source Schema         : helloworld

 Target Server Type    : MySQL
 Target Server Version : 50731
 File Encoding         : 65001

 Date: 12/08/2021 05:51:29
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for admin
-- ----------------------------
DROP TABLE IF EXISTS `admin`;
CREATE TABLE `admin`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of admin
-- ----------------------------
INSERT INTO `admin` VALUES (1, 'zhangsan', '123456');
INSERT INTO `admin` VALUES (2, 'xiaozhu', '123');

-- ----------------------------
-- Table structure for emp
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(11) NULL DEFAULT NULL,
  `salary` double(10, 2) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES (1, '小张1', 23, 23000.00);
INSERT INTO `emp` VALUES (2, '小李2', 24, 2400.00);
INSERT INTO `emp` VALUES (3, '小白', 25, 2500.00);
INSERT INTO `emp` VALUES (4, '小王', 25, 1500.00);
INSERT INTO `emp` VALUES (5, '小红红', 24, 1500.00);
INSERT INTO `emp` VALUES (6, '小四', 25, 1500.00);

SET FOREIGN_KEY_CHECKS = 1;

创建后端项目

pom.xml 文件中引入依赖坐标

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>com.baizhigroupId>
    <artifactId>helloworld_backartifactId>
    <version>1.0-SNAPSHOTversion>

    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.2.5.RELEASEversion>
        <relativePath/> 
    parent>

    <properties>
        <java.version>1.8java.version>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>

        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.2.5version>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.38version>
        dependency>
        
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>2.1.4version>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>

    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

project>
application.properties
server.port=8989

#配置mybatis相关
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/helloworld?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root

mybatis.type-aliases-package=com.baizhi.entity
mybatis.mapper-locations=classpath:com/baizhi/mapper/*.xml

#配置redis
spring.redis.host=127.0.0.1
spring.rabbitmq.host=6379

logging.level.com.baizhi.dao=debug
实现用户登录、用户退出登录功能
  • com.baizhi.constants.RedisPrefix(常量)
public interface RedisPrefix {
    String TOKEN = "TOKEN_";
}
  • com.baizhi.controller.AdminController(完成用户登录、退出登录功能)
@RestController
@CrossOrigin //允许跨域
public class AdminController {
    private static final Logger log = LoggerFactory.getLogger(AdminController.class);
    /**
     * 服务对象
     */
    @Resource
    private AdminService adminService;

    @Autowired
    private RedisTemplate redisTemplate;

    //退出用户登录
    @DeleteMapping("/token")
    public void token(String token) {
        redisTemplate.delete(RedisPrefix.TOKEN + token);
    }

    //已登录用户信息(获取token信息)
    @GetMapping("/token")
    public Admin admin(String token) {
        log.info("接收token信息:{} ", token);
        return (Admin) redisTemplate.opsForValue().get(RedisPrefix.TOKEN + token);
    }

    //用户登录
    @PostMapping("login")
    public Map<String, Object> login(@RequestBody Admin admin, HttpSession session) {
        Map<String, Object> result = new HashMap<>();
        log.info("admin username:{} password:{}", admin.getUsername(), admin.getPassword());
        try {
            //登录成功
            Admin adminDB = adminService.login(admin);
            //生成token信息
            String token = session.getId();
            //放入redis
            redisTemplate.opsForValue().set(RedisPrefix.TOKEN + token, adminDB, 30, TimeUnit.MINUTES);
            result.put("success", true);
            result.put("token", token);
        } catch (Exception e) {
            e.printStackTrace();
            result.put("success", false);
            result.put("msg", e.getMessage());
        }
        return result;
    }

    /**
     * 通过主键查询单条数据
     */
    @GetMapping("/admin")
    public Admin admin(Integer id) {
        return this.adminService.queryById(id);
    }
}
  • com.baizhi.service.AdminService
public interface AdminService {

	// ... ...
	
    //管理员登录
    Admin login(Admin admin);
}
  • com.baizhi.service.impl.AdminServiceImpl
@Service("adminService")
@Transactional
public class AdminServiceImpl implements AdminService {
    @Resource
    private AdminDao adminDao;

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public Admin login(Admin admin) {
        Admin adminDB = adminDao.findByUserName(admin.getUsername());
        if (adminDB == null) {
            throw new RuntimeException("用户名输入错误!!");
        }
        if (!adminDB.getPassword().equals(admin.getPassword())) {
            throw new RuntimeException("密码输入错误!!!");
        }
        return adminDB;
    }
}
  • com.baizhi.dao.AdminDao
public interface AdminDao {

	// ... ...
	
    //根据用户名查询用户
    Admin findByUserName(String username);
}
  • com.baizhi.mapper.AdminDao.xml
<select id="findByUserName" parameterType="string" resultType="Admin">
    select id, username, password
    from admin
    where username = #{username}
select>
使用 Vue Cli 创建前端项目
  • 项目结构

Vue实战之使用Vue CLI 脚手架开发前后端分离项目之员工列表实现_第2张图片

  • helloworld\src\utils\request.js
//引入axios
import axios from "axios";

//创建默认实例
const instance = axios.create({
  baseURL: 'http://localhost:8989',
  timeout: 5000,
})

//请求拦截器
instance.interceptors.request.use(config => {
  console.log("请求拦截器")
  return config;
})

//响应拦截器
instance.interceptors.response.use(response => {
  console.log("响应拦截器")
  return response;
}), err => {
  console.log("响应出现错误时进入的拦截器")
}

//暴露instance实例对象
export default instance;
  • helloworld\src\views\Index.vue
<template>
  <div>
    <h1>欢迎进入员工管理系统首页 <span v-show="isLogin">欢迎: {{ admin.username }}</span></h1>
    <a href="javascript:;" @click="logout" v-show="isLogin">退出登录</a>
    <router-link v-show="!isLogin" :to="{name:'Login'}">立即登录</router-link>
    <hr/>
    <a href="#/index/emps">员工列表</a>
    <a href="#/index/depts">部门列表</a>
    <a href="#/index/orders">订单列表</a>
    <a href="#/index/users">用户列表</a>

    <router-view></router-view>
  </div>
</template>

<script>
import instance from "../utils/request";

export default {
  name: "Index",
  data() {
    return {
      admin: {}
    }
  },
  methods: {
    logout() {
      let token = localStorage.getItem("token");
      //根据token删除redis中用户登录标记
      instance.delete("/token?token=" + token).then(res => {
        // this.$router.push({path:'/'});//切换到主页
        this.admin = {};
      });
    }
  },
  computed: {
    isLogin() {
      return this.admin.username;//很多地方都用到了 admin.username,可以用 computed 计算属性 其实就是封装一下
    },
  },
  created() {
    //从localStorage获取token
    let token = localStorage.getItem("token");
    //发送axios 根据token获取用户信息
    instance.get("/token?token=" + token).then(res => {
      this.admin = res.data;
    });
  }
}
</script>

<style scoped>

</style>
  • helloworld\src\views\Login.vue
<template>
  <div>
    <form>
      用户名:<input type="text" v-model="admin.username"><br/>
      密码:<input type="text" v-model="admin.password"><br/>
      <input type="button" value="登录" @click="login">
    </form>
  </div>
</template>

<script>
import instance from "../utils/request";

export default {
  name: "Login",
  data() {
    return {
      admin: {}
    }
  },
  methods: {
    login() {
      //console.log(this.admin);
      //发送axios请求,登录成功
      //this.$router.push({name:'Index'});
      instance.post("/login", this.admin).then(res => {
        //console.log(res.data);
        const result = res.data;
        if (result.success) {
          //前端存储token信息  localStorage:本地缓存
          localStorage.setItem("token", result.token);
          //切换路由到主页
          this.$router.push({name: 'Index'});
        } else {
          alert(result.msg);
        }
      });
    }
  }
}
</script>

<style scoped>

</style>
  • helloworld\src\router\index.js
import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

const originalPush = Router.prototype.push;
Router.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => err)
};

export default new Router({
  routes: [
 // {
 //   path: '/',
 //   name: 'HelloWorld',
 //   component: HelloWorld
 // }
    {
      path: '/',//默认路由,重定向到主页
      redirect: '/index'
    },
    {
      path: '/login',
      name: 'Login',
      component: () => import('../views/Login')//按需加载 用到的时候才用加载
    },
    {
      path: '/index',
      name: 'Index',
      component: () => import('../views/Index'),
      children: [
        {
          path: 'emps',
          name: 'Emps',
          component: () => import('../views/emp/Index')
        },
        {
          path: 'depts',
          name: 'Depts',
          component: () => import('../views/dept/Index')
        },
        {
          path: 'orders',
          name: 'Orders',
          component: () => import('../views/order/Index')
        },
        {
          path: 'users',
          name: 'Users',
          component: () => import('../views/user/Index')
        }
      ]
    },
    {
      path: '*',
      component: () => import('../views/404')
    }
  ]
})
  • helloworld\src\views\404.vue
<template>
  <div>
    <h2>404 Not Found 当前页面走丢了!!!点我立即回到
      <router-link :to="{name:'Index'}">主页</router-link>
    </h2>
  </div>
</template>

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

<style scoped>

</style>
实现员工列表(增删改查)功能
  • com.baizhi.controller.EmpController
@RestController
@CrossOrigin
public class EmpController {


    @Resource
    private EmpService empService;


    @GetMapping("/emp")
    public Emp emp(Integer id) {
        return this.empService.queryById(id);
    }


    //查询所有
    @GetMapping("/emps")
    public List<Emp> emps() {
        return empService.queryAllByLimit(0, Integer.MAX_VALUE);
    }

    //添加员工信息
    @PostMapping("/emp")
    public void add(@RequestBody Emp emp) {
        if (StringUtils.isEmpty(emp.getId())) {
            empService.insert(emp);
        } else {
            empService.update(emp);
        }
    }

    //根据id删除员工信息
    @DeleteMapping("/emp/{id}")
    public void delete(@PathVariable("id") Integer id) {
        empService.deleteById(id);
    }

    //根据id查询一个员工信息
    @GetMapping("/emp/{id}")
    public Emp getById(@PathVariable("id") Integer id) {
        return this.empService.queryById(id);
    }
}
  • helloworld/src/views/emp/Index.vue
<template>
  <div>
    <h2>员工列表页面</h2>

    <button @click="addRow">添加员工信息</button>
    <table border="1" width="100%" style="text-align: center">
      <tr>
        <th>编号</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>工资</th>
        <th>操作</th>
      </tr>
      <tr v-for="(emp,index) in emps" :key="emp.id">
        <td v-text="emp.id"></td>
        <td v-text="emp.name"></td>
        <td v-text="emp.age"></td>
        <td v-text="emp.salary"></td>
        <td><a href="javascript:;" @click="detailRow(emp.id)">修改</a> <a href="javascript:;" @click="delRow(emp.id)">删除</a></td>
      </tr>
    </table>
    <br/>
    <form>
      <div v-show="emp.id">
        编号:<input type="text" readonly v-model="emp.id"><br/>
      </div>
      姓名:<input type="text" v-model="emp.name"><br/>
      年龄:<input type="text" v-model="emp.age"><br/>
      工资:<input type="text" v-model="emp.salary"><br/>
      <input type="button" value="保存|修改" @click="saveOrUpdate(emp.id)">
    </form>
  </div>
</template>

<script>
import instance from "../../utils/request";

export default {
  name: "Index",
  data() {
    return {
      emps: [],
      emp: {}
    }
  },
  methods: {
    findAll() {
      instance.get("/emps").then(res => {
        console.log(res.data)
        this.emps = res.data
      })
    },
    addRow() {
      this.emp = {}
    },
    detailRow(id) {//定义根据id查询一个方法
      instance.get("/emp/" + id).then(res => {
        this.emp = res.data;
      })
    },
    saveOrUpdate() {
      if (!this.emp.name) {
        alert("请输入员工姓名");
        return false;
      }
      if (!this.emp.age) {
        alert("请输入员工年龄");
        return false;
      }
      if (!this.emp.salary) {
        alert("请输入员工工资");
        return false;
      }
      var _this = this;//因为箭头函数下的this作用域就不是之前的了,所以在箭头函数前把this赋给一个新的变量,这样的-this还是之前的this
      instance.post("/emp/", this.emp).then(res => {
        this.emp = {};
        this.findAll();
      }).catch(err => {
        console.log(err)
      })
    },
    delRow(id) {
      if (window.confirm("您确定要删除吗?")) {
        instance.delete("/emp/" + id).then(res => {
          this.findAll();
        })
      }
    }
  },
  created() {
    this.findAll();
  },
}
</script>

<style scoped>

</style>
vue cli 公共组件的提取
  • helloworld/src/views/Index.vue 中的
    包裹的内容提取出来,然后在Index.vue中使用组件

Vue实战之使用Vue CLI 脚手架开发前后端分离项目之员工列表实现_第3张图片

代码仓库

你可能感兴趣的:(vue)