K项目实战 - SpringBoot结合Vue2.x群统计项目实战概述

一、概述规划

01、基本的原型

02、准备工作

1、idea开发工具
2、Jdk1.8
3、Mysq5.7
4、SpringBoot + ssm(mybatis-plus)
5、Layui+Jquery
6、Vue2.6.12 + Axios
7、统计插件:echarts或antv
8、Navicat11
9、模板引擎:thymeleaf
10、git/gitee 牵涉的版本控制工具





03、架构

单体架构模式

04、2.0增加功能

二维码生成和扫码投票




05、表设计




数据脚本

/*
Navicat MySQL Data Transfer
Source Server         : localhost
Source Server Version : 60011
Source Host           : localhost:3306
Source Database       : ksd-state-db
Target Server Type    : MYSQL
Target Server Version : 60011
File Encoding         : 65001
Date: 2021-04-29 21:16:05
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for ksd_state
-- ----------------------------
DROP TABLE IF EXISTS `ksd_state`;
CREATE TABLE `ksd_state` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(200) DEFAULT NULL COMMENT '主题标题',
  `description` varchar(600) DEFAULT NULL COMMENT '统计描述',
  `personnum` int(11) DEFAULT NULL COMMENT '参与人数',
  `endtime` varchar(30) DEFAULT NULL COMMENT '统计结束时间',
  `status` int(1) DEFAULT NULL COMMENT '0未发布 1 发布',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT NULL,
  `userid` int(11) DEFAULT NULL COMMENT '添加用户',
  `username` varchar(100) DEFAULT NULL COMMENT '添加人的名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of ksd_state
-- ----------------------------
INSERT INTO `ksd_state` VALUES ('1', '飞哥', null, null, null, null, '2021-04-29 21:11:25', null, null, null);
-- ----------------------------
-- Table structure for ksd_state_detail
-- ----------------------------
DROP TABLE IF EXISTS `ksd_state_detail`;
CREATE TABLE `ksd_state_detail` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `title` varchar(100) DEFAULT NULL COMMENT '统计项的标题',
  `status` int(1) DEFAULT NULL COMMENT '0未发布 1 发布',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT NULL,
  `userid` int(11) DEFAULT NULL COMMENT '添加用户',
  `username` varchar(100) DEFAULT NULL COMMENT '添加人的名称',
  `itemnum` int(11) DEFAULT NULL COMMENT '具体项目点击数量',
  `stateid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of ksd_state_detail
-- ----------------------------
INSERT INTO `ksd_state_detail` VALUES ('1', '小明', null, '2021-04-29 21:11:43', null, null, null, null, '1');
INSERT INTO `ksd_state_detail` VALUES ('2', '小张', null, '2021-04-29 21:11:47', null, null, null, null, '1');
INSERT INTO `ksd_state_detail` VALUES ('3', '小红', null, '2021-04-29 21:11:50', null, null, null, null, '1');
INSERT INTO `ksd_state_detail` VALUES ('4', '小王', null, '2021-04-29 21:11:54', null, null, null, null, '1');
INSERT INTO `ksd_state_detail` VALUES ('5', '小李', null, '2021-04-29 21:11:56', null, null, null, null, '2');
-- ----------------------------
-- Table structure for ksd_state_user_detail
-- ----------------------------
DROP TABLE IF EXISTS `ksd_state_user_detail`;
CREATE TABLE `ksd_state_user_detail` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT NULL,
  `userid` int(11) DEFAULT NULL COMMENT '添加用户',
  `username` varchar(100) DEFAULT NULL COMMENT '添加人的名称',
  `stateid` int(11) DEFAULT NULL,
  `detailid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of ksd_state_user_detail
-- ----------------------------
INSERT INTO `ksd_state_user_detail` VALUES ('1', '2021-04-29 21:11:43', null, null, null, '1', null);
INSERT INTO `ksd_state_user_detail` VALUES ('2', '2021-04-29 21:11:47', null, null, null, '1', null);
INSERT INTO `ksd_state_user_detail` VALUES ('3', '2021-04-29 21:11:50', null, null, null, '1', null);
INSERT INTO `ksd_state_user_detail` VALUES ('4', '2021-04-29 21:11:54', null, null, null, '1', null);
INSERT INTO `ksd_state_user_detail` VALUES ('5', '2021-04-29 21:11:56', null, null, null, '2', null);

06、echarts官网

Apache ECharts




07、效果展示

二、项目实战 - SpringBoot结合Vue2.x群统计项目-项目的搭建

01、课程目标

1、快速搭建springboot的SSM项目
2、在pom.xml中依赖SSM相关依赖
3、在application.yml中整合项目中常见配置
4、定义产品相关的entity、mapper、service、controller
5、完成统计业务的分数据库以及表的创建 分别是:统计表和统计明细表
6、定义一个页面index.html看是否能进行跳转
7、导入layui/jquery/vue/axios静态资源到static目录下
8、定义视图页面index.html设计添加投票的添加和查询统计
9、定义统计明细的接口以及使用vue进行渲染。
10、优化和完善




02、实现步骤

02-1、新建一个springboot工程

02-2、pom.xml引入支付相关依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </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>
        <!--mysql5.6x 驱动5.1.10-->
        <!--mysql5.7x+ 驱动8.0.17-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.10</version>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.13</version>
        </dependency>
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.10</version>
        </dependency>
        <!--二维码生成zxing-->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-avro</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.6</version>
        </dependency>

02-02、定义application.yml和application-prod.yml及application-dev.yml




application.yml如下

server:
  port: 80
# 数据库连接
spring:
  application:
    name: weixinpay
  profiles:
    active: dev
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    locale: zh_CN
    # 解决json返回过程中long的精度丢失问题
    generator:
      write-numbers-as-strings: true
      write-bigdecimal-as-plain: true
  mvc:
    servlet:
      load-on-startup: 1 #SpringBoot的接口第一次访问都很慢,通过日志可以发现,dispatcherServlet不是一开始就加载的,有访问才开始加载的,即懒加载。
  main:
    allow-bean-definition-overriding: true
# mybatis-plus配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:/mapper/*.xml
  type-aliases-package: com.kuangstudy.entity
logging:
  level:
    root: info
# 微信登录相关
weixin:
  login:
    info:
      # 微信小程序APPID
      appid: wx2f823cdc8dfba815
      # 微信小程序API私钥
      appsecret: 0139a6d9e93fb88d3d68e0a8a1b06bd6
      # 微信小程序登录成功回调地址
      redirectUrl: https://www.kuangstudy.com/login/api/wx/callback
  pay:
    info:
      # 微信支付网关
      gateway: https://api.weixin.qq.com/sns/jscode2session
      # 微信支付API秘钥
      appsecret: 0139a6d9e93fb88d3d68e0a8a1b06bd6
      # 微信商户id
      mchid: 1550648501
      # 微信小程序APPID
      appid: wx2f823cdc8dfba815
      # 支付成功回调地址,如果是微信小程序可以不配置
      notifyPath: https://api.kuangstudy.com/api/pay/callback

application-prod.yml

server:
  port: 80
# 数据库连接
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jiangfujiajiu?serverTimezone=GMT%2b8&useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: jiangfujiajiu
    password: KiD2y5kDmZZEmc3p
    hikari:
      connection-timeout: 60000
      validation-timeout: 3000
      idle-timeout: 60000
      login-timeout: 5
      max-lifetime: 60000
      maximum-pool-size: 400
      minimum-idle: 100
      read-only: false

application-dev.yml

# 数据库连接
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/jiangfujiajiu?serverTimezone=GMT%2b8&useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
    hikari:
      connection-timeout: 60000
      validation-timeout: 3000
      idle-timeout: 60000
      login-timeout: 5
      max-lifetime: 60000
      maximum-pool-size: 400
      minimum-idle: 100
      read-only: false

02-4、定义产品相关的entity、mapper、service、controller

因为代码体积过大,详看源代码中的 相关文件 里有所有完整的源代码。请结合视频酌情复制即可。节约学习时间

源码下载地址:下载 - KuangStudy

02-5、完成产品列表接口的定义和查询

因为代码体积过大,详看源代码中的 相关文件 里有所有完整的源代码。请结合视频酌情复制即可。节约学习时间


源码下载地址:下载 - KuangStudy

02-6、完成产品明细接口的查询

因为代码体积过大,详看源代码中的 相关文件 里有所有完整的源代码。请结合视频酌情复制即可。节约学习时间

源码下载地址:下载 - KuangStudy

三、项目实战 - SpringBoot结合Vue2.x群统计项目-完成接口的对接和静态资源的导入

01、目标

完成接口的对接和静态资源的导入




02、具体实现

下载静态资源


1: 在任意磁盘新建一个文件夹

2:执行如下命令把对应项目以来的js组件和css组件全部下载下来

npm init -y
npm instaill vue jquery layui axios

npm install vue axios [email protected]

 

3、在各种的目录中找到/dist/编译好的对应组件的js和css即可,放入到项目的static/js/css/

 




03、热加载

1: 在settings的配置中找到自动编译

2: 在idea的注册列表中去打开另外一个自动编译的配置如下:

按快捷键:CTRL+SHIFT+ALT+/
 

3:在pom.xml文件中增加devtools的配置

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
            <scope>true</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!--fork:如果没有该项配置,整个devtools不会起作用-->
                    <fork>true</fork>
                </configuration>
            </plugin>
            <plugin><!--编译跳过测试文件检查的生命周期-->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

使用方式

在修改页面按N次ctrl+F9 会自动重新编译页面到target/classes/static目录, 请注意:这是不万能,所有如果没有效果,可以收到吧static静态资源或者template静态资源手动复制到target/classes/static

如果刷新没有看到效果:请用ctrl+f5 强刷N次

四、基于Vue搭建自身后台

01、具备的知识点

vue、vuex、vue-router

02、官网文档

vue:Vue.jsVue.js - The Progressive JavaScript Frameworkhttps://cn.vuejs.org/index.html

vue-router:Vue Routerhttps://router.vuejs.org/zh/

vuex:Vuex 是什么? | Vuexhttps://vuex.vuejs.org/zh/

03、如何搭建一个vue后台的项目

3-1、使用vue-cli快速构建一个后台

参考官网:Vue CLIhttps://cli.vuejs.org/zh/

前提

必须要安装nodejs

下载 | Node.js 中文网http://nodejs.cn/download/判断是否安装成功

node -v

安装 

cnpm install -g @vue/cli
# OR
yarn global add @vue/cli(建议使用这个)

判断是否安装成功:

vue --version

启动项目

你可以通过vue ui命令图形化界面创建和管理项目,在项目所在目录进行cmd

vue ui

创建项目 

 

 

 创建完成会得到以下目录结构

3-2、安装核心的依赖

1、开发工具

vscode、webstorm、hbuilderx、idea

 

 2、安装vuex和vue-router依赖

 安装完成多了这两处

 也可以使用命令进行安装

npm i vue-router vuex --save-dev

3、为什么要安装vuex和vue-router依赖

vuex:是状态管理的插件(有种session的感觉)

vue-router:是路由管理的插件

 

 

 4、编写登录的页面和首页页面

(1)编写Login.vue页面组件,并且配置路由

<template>
    <div class="ksd-loginbox">
        <h1>我是一个登录页面组件</h1>
    </div>
</template>

<script>
    export default {
        name: 'Login',
        components: {

        }
    }
</script>
<style>

</style>

在router--index.js中添加

  {
    path: '/login',
    name: 'Login',
    component: () => import('../views/Login.vue')
  },

原型链

原型链:是给所有的对象实例派生属性和方法的一种机制,也就是,给创建好的对象进行扩展方法和属性的一种机制,可以达到继承的目的。

 

 main.js

function Player() {  //相当于java中的class Player()
  var name=''   //成员变量
}

Player.age=10;//静态变量

//相当于对Player对象进行扩展
Player.prototype.play=function () {
console.log(111)
}
//相当于对Player对象进行扩展
Player.prototype.pause=function () {
console.log(222)
}

//每个对象都有自带的prototype
var player1 = new Player();
var player2 = new Player();
var player3 = new Player();
console.log(player1);
console.log(player2);
console.log(player3);

该如何使用呢?

main.js

//静态实例,若页面需要调用此实例,需要自己额外导入
Vue.sayHello2=function(){
  alert("sayHello2")
}

//给每个页面都可以调用到sayHello实例
Vue.prototype.sayHello=function () {
console.log("sayHello")
}

Index.vue

<script>
    import Vue from 'vue';   //静态实例调用sayHello需要额外导入
    export default {
        name: "Index",
        components:{},
        data(){
            return{

            }
        },
        created() {
            this.sayHello();
            //this.sayHello2();此处就需要导入
            Vue.sayHello2();//上面进行了import Vue from 'vue';的导入

        },
        methods:{

        }
    }
</script>

所以this.$router就是

//所以this.$router就是
Vue.prototype.$router=function () {
  return{
    push:function () {}
  }
}

进行页面跳转

<template>
    <div class="ksd-loginbox">
        <p>
            <button @click="tologin">登录</button>
        </p>
    </div>
</template>

<script>
    import loginService from "@/service/LoginService";
    export default {
        name: 'Login',
        components: {

        },
        methods:{
            tologin(){
                //方法1:路径跳转
                //this.$router.push('/');
                //方法2:name跳转
                // this.$router.push({'name':'Index'})
                //方法3:可以抽离出来在进行定义跳转
                loginService.login();
            }
        }
    }
</script>

LoginService.js

import router from '@/router'

export default {
    login(){
        router.push("/");
    }
};

(2)编写一个index.vue首页的组件,并且配置路由

下载插件vue-cli-plugin-element

 发现项目中自动出现

 

之后就可以在element官网拿取样式(网址:Element - The world's most popular Vue UI framework )

此时出现一个问题:普通路由跳转会跳转到另外页面,不能实现只替换main中的内容

查询vue-router官网,使用嵌套路由进行实现(嵌套路由 | Vue Router

  {
    path: '/user',
    component: Index,
    children:[
      {
        path: 'add',
        name: 'UserAdd',
        component: () => import('../views/user/Add.vue')
      },
      {
        path: 'list',
        name: 'UserList',
        component: () => import('../views/user/List.vue')
      }
    ]
  }

Index.vue中添加<router-view></router-view>

            <el-main>
                <router-view></router-view>
            </el-main>

(3)使用axios异步请求,模拟登录到index.vue(牵涉到知识点:axios和vue-router如何跳转,如果跳转过程中传递参数又如何传递,又如何接收)

axios官网:axios中文文档|axios中文网 | axios

axios是一个异步请求的js库,类似于:jquery异步

注意:无论是jquery异步,还是axios还是微信小程序:wx.request、ui.request都是对js中XMLHttpServletRequest的封装。

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应(异步的权限拦截 若依,antd,vue-admin)
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

把axios进行了一个重构和二次封装 request.js和server.js和cache.js

在图形化界面安装vue-cli-plugin-axios

安装完成后出现了一个报错

 解决方法

打开package.json,在rules下添加

"no-unused-vars": "off"

如下图

然后重启项目

报错原因

项目安装了eslint校验,

后台

a、编写接口StateController

 @GetMapping("/state/list")
    public R findStates() {
        QueryWrapper<State> queryWrapper = new QueryWrapper<>();
        return R.ok().data("statesData", stateService.list(queryWrapper));
    }

b、拦截器配置WebMvcConfig

    @Override
    public void addCorsMappings(CorsRegistry registry){
        registry.addMapping("/state/**")
                .allowedOrigins("http://localhost:8080")            //此处如果写*,代表放行所有
                .allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
                .maxAge(3600)
                .allowedHeaders("*");
    }

前端:

Index.vue

引入

import axios from 'axios';
<template>
    <el-container>
        <el-header>
            <Nav></Nav>
        </el-header>
        <el-container>
            <el-aside width="200px">
                <Aside></Aside>
            </el-aside>
            <el-main>
                <ul id="example">
                    <li v-for="item in statesData" :key="item.id">
                        {
   
   { item.id }}
                        {
   
   { item.title }}
                        {
   
   { item.createTime }}
                    </li>
                </ul>

                <router-view></router-view>
            </el-main>
        </el-container>
    </el-container>
</template>

<script>
    // import Vue from 'vue';
    import Nav from "../components/Nav";
    import Aside from "../components/Aside";
    //引入axios
    import axios from 'axios';       

    export default {
        name: "Index",
        components: {
            Nav, Aside
        },
        data() {
            return {
                data:{},
                statesData:[]   //获取数组
            }
        },
        created() {

            var promise = axios.get("http://localhost/state/list");
            promise.then(res=>{
                this.data=res.data.data
                this.statesData=res.data.data.statesData
                console.log("res",res)
            }).catch(error=>{
                console.log("error",error)
            })

        },
        methods: {}
    }
</script>

(4)、了解一个页面的组成部分,以及了解axios异步处理框架(异步自定义、拦截器)对照若依或者antd源码进行分析

axios

1、异步处理肯定是每个开发人员都要调用的js库,因为要完成数据接口渲染工作。开发定义的位置和业务是非常多的,一旦维护起来会非常的不方便

2、书写方式不友好,后续的优化和控制就不便

3、如果接口一旦要考虑安全性jwt token,那么每个axios处理接口的地方都需要增加参数或者请求头中增加参数,导致后续不便

4、在开发中axios有些请求是需要拦截的,有些是不需要拦截,如何进行封装和重构,就很有必要

5、在肯定要增加一些统一域名和统一参数或者一些状态标志等等,如果每个地方去增加也不方便

封装思路:

1、entity、service、controller

2、接口--后端提供--entity

3、接口--axios--service--页面(页面组件)

封装的好处

复用

配置项目所需要的服务常量

(5)封装一个request.js来完成异步请求的逻辑

此处拦截器代码还未实现

import server from '../common/server';
import axios from 'axios'

var request=function (url,params,type="get") {
    var token='xxxxxx';
    var headers={'token': token}
    var requestparams={};

    if (type && type.toUpperCase() == 'post') {
        headers["content-type"] = "application/x-www-form-urlencoded";
        requestparams=params;
    }else {
        requestparams.params=params;
    }

    //1:创建一个axios的对象,对异步请求对象进行增强的处理
    const axiosInstance=axios.create({
        //如果你访问的路径是一个相对路径,就自动增加baseURL,
        //如果你访问是一个https或者http请求就不会增加baseURL
        baseURL:server.url,
        headers:headers
    });


    // 添加请求拦截器
    axiosInstance.interceptors.request.use(function (config) {
        console.log("拦截器。。。。")
        console.log(config)
        // 在发送请求之前做些什么
        return config;
    }, function (error) {
        // 对请求错误做些什么
        return Promise.reject(error);
    });

// 添加响应拦截器
    axiosInstance.interceptors.response.use(function (response) {
        // 对响应数据做点什么
        return response;
    }, function (error) {
        // 对响应错误做点什么
        return Promise.reject(error);
    });

    return axiosInstance[type](url,requestparams);

}

//注意:凡是可以.的都是对象,对象.属性 或者对象[属性]



// var request = function (url, params, type) {
//
//     //1、处理token,放入到请求头中
//     var token = "xxxxxx";
//     var headers = {'token': token}
//
//     //3、组装异步请求的参数
//     var axiosobj = {
//         method: type || "get",
//         url: server.url + url,
//         // data: params,
//         headers
//     };
//
//     //2、处理post请求参数的问题
//     if (type && type.toUpperCase() == 'post') {
//         headers["content-type"] = "application/x-www-form-urlencoded";
//         axiosobj.data=params;
//     }else{
//         axiosobj.params=params;
//     }
//
//     //返回参数
//     return axios(axiosobj);
// };
//
 export default request;

(6)开始对项目进行分层框架和目录划分,让业务和接口调用进行分离

像后台分层一样进行划分 

(7)安装一个elementui组件(布局使用,路由完成跳转)

制作组件

Aside组件(类似于侧边导航栏)

<template>
    <el-menu
            default-active="1"
            class="el-menu-vertical-demo"
            @open="handleOpen"
            @close="handleClose"
            background-color="#545c64"
            text-color="#fff"
            style="height: 100%"
            active-text-color="#ffd04b">
        <el-submenu index="1">
            <template slot="title">
                <i class="el-icon-location"></i>
                <span>首页后台</span>
            </template>
            <el-menu-item-group>
                <el-menu-item index="1-1">
                    <router-link to="/user/list">用户管理</router-link>
                </el-menu-item>
                <el-menu-item index="1-2">
                    <router-link to="/user/add">用户添加</router-link>
                </el-menu-item>
            </el-menu-item-group>
        </el-submenu>
        <el-menu-item index="2">
            <i class="el-icon-menu"></i>
            <span slot="title">订单管理</span>
        </el-menu-item>
        <el-menu-item index="3">
            <i class="el-icon-document"></i>
            <span slot="title">课程管理</span>
        </el-menu-item>
        <el-menu-item index="4">
            <i class="el-icon-setting"></i>
            <span slot="title">系统设置</span>
        </el-menu-item>
    </el-menu>
</template>

<script>
    export default {
        name: "Aside",
        methods: {
            handleOpen(key, keyPath) {
                console.log(key, keyPath);
            },
            handleClose(key, keyPath) {
                console.log(key, keyPath);
            }
        }
    }
</script>

<style scoped>

</style>

在vue页面中引入组件<Aside></Aside>

<template>
    <el-container>
        <el-header>
            <Nav></Nav>
        </el-header>
        <el-container>
            <el-aside width="200px">
                <Aside></Aside>
            </el-aside>
            <el-main>
                <ul id="example">
                    <li v-for="item in statesData" :key="item.id">
                        {
   
   { item.id }}
                        {
   
   { item.title }}
                        {
   
   { item.createTime }}
                    </li>
                </ul>
                <router-view></router-view>
            </el-main>
        </el-container>
    </el-container>
</template>

<script>
    import Nav from "../components/Nav";
    import Aside from "../components/Aside";

    import stateService from "../service/state/StateService";
    import stateDetailService from "../service/index/IndexService"
    import toLogin from "../common/login";

    export default {
        name: "Index",
        components: {
            Nav, Aside
        },
        data() {
            return {
                data:{},
                statesData:[]   //获取数组
            }
        },
        created() {
            var promise = stateService.getState();
            promise.then(res=>{
                this.data=res.data.data
                this.statesData=res.data.data.statesData
                console.log("res",res)
            }).catch(error=>{
                console.log("error",error)
            })

        },
        methods: {
            //加载明细
            loadStateDetail(){
                toLogin(function () {
                    stateDetailService.getStateDetail().then(res=>{
                        console.log(res)
                    }).catch(err=>{
                        console.log("error",err)
                    })
                })
            }
        }
    }
</script>

<style scoped>


</style>

(8)状态管理的module的分析和业务的结合。(为代码实现:登录放入vuex进行管理,然后在首页中展示用户信息)

项目实战 - SpringBoot结合Vue2.x群统计项目-统计页面的展示和数据查询检索

01、目标

统计页面的展示和数据查询检索

02、具体实现

1、官网:Layui 开发使用文档 - 入门指南
2、下载

npm i layui

Vue组件通信 - 父子之间通信 - $parent 和 $refs

01、目标

使用$parent完成子调用父组件的方法和属性

02、具体实现

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    { {title} }
    <mybutton v-bind:message="title"></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
    // 子调用父的函数----调用函数
    const buttonCompoment= {
        template:"<button @click='childrenClick'>{ {message} }</button>",
        // 它的数据是一个函数 + return {}。
        data(){
            return {
                name:"按钮1"
            }
        },
        // 生命周期钩子
        created(){
          console.log("组件加载完毕执行此处...")
        },
        // 组件属性 自定义属性
        props : {
            "message":{type:String}
        },
        // 计算属性
        computed : {
        },
        // 方法
        methods : {
            childrenClick(){
                // 调用父属性
                this.$parent.title = "子改变父亲的标题了哦!!";
                // 调用父函数
                this.$parent.calnum();
            }
        },
        // 监控属性
        watch : {
        }
    }
    // 全局注册
    Vue.component("mybutton",buttonCompoment);
    // 1 : 实例化vue
    var vue = new Vue({
        // 2 : 指定渲染的范围
        el:"#app",
        // 3 :数据定义的位置也就是Model
        data:{
           title:"我是的标题"
        },
        // 4: 事件定义的位置,@事件类型="事件名"
        methods:{
            calnum(){
                alert("我调用父亲的函数");
            }
        }
    })
</script>
</body>
</html>

Vue高级编程 - 组件

官网参考:组件基础 — Vue.js

01、概述

在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。但是如果每个页面都独自开发,这无疑增加了开发的成本。所以会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。

Vue组件的作用: 复用

通常一个应用会以一棵嵌套的组件树的形式来组织:
 

02、目标

定义和注册组件




03、定义组件

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    <mybutton></mybutton>
    <mybutton></mybutton>
    <mybutton></mybutton>
    <mybutton></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
    // 自定义组件
    const buttonCompoment= {
        // 这里是组件的模板
        template:"<button>{ {name} }</button>",
        // 它的数据是一个函数 + return {}。
        data(){
            return {
                name:"按钮1"
            }
        },
        // 生命周期钩子
        created(){
          console.log("组件加载完毕执行此处...")
        },
        // 组件属性
        props : {
        },
        // 计算属性
        computed : {
        },
        // 方法
        methods : {
        },
        // 监控属性
        watch : {
        }
    }
    // 1 : 实例化vue
    var vue = new Vue({
        // 2 : 指定渲染的范围
        el:"#app",
        // 3 :数据定义的位置也就是Model
        data:{
        },
        // 4: 事件定义的位置,@事件类型="事件名"
        methods:{
        }
    })
</script>
</body>
</html>

04、小结

组件中的data是一个json对象?

不是,必须是一个函数。这个是和父组件的区别

Vue高级编程 - 组件注册

官网参考:组件基础 — Vue.js

01、目标

组件的注册(全局注册和局部注册)




02、全局注册

  • 全局注册的组件,可以用在所有的 Vue 实例 (new Vue) 中。
  • 语法如下
# 第一种方式
Vue.component('组件名称', { /* ... */ })
# 第二种方式
Vue.component('组件名称', 组件对象);
  • 定义组件名

参考官网:组件注册 — Vue.js

03、全局注册具体实现

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    { {title} }
    <mybutton></mybutton>
    <mybutton></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
    // 自定义组件
    const buttonCompoment= {
        template:"<button>{ {name} }</button>",
        // 它的数据是一个函数 + return {}。
        data(){
            return {
                name:"按钮1"
            }
        },
        // 生命周期钩子
        created(){
            console.log("组件加载完毕执行此处...")
        },
        // 组件属性 自定义属性
        props : {
        },
        // 计算属性
        computed : {
        },
        // 方法
        methods : {
        },
        // 监控属性
        watch : {
        }
    }
    // 全局注册
    Vue.component("mybutton",buttonCompoment);
    // 1 : 实例化vue
    var vue = new Vue({
        // 2 : 指定渲染的范围
        el:"#app",
        // 3 :数据定义的位置也就是Model
        data:{
            title:"我是一个按钮"
        },
        // 4: 事件定义的位置,@事件类型="事件名"
        methods:{
        } 
    })
</script>
</body>
</html>

04、局部注册组件

  • 局部注册的组件,只能在当前的Vue实例中可以使用
  • 语法
// 局部注册组件(只有当前vue实例可以用)
components : {
    "mybutton" : MyButton
}
  • 使用自定义组件:
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    { {title} }
    <mybutton></mybutton>
    <mybutton></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
    // 自定义组件
    const buttonCompoment= {
        template:"<button>{ {name} }</button>",
        // 它的数据是一个函数 + return {}。
        data(){
            return {
                name:"按钮1"
            }
        },
        // 生命周期钩子
        created(){
            console.log("组件加载完毕执行此处...")
        },
        // 组件属性 自定义属性
        props : {
        },
        // 计算属性
        computed : {
        },
        // 方法
        methods : {
        },
        // 监控属性
        watch : {
        }
    }
    // 全局注册
    //Vue.component("mybutton",buttonCompoment);
    // 1 : 实例化vue
    var vue = new Vue({
        // 2 : 指定渲染的范围
        el:"#app",
        // 3 :数据定义的位置也就是Model
        data:{
            title:"我是一个按钮"
        },
        // 4: 事件定义的位置,@事件类型="事件名"
        methods:{
        },
        //局部注册
        components:{
            "mybutton":buttonCompoment
        }
    })
</script>
</body>
</html>

05、小结

  • 全局注册组件与局部注册组件的区别?
  1. 全局可以提供给所有页面使用,局部只能给当前页面使用。
  • 全局注册组件语法?
  1. // 全局注册
  2. Vue.component("mybutton",buttonCompoment);

Vue高级编程 - 组件-父向子通讯-Props

官网参考:Prop — Vue.js


01、目标

通过 Prop 向子组件传递数据


02、语法

// 定义组件: 组件属性(定义父组件需要传递过来的属性)
props : {
    // Prop属性名 : {type : "数据类型", required : 是否必须}
    title : {type : String, required : true}, 
    color : {type : String, required : false}
}
// 使用组件
<组件名称 title="" color=""></组件名称>

03、具体代码

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    <mybutton v-bind:message="title"></mybutton>
    <mybutton v-bind:message="title"></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
    // 子调用父的函数----调用函数
    const buttonCompoment= {
        template:"<button>{ {message} }</button>",
        // 它的数据是一个函数 + return {}。
        data(){
            return {
                name:"按钮1"
            }
        },
        // 生命周期钩子
        created(){
            console.log("组件加载完毕执行此处...")
        },
        // 组件属性 自定义属性
        props : {
            "message":{type:String}
        },
        // 计算属性
        computed : {
        },
        // 方法
        methods : {
        },
        // 监控属性
      watch : {
        }
  }
  // 全局注册
    Vue.component("mybutton",buttonCompoment);
    // 1 : 实例化vue
    var vue = new Vue({
        // 2 : 指定渲染的范围
        el:"#app",
        // 3 :数据定义的位置也就是Model
        data:{
            title:"我是的父按钮"
        },
        // 4: 事件定义的位置,@事件类型="事件名"
        methods:{
        }
    })
</script>
</body>
</html>

04、小结

父组件如何与子组件通信? props

Vue高级编程 - 组件- 子向父通信 - $emit

参考官网:自定义事件 — Vue.js

01、目标

通过Vue实例$emit方法,触发当前实例上的事件方式向父组件传递数据

02、具体实现

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    <mybutton  @btnclick="calcNum"></mybutton>
    <mybutton @btnclick="calcNum"></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
    // 子调用父的函数----调用函数
    const buttonCompoment= {
        template:"<button @click='clickme'>{ {name} }</button>",
        // 它的数据是一个函数 + return {}。
        data(){
            return {
                name:"点击调用父元素方法"
            }
        },
        // 生命周期钩子
        created(){
            console.log("组件加载完毕执行此处...")
        },
        // 组件属性 自定义属性
        props : {
        },
        // 计算属性
        computed : {
        },
        // 方法
        methods : {
            clickme(){
                //这里是自定义事件,参数1是事件名称,参数2是参数
                this.$emit("btnclick",{});
            }
        },
        // 监控属性
        watch : {
      }
    }
    // 全局注册
  Vue.component("mybutton",buttonCompoment);
    // 1 : 实例化vue
    var vue = new Vue({
        // 2 : 指定渲染的范围
        el:"#app",
        // 3 :数据定义的位置也就是Model
        data:{
            title:"我是的标题"
        },
        // 4: 事件定义的位置,@事件类型="事件名"
        methods:{
            calcNum(){
                alert("你调用父函数...")
            }
        }
    })
</script>
</body>
</html>

03、小结

子组件如果向父组件通信? $emit

视频地址:项目实战 - SpringBoot结合Vue2.x群统计项目_哔哩哔哩_bilibili

本地mysql数据库:kuangstudy

项目位置:F:\studyitems\开源项目\vue2结合springboot群统计项目\Mytry

猜你喜欢

转载自blog.csdn.net/weixin_49562132/article/details/120506676