前端Vue

Vue

单向绑定v-bind,简写 :

除了使用插值表达式{{}}进行数据渲染,也可以使用 v-bind指令,它的简写的形式就是一个冒号(:)

<body>
    <div id="app">
        <h1 v-bind:title="message">
            test
        </h1>
    </div>
    <script src="vue.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                message: 'hello,vue!'
            }
        })
    </script>
</body>

双向绑定v-model

当v-model绑定的值改变时,其他和他绑定的值一样的也跟着改变。

<body>
    <div id="app">
        <!-- v-bind:value只能进行单向的数据渲染 -->
        <input type="text" v-bind:value="searchMap.keyWord">
        <!-- v-model 可以进行双向的数据绑定  -->
        <input type="text" v-model="searchMap.keyWord">

        <p>您要查询的是:{{searchMap.keyWord}}</p>
    </div>
    <script src="vue.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                searchMap:{
                    keyWord: '尚硅谷'
                }
            }
        })
    </script>
</body>

事件绑定v-on,简写 @

<body>
    <div id="app">
        <button v-on:click="search()">点我</button>
        
        <!-- 简写 -->
        <button @click="search()">点我</button>
    </div>
    <script src="vue.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                
            },
            methods: {
                search() {
                    alert("hahaha")
                }
            }
        })
    </script>
</body>

加深

配置v-bind使用,当单机事件时,显示信息

<body>
    <div id="app">
        <button @click="search()">点我</button>

        <p><a :href="result.site" target="_blank">{{result.title}}</a></p>
    </div>
    <script src="vue.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                result: {}
            },
            methods: {
                search() {
                    console.log("hahaha")
                    this.result = {
                        "title":"百度",
                        "site":"http://www.baidu.com"
                    }
                }
            }
        })
    </script>
</body>

v-if

<body>
    <div id="app">
        <input type="checkbox" v-model="ok">同意许可协议

        <!-- v:if条件指令:还有v-else、v-else-if 切换开销大 -->
        <h1 v-if="ok">Dragon</h1>
        <h1 v-else>no</h1>
    </div>
    <script src="vue.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                ok: false
            }
        })
    </script>
</body>

v-for

<body>
    <div id="app">
        <table border="1">
            <tr v-for="user in userList">
                <td>{{user.id}}</td>
                <td>{{user.name}}</td>
                <td>{{user.age}}</td>
            </tr>
        </table>
    </div>
    <script src="vue.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                userList: [
                    {id:1,name:'张3',age:12},
                    {id:2,name:'张4',age:13},
                    {id:3,name:'张5',age:14}
                ]
            }
        })
    </script>
</body>

生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sN4MwaZK-1652586714636)(C:/Users/hasee/Pictures/javaWeb/Vue/生命周期.png)]

总结

概括就是:在页面渲染之前会执行created方法,页面数据渲染之后会执行mounted方法。

Vue路由

引入js

<script src="vue.min.js"></script>
<script src="vue-router.min.js"></script>

编写html

<div id="app">
    <h1>Hello App!</h1>
    <p>
        <!-- 使用 router-link 组件来导航. -->
        <!-- 通过传入 `to` 属性指定链接. -->
        <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
        <router-link to="/">首页</router-link>
        <router-link to="/student">会员管理</router-link>
        <router-link to="/teacher">讲师管理</router-link>
    </p>
    <!-- 路由出口 -->
    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view></router-view>
</div>

编写js

<script>
    // 1. 定义(路由)组件。
    // 可以从其他文件 import 进来
    const Welcome = { template: '<div>欢迎</div>' }
    const Student = { template: '<div>student list</div>' }
    const Teacher = { template: '<div>teacher list</div>' }
    // 2. 定义路由
    // 每个路由应该映射一个组件。
    const routes = [
        { path: '/', redirect: '/welcome' }, //设置默认指向的路径
        { path: '/welcome', component: Welcome },
        { path: '/student', component: Student },
        { path: '/teacher', component: Teacher }
    ]
    // 3. 创建 router 实例,然后传 `routes` 配置
    const router = new VueRouter({
        routes // (缩写)相当于 routes: routes
    })
    // 4. 创建和挂载根实例。
    // 从而让整个应用都有路由功能
    const app = new Vue({
        el: '#app',
        router
    })
    // 现在,应用已经启动了!
</script>

axios

固定结构

<body>
    <div id="app">

    </div>
    <script src="vue.min.js"></script>
    <script src="axios.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            //固定结构
            data: {//data定义变量和初始值
                
            },
            created() {//页面渲染之前执行
                //调用定义的方法
            },
            methods: {//定义具体方法

            }
        })
    </script>
</body>

测试

<body>
    <div id="app">
        <ul v-for="user in userList">
            <li>姓名:{{user.name}},年龄:{{user.age}}</li>
        </ul>
    </div>
    <script src="vue.min.js"></script>
    <script src="axios.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            //固定结构
            data: {//data定义变量和初始值
                //定义初始值,接受json数据
                userList:[]
            },
            created() {//页面渲染之前执行
                //调用定义的方法
                this.getUserList()
            },
            methods: {//定义具体方法
                //查询所有的数据
                getUserList() {
                    //使用axios发送ajax请求
                    axios.get("data.json")//请求路径
                        //请求成功执行then方法
                        .then(response => {
                            //通过response响应的数据返回给初始值
                            this.userList = response.data.data.items
                        }) 
                        //请求失败执行catch方法
                        .catch(error => {
                        })
                }
            }
        })
    </script>
</body>

Node.js

简单理解就是javaScript的运行环境。

NPM

相当于maven中pom依赖

配置淘宝镜像

#经过下面的配置,以后所有的 npm install 都会经过淘宝的镜像地址下载
npm config set registry https://registry.npm.taobao.org 

#查看npm配置信息
npm config list

npm install命令的使用

#使用 npm install 安装依赖包的最新版,
#模块安装的位置:项目目录\node_modules
#安装会自动在项目目录下添加 package-lock.json文件,这个文件帮助锁定安装包的版本
#同时package.json 文件中,依赖包会被添加到dependencies节点下,类似maven中的 <dependencies>
npm install jquery


#npm管理的项目在备份和传输的时候一般不携带node_modules文件夹
npm install #根据package.json中的配置下载依赖,初始化项目


#如果安装时想指定特定的版本
npm install jquery@2.1.x


#devDependencies节点:开发时的依赖包,项目打包到生产环境的时候不包含的依赖
#使用 -D参数将依赖添加到devDependencies节点
npm install --save-dev eslint
#或
npm install -D eslint


#全局安装
#Node.js全局安装的npm包和工具的位置:用户目录\AppData\Roaming\npm\node_modules
#一些命令行工具常使用全局安装的方式
npm install -g webpack

其它命令

#更新包(更新到最新版本)
npm update 包名
#全局更新
npm update -g 包名
#卸载包
npm uninstall 包名
#全局卸载
npm uninstall -g 包名

Babel

简介

Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行执行。

这意味着,你可以现在就用 ES6 编写程序,而不用担心现有环境是否支持。

安装

安装命令行转码工具

Babel提供babel-cli工具,用于命令行转码。它的安装命令如下:

npm install --global babel-cli
#查看是否安装成功
babel --version

Babel的使用

初始化项目

npm init -y

创建文件

src/example.js

下面是一段ES6代码:

// 转码前
// 定义数据
let input = [1, 2, 3]
// 将数组的每个元素 +1
input = input.map(item => item + 1)
console.log(input)

配置.babelrc

Babel的配置文件是.babelrc,存放在项目的根目录下,该文件用来设置转码规则和插件,基本格式如下。

{
    "presets": [],
    "plugins": []
}

presets字段设定转码规则,将es2015规则加入 .babelrc:

{
    "presets": ["es2015"],
    "plugins": []
}

安装转码器

在项目中安装

npm install --save-dev babel-preset-es2015

转码

# 转码结果写入一个文件
mkdir dist1
# --out-file 或 -o 参数指定输出文件
babel src/example.js --out-file dist1/compiled.js
# 或者
babel src/example.js -o dist1/compiled.js
# 整个目录转码
mkdir dist2
# --out-dir 或 -d 参数指定输出目录
babel src --out-dir dist2
# 或者
babel src -d dist2

模块化

es5模块化

定义一个模块01.js

//定义两个方法
const sum = function(a,b){
    return parseInt(a) + parseInt(b)
}
const subtract = function(a,b){
    return parseInt(a) - parseInt(b)
}

//导出模块
module.exports = {
    sum,
    subtract
}

在02.js文件中引用01.js模块

//访问01中的方法
const a = require('./01.js')

console.log(a.sum(1,2))
console.log(a.subtract(2,1))

测试

node 02.js

es5总结

module.exports导出模块

require(‘./路径’)引用某个导出的模块

es6模块化

定义一个模块01.js

//定义方法
export function getList(){
    console.log("getList......")
}

export function save(){
    console.log("save.....")
}

在02.js文件中引用01.js模块

//调用01中的方法
import {getList,save} from './01.js'

//调用方法
console.log(getList())
console.log(save)

注意:这时的程序无法运行的,因为ES6的模块化无法在Node.js中执行,需要用Babel编辑成ES5后再执行。

转换的时候注意要在目录文件夹外转换。

测试转换后的文件

node 02.js

简化写法

导出模块

export default {
    getList() {
        console.log('获取数据列表2')
    },

    save() {
        console.log('保存数据2')
    }
}

导入模块

import a from "./userApi2.js"
a.getList()
a.save()

Webpack

Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。

从图中我们可以看出,Webpack 可以将多种静态资源 js、css、less 转换成一个静态文件,减少了页面的请求

简单说就是把多个js文件打包成一个js文件。

1、全局安装

npm install -g webpack webpack-cli

2、创建js文件用于打包操作

  1. src下创建common.js

    exports.info = function (str) {
        document.write(str);
    }
    
  2. src下创建utils.js

    exports.add = function (a, b) {
        return a + b;
    }
    
  3. src下创建main.js,用于引入其他两个文件,打包入口

    const common = require('./common');
    const utils = require('./util');
    
    common.info('Hello world!' + utils.add(100, 200));
    

3、创建webpack配置文件,配置打包信息

webpack.config.js

const path = require("path"); //Node.js内置模块
module.exports = {
    entry: './src/main.js', //配置入口文件
    output: {
        path: path.resolve(__dirname, './demo'), //输出路径,__dirname:当前文件所在路径 
        filename: 'bundle.js' //输出文件
    }
}

4、使用命令进行打包

webpack #有黄色警告,这个打包只有一行,不方便查看
webpack --mode=development #没有警告,这个打包后回事多行文件,推荐  ***********
#执行后查看bundle.js 里面包含了上面两个js文件的内容并惊醒了代码压缩

5、打包后测试

新建test.html

<script src="demo/bundle.js"></script>

css打包

在src下新建style.css文件

body{
    background-color: red;
}

引入到main.js中

require("./style.css")

安装style-loader和 css-loader

Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。

Loader 可以理解为是模块和资源的转换器。

首先我们需要安装相关Loader插件,css-loader 是将 css 装载到 javascript;style-loader 是让 javascript 认识css

npm install --save-dev style-loader css-loader 

修改配置文件

在ouput后边添加

//...,
    output:{},
    module: {
        rules: [  
            {  
                test: /\.css$/,    //打包规则应用到以css结尾的文件上
                use: ['style-loader', 'css-loader']
            }  
        ]  
    }

解决前后端跨域

1、在controller中加入注解解决

@CrossOrigin  //解决跨域

2、使用网关解决

ById得到这一行的id

scope.row.id

路由跳转界面

this.$router.push({ path: '/teacher/list' })

阿里云oss

导入依赖

<dependencies>
    <!-- 阿里云oss依赖 -->
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
    </dependency>

    <!-- 日期工具栏依赖 -->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
    </dependency>
</dependencies>

配置文件

#服务名
spring.application.name=service-oss

#环境设置:dev、test、prod
spring.profiles.active=dev
        
#阿里云 OSS
#不同的服务器,地址不同
aliyun.oss.file.endpoint=your endpoint
aliyun.oss.file.keyid=your accessKeyId
aliyun.oss.file.keysecret=your accessKeySecret
#bucket可以在控制台创建,也可以使用java代码创建
aliyun.oss.file.bucketname=edu-rb

测试,启动报错解决

原因是启动类自动去加载数据库了,解决办法

1、在配置文件中加上数据库的配置,虽然能解决,但是我们不许要数据库,这就有点多余了。

2、在启动类的注解**@SpringBootAppliation**参数中加上(exclude = DataSourceAutoConfiguration),表示不加载数据库。【推荐】

实现文件上传

从配置文件读取常量

创建常量读取工具类:ConstantPropertiesUtil.java

//当项目启动,spring加载之后,自动执行InitializingBean里的方法
@Component
public class ConstantPropertiesUtils implements InitializingBean {

    @Value("${aliyun.oss.file.endpoint}")
    private String endPoint;

    @Value("${aliyun.oss.file.keyid}")
    private String keyId;

    @Value("${aliyun.oss.file.keysecret}")
    private String keySecret;

    @Value("${aliyun.oss.file.bucketname}")
    private String bucketName;

    //定义公开静态常量
    public static String END_POINT;
    public static String ACCESS_KEY_ID;
    public static String ACCESS_KEY_SECRET;
    public static String BUCKET_NAME;

    //当spring执行时,上边的值初始化完成后,这个方法会自动执行
    @Override
    public void afterPropertiesSet() throws Exception {
        END_POINT = endPoint;
        ACCESS_KEY_ID = keyId;
        ACCESS_KEY_SECRET = keySecret;
        BUCKET_NAME = bucketName;
    }
}

创建service层,创建controller,注入service

@Controller
@RestController("eduoss/fileoss")
public class OssController {

    @Autowired
    private OssService ossService;

    //上传头像
    @PostMapping
    public ResultCode updateOssFile(MultipartFile file) {
        //获取上传文件,MultipartFile

        //返回上传到oss路径
        String url = ossService.updateFileAvatar;

        return ResultCode.ok().data("url",url);
    }
}

在service实现上传文件

package com.dragon.serviceedu.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.dragon.serviceedu.service.OssService;
import com.dragon.serviceedu.utils.ConstantPropertiesUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;

@Service
public class OssServiceImpl implements OssService {
    @Override
    public String updateFileAvatar(MultipartFile file) {

        //获取ConstantPropertiesUtils中的值
        String endpoint = ConstantPropertiesUtils.END_POINT;
        String accessKeyId = ConstantPropertiesUtils.ACCESS_KEY_ID;
        String accessKeySecret = ConstantPropertiesUtils.ACCESS_KEY_SECRET;
        String bucketName = ConstantPropertiesUtils.BUCKET_NAME;

        try {
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            //获取上传文件输入流
            InputStream inputStream = file.getInputStream();

            //获取文件名称
            String filename = file.getOriginalFilename();

            //在文件名字中添加uuid,不然上传文件覆盖之前文件
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            filename = uuid + filename;
            
            //把文件按照日期分类,创建文件目录  2020/12/15/01.jpg
            String datePath = new DateTime().toString("yyyy/MM/dd");

            //拼接
            filename = datePath + "/" + filename;
            
            //调用oos方法实现上穿
            /*
            * 参数一:bucketName
            * 参数二:上传到oss文件路径或名称
            * 参数三:上传文件输入流
            * */
            ossClient.putObject(bucketName, filename, inputStream);

            // 关闭OSSClient。
            ossClient.shutdown();

            //把上传文件的路径返回
            //需要手动拼接oss文件路径
            //https://edu-rb.oss-cn-beijing.aliyuncs.com/2.jpg
            String url = "https://"+bucketName+"."+endpoint+"/"+filename;
            return url;
        } catch (Exception e) {

        }
        return null;
    }
}

Controller

package com.dragon.serviceedu.controller;

import com.dragon.commonutils.ResultCode;
import com.dragon.serviceedu.service.OssService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@Api(description="阿里云文件管理")
@Controller
@RestController("eduoss/fileoss")
@CrossOrigin
public class OssController {

    @Autowired
    private OssService ossService;

    //上传头像
    @ApiOperation(value = "文件上传")
    @PostMapping("upload")
    public ResultCode updateOssFile(MultipartFile file) {
        //获取上传文件,MultipartFile

        //返回上传到oss路径
        String url = ossService.updateFileAvatar(file);

        return ResultCode.ok().data("url",url);
    }
}

Nginx

tasklist /fi "imagename eq nginx.exe"  #查看启动了几个nginx
taskkill /fi "imagename eq nginx.exe" /f #杀死所有nginx

EasyExecl

EasyExcel特点

  • Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。
  • EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
  • EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。

实现EasyExcel对Excel写操作

1、导入依赖

        <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.1.1</version>
        </dependency>

还要对应一个poi依赖,这个在父类中导入过了
            <!--xls-->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>${poi.version}</version>
            </dependency>
            <!--xlsx-->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>${poi.version}</version>
            </dependency>

<poi.version>3.17</poi.version>

2、创建实体类

设置表头和添加的数据字段

@Data
public class DemoData {

    //设置Excel表头名称
    @ExcelProperty("学生编号")
    private Integer sno;

    @ExcelProperty("学生姓名")
    private String sname;
}

3、编写测试类,实现写出

package com.dragon.serviceedu.excel;

import com.alibaba.excel.EasyExcel;

import java.util.ArrayList;
import java.util.List;

public class TestEasyExcel {

    public static void main(String[] args) {
        //设置写入文件的地址,和文件的名称
        String fileName = "E:/write.xlsx";

        //EasyExcel,实现写的方法
        EasyExcel.write(fileName, DemoData.class).sheet("学生列表").doWrite(getData());
    }

    private static List<DemoData> getData() {
        List<DemoData> list = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            DemoData data = new DemoData();
            data.setSno(i);
            data.setSname("张" + i);
            list.add(data);
        }
        return list;
    }
}

实现Excel读操作

1、创建实体类

package com.dragon.serviceedu.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

@Data
public class DemoData {

    //设置Excel表头名称
    @ExcelProperty(value = "学生编号",index = 0)
    private Integer sno;

    @ExcelProperty(value = "学生姓名",index = 1)
    private String sname;
}

2、创建一个监听器

package com.dragon.serviceedu.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.dragon.serviceedu.excel.DemoData;

import java.util.Map;

public class ExcelListener extends AnalysisEventListener<DemoData> {
    //一行一行去读取excle内容
    @Override
    public void invoke(DemoData demoData, AnalysisContext analysisContext) {
        System.out.println("***"+demoData);
    }

    //读取excel表头信息
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头信息:"+headMap);
    }

    //读取完成后执行
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

3、实现读的功能

        //2、实现读的操作
        String fileName = "E:/write.xlsx";
        EasyExcel.read(fileName, DemoData.class, new ExcelListener()).sheet().doRead();

实现Excel读入数据库

1、创建对应实体类

@Data
public class SubjectData {
    //设置列对应的属性
    @ExcelProperty(index = 0)
    private String oneSubjectName;

    //设置列对应的属性
    @ExcelProperty(index = 1)
    private String twoSubjectName;
}

2、controller

@Api(description = "Excel上传")
@RestController
@RequestMapping("/serviceedu/subject")
@CrossOrigin
public class EduSubjectController {

    @Autowired
    private EduSubjectService subjectService;

    //添加课程分类
    //获取上传文件,把文件内容读取出来
    @PostMapping("addSubject")
    public ResultCode addSubject(MultipartFile file) {
        //上传过来的Excel文件
        subjectService.saveSubject(file,subjectService);

        return ResultCode.ok();
    }
}

3、service

public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService {

    //添加课程分类
    @Override
    public void saveSubject(MultipartFile file , EduSubjectService subjectService) {
        try {
            //文件输入流
            InputStream in = file.getInputStream();
            //调用方法进行读取
            EasyExcel.read(in, SubjectData.class, new SubjectExcelListener(subjectService)).sheet().doRead();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

4、创建监听器Listener

public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {

    //手动注入SubjectService
    public EduSubjectService subjectService;
    public SubjectExcelListener() {}
    public SubjectExcelListener(EduSubjectService subjectService) {
        this.subjectService = subjectService;
    }

    //一行一行去读取excle内容
    @Override
    public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
        if (subjectData == null) {
            throw new MyException(2001, "文件为空");
        }

        //一行一行读取,每次读取两个值,第一个值为一级分类,第二个值为二级分类
        //判断一级分类是否重复
        EduSubject existOneSubject = this.existOneSubject(subjectService, subjectData.getOneSubjectName());
        if (existOneSubject == null) { //没有相同一级分类,进行添加
            existOneSubject = new EduSubject();
            existOneSubject.setParentId("0");
            existOneSubject.setTitle(subjectData.getOneSubjectName());  //一级分类名称
            subjectService.save(existOneSubject);
        }

        //获取一级分类id值
        String pid = existOneSubject.getId();

        //添加二级分类
        //判断二级分类
        EduSubject existTwoSubject = this.existTwoSubject(subjectService, subjectData.getTwoSubjectName(), pid);
        if (existTwoSubject == null) {
            existTwoSubject = new EduSubject();
            existTwoSubject.setParentId(pid);
            existTwoSubject.setTitle(subjectData.getTwoSubjectName());  //一级分类名称
            subjectService.save(existTwoSubject);
        }
    }

    //读取excel表头信息
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头信息:"+headMap);
    }

    //判断一级分类不能重复添加
    private EduSubject existOneSubject(EduSubjectService subjectService,String name) {
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title", name);
        wrapper.eq("parent_id", "0");
        EduSubject oneSubject = subjectService.getOne(wrapper);
        return oneSubject;
    }

    //判断一级分类不能重复添加
    private EduSubject existTwoSubject(EduSubjectService subjectService,String name,String pid) {
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title", name);
        wrapper.eq("parent_id", pid);
        EduSubject TwoSubject = subjectService.getOne(wrapper);
        return TwoSubject;
    }
}

注意:这里应为Listener没有被spring接管,所以无法注入eduSubjectService,因此必须我们自己手动注入eduSubjectService。之后在保存数据库时,判断此标题是否重复。

阿里云视频点播

1、初始化

import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;

public class InitObject {
    public static DefaultAcsClient initVodClient(String accessKeyId, String accessKeySecret) throws ClientExcW3W35eption {
        String regionId = "cn-shanghai";  // 点播服务接入区域
        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        DefaultAcsClient client = new DefaultAcsClient(profile);
        return client;
    }
}

2、获取视频地址

	//获取视频地址
    public static void getPlayUrl() throws Exception {
        //1、根据视频id获取视频播放地址
        //创建初始化对象
        DefaultAcsClient client = InitObject.initVodClient("LTAI4G73PF2donPnup9AZ47q", "jVSBNUnjRKVaZRvr7mxumSn4I2HGin");

        //创建获取视频地址的request
        GetPlayInfoRequest request = new GetPlayInfoRequest();

        //向request中设置视频id
        request.setVideoId("5ec5b46c3551444cb6cccabcd2cff640");

        //调用初始化对象里面的方法,传递request,获取数据
        GetPlayInfoResponse response = client.getAcsResponse(request);

        List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();
        //播放地址
        for (GetPlayInfoResponse.PlayInfo playInfo : playInfoList) {
            System.out.print("PlayInfo.PlayURL = " + playInfo.getPlayURL() + "\n");
        }
    }

3、获取视频凭证

public static void main(String[] args) throws Exception {
        //根据视频id获取视频凭证
        //创建初始化对象
        DefaultAcsClient client = InitObject.initVodClient("LTAI4G73PF2donPnup9AZ47q", "jVSBNUnjRKVaZRvr7mxumSn4I2HGin");

        //创建获取视频地址的request
        GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();

        //设置视频id
        request.setVideoId("054182ab67a847f5b30da3726914a616");

        GetVideoPlayAuthResponse response = client.getAcsResponse(request);

        System.out.println("视频凭证:" + response.getPlayAuth());
    }

本地视频上传阿里云

package com.dragon.serviceedu.service.impl;

import com.aliyun.vod.upload.impl.UploadVideoImpl;
import com.aliyun.vod.upload.req.UploadStreamRequest;
import com.aliyun.vod.upload.resp.UploadStreamResponse;
import com.dragon.serviceedu.service.VodService;
import com.dragon.serviceedu.utils.ConstantVodUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;

@Service
public class VodSerivceImpl implements VodService {

    //上传到阿里云视频
    @Override
    public String uploadVideo(MultipartFile file) {

        try {
            //title上传之后显示的名称
            //subString截取 . 之前的文件名
            String title = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."));

            //inputStream上传文件流
            InputStream inputStream = file.getInputStream();

            UploadStreamRequest request = new UploadStreamRequest(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET,
                    title, file.getOriginalFilename(), inputStream);

            UploadVideoImpl uploader = new UploadVideoImpl();
            UploadStreamResponse response = uploader.uploadStream(request);

            //如果设置回调URL无效,不影响视频上传,可以返回VideoId同时会返回错误码。
            // 其他情况上传失败时,VideoId为空,此时需要根据返回错误码分析具体错误原因
            String videoId = null;
            if (response.isSuccess()) {
                videoId = response.getVideoId();
            } else {
                videoId = response.getVideoId();
            }
            return videoId;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

单点登录SSO(single sign on)

实现多模块共享同意用户。

实现的三种常见方式

  1. session广播机制实现【不推荐使用,如果模块多的话,复制的量太大】
  2. 使用cookie + redis实现
  3. 使用token实现**(自包含令牌)**
    • token是什么?按照一定规则生成字符串,字符串可以包含用户信息。

JWT

  • token是按照一定规则生成字符串,包含用户信息
  • 规则是怎么样的,不一定
  • 一般采用通用的规则,官方规则jwt

JWT就是给我们规定好了规则,使用JWT规则可以生成字符串,包含用户信息

OAuth2

OAuth2是什么?

OAuth2是针对特定问题的一种解决方案。主要可以解决两个问题:

  1. 开放系统间授权

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sk8vzObE-1652586714639)(C:/Users/hasee/AppData/Roaming/Typora/typora-user-images/image-20201231221549601.png)]

  2. 分布式访问问题

微信扫码登录

步骤:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G68UENiE-1652586714641)(C:/Users/hasee/AppData/Roaming/Typora/typora-user-images/image-20210102200802938.png)]

官方图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZbSi8CzU-1652586714642)(C:/Users/hasee/AppData/Roaming/Typora/typora-user-images/image-20210102200920276.png)]

定时任务 Scheduled

在固定时间执行代码。

  1. 启动类添加注解 @EnableScheduling //开启定时任务

  2. 创建定时任务类,使用cron表达式设置执行代码的时间,在方法上添加注解**@Scheduled**和cron表达式

    @Component
    public class ScheduleTask {
    
        // 每个5秒执行一次
        @Scheduled(cron = "0/5 * * * * ?")
        public void task() {
            System.out.println("ScheduleTask执行了.............");
        }
    }
    
  3. 在线生成cron表达式

    http://cron.qqe2.com/

ECharts

简介

ECharts是百度的一个项目,后来百度把Echart捐给apache,用于图表展示,提供了常规的折线图柱状图散点图饼图K线图,用于统计的盒形图,用于地理数据可视化的地图热力图线图,用于关系数据可视化的关系图treemap旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图仪表盘,并且支持图与图之间的混搭。

官方网站:https://echarts.apache.org

install

npm install --save echarts@4.1.0

canal数据同步工具

1、应用场景

在前面的统计分析功能中,我们采取了服务调用获取统计数据,这样耦合度高,效率相对较低,目前我采取另一种实现方式,通过实时同步数据库表的方式实现,例如我们要统计每天注册与登录人数,我们只需把会员表同步到统计库中,实现本地统计就可以了,这样效率更高,耦合度更低,Canal就是一个很好的数据库同步工具。canal是阿里巴巴旗下的一款开源项目,纯Java开发。基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了MySQL。

2、Canal环境搭建

canal的原理是基于mysql binlog技术,所以这里一定需要开启mysql的binlog写入功能

开启mysql服务: service mysql start

(1)检查binlog功能是否有开启

mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | OFF    |
+---------------+-------+
1 row in set (0.00 sec)

(2)如果显示状态为OFF表示该功能未开启,开启binlog功能

1,修改 mysql 的配置文件 my.cnf
vi /etc/my.cnf 
追加内容:
log-bin=mysql-bin     #binlog文件名
binlog_format=ROW     #选择row模式
server_id=1           #mysql实例id,不能和canal的slaveId重复
2,重启 mysql:
service mysql restart   
3,登录 mysql 客户端,查看 log_bin 变量
mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON|
+---------------+-------+
1 row in set (0.00 sec)
————————————————
如果显示状态为ON表示该功能已开启

(3)在mysql里面添加以下的相关用户和权限

CREATE USER 'canal'@'%' IDENTIFIED BY 'canal';
GRANT SHOW VIEW, SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;

3、下载安装Canal服务

下载地址:

https://github.com/alibaba/canal/releases

(1)下载之后,放到目录中,解压文件

cd /usr/local/canal

canal.deployer-1.1.4.tar.gz

tar zxvf canal.deployer-1.1.4.tar.gz

(2)修改配置文件

vi conf/example/instance.properties
#需要改成自己的数据库信息
canal.instance.master.address=192.168.44.132:3306
#需要改成自己的数据库用户名与密码
canal.instance.dbUsername=canal
canal.instance.dbPassword=canal
#需要改成同步的数据库表规则,例如只是同步一下表
#canal.instance.filter.regex=.*\\..*
canal.instance.filter.regex=guli_ucenter.ucenter_member

注:

mysql 数据解析关注的表,Perl正则表达式.
多个正则之间以逗号(,)分隔,转义符需要双斜杠(\\) 
常见例子:
1.  所有表:.*   or  .*\\..*
2.  canal schema下所有表: canal\\..*
3.  canal下的以canal打头的表:canal\\.canal.*
4.  canal schema下的一张表:canal.test1
5.  多个规则组合使用:canal\\..*,mysql.test1,mysql.test2 (逗号分隔)
注意:此过滤条件只针对row模式的数据有效(ps. mixed/statement因为不解析sql,所以无法准确提取tableName进行过滤)

(3)进入bin目录下启动

sh bin/startup.sh

next

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值