项目介绍

项目已开源gitee:

https://gitee.com/gdones/gd-webchart

技术选型

后端:SpringBoot(WEB)+ JWT + MyBatis-plus +MySql5.7 + Redis + SpringFileStroage
前端:Vue2.0 + ElementUI

技术难点

  1. 多端聊天(长链接的实现)- WebSocket
  2. 文件存储、消息的存储 - IO\Reids\Mysql
  3. 登录权限的验证(完整版登录功能)- JWT\行为验证码\拦截器、过滤器(SpringBoot)

后端框架的搭建

1. SpringBoot框架构建

1.下载工具

使用idea工具(企业版)
下载地址:https://www.jetbrains.com/idea/download/#section=windows
找破解工具破解

2.配置maven工具

下载地址:https://maven.apache.org/download.cgi

1.下载解压好配置环境变量:
配置mavne-》bin目录添加到path环境变量中



2. 修改maven的配置:

<?xml version="1.0" encoding="UTF-8"?><settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"><!-- jar包下载的位置  -->     <localRepository>F:\GjbSVN\maven仓库</localRepository><pluginGroups></pluginGroups><proxies></proxies><servers></servers><mirrors><!-- 修改mavn仓库的镜像资源位置 --><mirror><id>nexus-aliyun</id><mirrorOf>*,!jeecg,!jeecg-snapshots,!getui-nexus</mirrorOf><name>Nexus aliyun</name><url>http://maven.aliyun.com/nexus/content/groups/public</url></mirror> </mirrors><profiles></profiles></settings>

3.idea构建springBoot项目


此时会打开项目窗口,然后要进行idea的maven配置修改


完成后项目会从新下载相关的jar包,稍等片刻
接下来启动程序:

2. 网络接口的编写测试

controller类编写

/*** 模块名称:测试控制器类* 模块类型:Controller* 编码人:高靖博* 创建时间:2023/4/13* 联系电话:18587388612*/// 协议名称:// 服务器ip地址:服务端口号/资源地址
// http://localhost:9010/test/test1@RestController
@RequestMapping("/test")
public class TestController {// 只允许GET类型请求// 查询:GET  提交或加密: POST  修改:PUT  删除:DELETE@GetMapping("/test1")public String test1(){return "<h1>只因你太美!</h1>";}// 返回值类型只要不是String,都会将对象转换为json数据返回到前端@GetMapping("/test2")public MyResult test2(){return new MyResult();}}

3.SpringBoot集成MyBatis-plus

1.打开pom.xml引入依赖

<!-- 新:版本升级 mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><!-- freemarker-模板引擎 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><!-- mp代码生成器 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><!-- mysql驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.21</version></dependency>
<!-- 阿里fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.80</version></dependency>

2. 配置mybatis-plus

在resources目录下,将application.properties文件删除改为application.yml文件

# 修改springBoot端口号
server:port: 9010# mybatis-plus相关内容
mybatis-plus:#dto别名映射 !!!!!!!需要修改type-aliases-package: com.webchartserver#xml文件路径映射(xml文件要和接口文件同名)!!!!!!!需要修改mapper-locations: com/webchartserver/**/dao/mapper/**.xmlconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启日志(需要引入log4j日志框架)map-underscore-to-camel-case: false# 全局变量配置# 逻辑删除-如:每个表中都有一个通用的字段isDelete描述当前数据是否被删除,1:已删除 0:未删除global-config:db-config:# 当逻辑删除应该设置什么值:1logic-delete-value: 1logic-not-delete-value: 0logic-delete-field: isDelete # 所有表中都要有一个isDelete字段且字段类型是int类型

3.编写一个代码生成工具

package com.webchartserver.core.mpganer;import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;/*** 模块名称:* 模块类型:* 编码人:高靖博* 创建时间:2023/4/13* 联系电话:18587388612*/
public class MyBatisGer {// 数据库的连接 !!!需要修改private final static String URL = "jdbc:mysql://localhost:3306/webchart?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai";// 数据库用户名private final static String USER_NAME = "root";// 数据库密码private final static String PWD = "cxk666";// 每个类作者的名字private final static String AUTHOR = "GaoJingBo";// 生成的代码输出的目录private final static String OUT_PUT_DIR = "D://mybatis";// 修改根包路径private final static String PARENT_PACKAGE_NAME = "com.webchartserver";// 业务模块名private final static String PARENT_MODEL_NAME = "user";// 要生成的业务表private final static String TABLE_NAME = "t_user";// 如果表名有前缀可以去除前缀private final static String PREFIX = "t_";public static void main(String[] args) {FastAutoGenerator.create(URL, USER_NAME, PWD).globalConfig(builder -> {builder.author(AUTHOR) // 设置作者.fileOverride() // 覆盖已生成文件.dateType(DateType.ONLY_DATE)// 日期类型.commentDate("yyyy-MM-dd") //公共默认日期格式.outputDir(OUT_PUT_DIR); // 指定输出目录}).packageConfig(builder -> {builder.parent(PARENT_PACKAGE_NAME) //设置父路径根包.moduleName(PARENT_MODEL_NAME) //设置模块名称.entity("dto") //dto实体.service("service") //业务接口.serviceImpl("service.impl") //业务实现.mapper("mapper") //mybatis-plus-mapper接口.xml("mapper.xml") mybatis-plus-mapper接口映射xml.controller("controller") //控制器.other("other");}).strategyConfig(builder -> {builder.controllerBuilder().enableHyphenStyle().enableRestStyle();builder.mapperBuilder().enableMapperAnnotation();builder.entityBuilder().enableLombok().logicDeleteColumnName("isDelete")// 逻辑删除表字段名.logicDeletePropertyName("isDelete")// 逻辑删除实体属性名// 添加填充规则.addTableFills(new Column("insertTime", FieldFill.INSERT)).addTableFills(new Column("updateTime", FieldFill.INSERT_UPDATE)).idType(IdType.NONE);builder.addInclude(TABLE_NAME) // 设置需要生成的表名.enableSkipView()//跳过视图.addTablePrefix(PREFIX); // 设置过滤表前缀}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();}
}

4. 准备一个数据表,进行代码生成

用户信息表

用户信息表-ER图

CREATE TABLE `t_user`  (`userID` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户id',`insertID` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录插入者帐号',`insertIP` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录插入者IP',`updateTime` datetime(0) NULL DEFAULT NULL COMMENT '记录更新时间',`updateID` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录更新者帐号',`updateIP` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录更新者IP',`isDelete` int(11) NULL DEFAULT 0 COMMENT '是否删除',`comment` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',`code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '编号',`realName` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '真实姓名',`nickName` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',`sex` int(11) NULL DEFAULT NULL COMMENT '性别:1:男 2:女 3:保密',`tellNumber` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号码',PRIMARY KEY (`userID`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

5. SpringBoot集成数据源连接池-阿里巴巴druid

数据库连接池的作用:

  1. 减少创建连接的io过程
  2. 使用连接的方式更简单,管理也更加简单
  3. 满足高并发场景下重复读写创建连接的业务

1.引入依赖

<!-- 数据源依赖 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version></dependency>

2. 在application.yml中配置druid连接池

# spring框架配置
spring:# 数据源配置datasource:# druid连接池type: com.alibaba.druid.pool.DruidDataSource# mysql驱动driver-class-name: com.mysql.cj.jdbc.Driver# 数据库连接地址 !!!! 需要修改url: jdbc:mysql://localhost:3306/webchart?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai# 用户名、密码username: rootpassword: cxk666# druid连接池配置# 初始化连接池最大值,连接中活跃数量最大值initial-size: 10max-active: 8# 获取连接等待的最长时间(毫秒)max-wait: 60000# 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。test-while-idle: true# 既作为检测的间隔时间又作为testWhileIdel执行的依据time-between-eviction-runs-millis: 60000# 销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接(配置连接在池中的最小生存时间)min-evictable-idle-time-millis: 30000# 用来检测数据库连接是否有效的sql 必须是一个查询语句(oracle中为 select 1 from dual)validation-query: select 1 from dual# 申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为truetest-on-borrow: false# 归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为truetest-on-return: false# 是否缓存preparedStatement, 也就是PSCache,PSCache对支持游标的数据库性能提升巨大,比如说oracle,在mysql下建议关闭。pool-prepared-statements: false# 置监控统计拦截的filters,去掉后监控界面sql无法统计,stat: 监控统计、Slf4j:日志记录、waLL: 防御sqL注入filters: stat,wall,slf4j# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100max-pool-prepared-statement-per-connection-size: -1# 合并多个DruidDataSource的监控数据use-global-data-source-stat: true# 通过connectProperties属性来打开mergeSql功能;慢SQL记录connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000web-stat-filter:# 是否启用StatFilter默认值trueenabled: true# 添加过滤规则url-pattern: /*# 忽略过滤的格式exclusions: /druid/*,*.js,*.gif,*.jpg,*.png,*.css,*.icostat-view-servlet:# 是否启用StatViewServlet默认值trueenabled: true# 访问路径为/druid时,跳转到StatViewServlet !!!! 需要修改url-pattern: /druid/*# 是否能够重置数据reset-enable: false# 需要账号密码才能访问控制台,默认为rootlogin-username: adminlogin-password: 123456# IP白名单allow: 127.0.0.1# IP黑名单(共同存在时,deny优先于allow)deny:

启动项目,测试druid连接池是否正常:

http://localhost:9010/druid/index.html

4.SpringBoot+MP的低代码CRUD

package com.webchartserver.user.controller;import com.webchartserver.core.dto.MyResult;
import com.webchartserver.user.dto.User;
import com.webchartserver.user.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;/**** 用户信息管理* @author GaoJingBo* @since 2023-04-13*/
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {// 注入业务层实现@Resource(name = "userServiceImpl")private IUserService userService;/*** 用户添加* @param user 要添加的用户信息* @return*/@PostMapping("/add")public MyResult add(@RequestBody User user){log.debug("-- 添加用户");MyResult result = new MyResult();boolean save = userService.save(user);result.setMsg("用户注册成功!");return result;}/*** 修改用户* @param user 要修改的用户信息(前端需要传递要修改的主键字段值)* @return*/@PutMapping ("/update")public MyResult update(@RequestBody User user){log.debug("-- 修改用户");MyResult result = new MyResult();boolean save = userService.updateById(user);result.setMsg("用户修改成功!");return result;}/*** 删除用户* @param pkID 传递主键字段值* @return*/@DeleteMapping ("/deletes")public MyResult deletes(String pkID){log.debug("-- 删除用户");MyResult result = new MyResult();boolean b = userService.removeById(pkID);result.setMsg("删除成功!");return result;}}

5. SpringBoot整合WebSocket

1. 引入webSocket依赖

<!-- 服务端WebSocket需要的依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>

2. 编写一个WebSocket服务配置类

搭建一个webSocket服务端

package com.webchartserver.core.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** 模块名称: 开启WebSocket服务* 模块类型:* 编码人:高靖博* 创建时间:2023/4/14* 联系电话:18587388612*/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}

创建一个消息转发的业务类

package com.webchartserver.core.config;import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;/*** 模块名称:WebSocket-聊天程序消息转发处理类* 模块类型:* 编码人:高靖博* 创建时间:2023/4/14* 联系电话:18587388612*/
@Component
@ServerEndpoint("/wxserver/{wxNumber}")
// ws://loaclhost:9010/wxserver
public class WebSocket {static{System.out.println("-------------------------------------------------");System.out.println("--------------WebSocket服务初始化------------------");System.out.println("-------------------------------------------------");}// 当前客户端的会话对象private Session session;// 当前客户端的微信号private String nowWxNumber;// 用来存在线连接用户信息( 线程安全 )// key: 微信号  value: 每个客户端的session对象private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<String,Session>();// 保存每一个连接的客户端对象(在线客户端)private static CopyOnWriteArraySet<WebSocket> webSockets =new CopyOnWriteArraySet<>();/*** 当客户端连接时会触发该方法*/@OnOpenpublic void onOpen(Session session,@PathParam("wxNumber") String wxNumber){System.err.println("---客户端连接!");sessionPool.put(wxNumber,session);this.session = session;this.nowWxNumber = wxNumber;webSockets.add(this);}/*** 当客户端发送消息给服务器时触发* @param msg 客户端发送给服务器的数据内容*/@OnMessagepublic void onMsg(String msg){System.err.println("客户端发送消息:"+msg);// 遍历所有已连接到服务器的集合进行挨个发送信息for(WebSocket webSocket:webSockets){// 判断客户端是否断开连接if(webSocket.session.isOpen()==true){// 还在线webSocket.session.getAsyncRemote().sendText(msg);}}}/*** 客户端断开连接时触发*/@OnClosepublic void onClose(){System.err.println("--客户端断开连接");}/*** 当客户端发送消息或服务器端出现异常时触发* @param e*/@OnErrorpublic void onErr(Throwable e){e.printStackTrace();System.err.println("--WebSocket异常!!!!");}}

前端测试

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>测试</title><style>/* 历史信息窗口样式 */.hsDiv{border:1px solid black;border-radius: 11px;width: 100%;height: 500px;overflow: auto;box-sizing: border-box;padding: 8px;}/* 消息的时间文字样式 */.time{font-size: 10px;color:gray;}/* 消息的文字内容样式 */.msgText{color:blue;}/* 发送人信息 */.person{font-size: 7px;color:black;   }</style>
</head>
<body><span id="state">离线</span><span id="qqNumber"></span><input id="nickName" placeholder="定义一个你的昵称" /><button onclick="toConect()">连接</button><hr/><button onclick="sendMsg()">发送</button><input id="msg" placeholder="请输入消息...." /><hr/><!-- 历史信息框体 --><div class="hsDiv" id="hsDiv"></div></body><script>
var qqNumber;var webScoket;var htmls = ""; // 所有历史信息htmlvar nikeName = ""; // 客户端昵称// 连接到服务器
function toConect(){// 生成一个唯一的数字qqNumber  = parseInt(Math.random()*10000000000000);webScoket = new WebSocket("ws://localhost:9010/wxserver/"+qqNumber);// 定义一个连接成功的回调函数webScoket.onopen = function (){console.dir("-连接成功!");document.getElementById("state").innerHTML = "在线";document.getElementById("qqNumber").innerHTML = qqNumber;// 获取连接的昵称信息var nikeNames = document.getElementById("nickName").value;nikeName = nikeNames;}// 定义一个服务器发送消息给客户端的回调函数webScoket.onmessage = function(data){console.dir("-接收到消息:"+data.data);// QQ信息$消息内容$发送时间$昵称var msgArr = data.data.split("$");htmls += '<span class="time">时间:'+msgArr[2]+'</span><br/>'+'<span class="person">['+msgArr[3]+']</span><br/>'+'<span class="msgText">'+msgArr[1]+'</span>'+'<hr/>';// 动态html代码段添加进入聊天历史信息框中document.getElementById("hsDiv").innerHTML = htmls;}}// 发送消息方法
function sendMsg(){// 得到要发送的信息文字var msg = document.getElementById("msg").value;//  发送消息的格式:// QQ信息$消息内容$发送时间$昵称var nowDate = new Date();var sendMsgStr = qqNumber+"$"+msg+"$"+(nowDate.getFullYear() +"-"+nowDate.getMonth()+"-"+nowDate.getDate()+" "+nowDate.getHours()+":"+nowDate.getMinutes()+":"+nowDate.getSeconds()+"$"+nikeName)webScoket.send(sendMsgStr); // 消息发送给服务器了}</script></html>

前端框架搭建

1. npm、cnpm node环境搭建vue脚手架

1. 安装node.js环境

1.进入官网

https://nodejs.org/en/

2.安装msi,安装目录到C盘

安装好后,使用cmd执行 node- v npm -v看看是否都输出了版本号

3.在除C盘外创建一个nodejsFile文件夹,创建两个文件夹 node_global和node_cache,然后运行以下命令

npm config set prefix "D:\Program Files\nodejs\node_global"
npm config set cache "D:\Program Files\nodejs\node_cache"

4.检查当前系统变量中,path路径有没有叫C:\ProgramFiles\nodejs\node_modules

如果有,创建一个同名路径文件夹在C盘之外的盘符,如果没有就不用管了

  1. 在path变量中配置你的C:\Program Files\nodejs\node_modules路径

2. 安装淘宝镜像 cnpm

功能:和npm一样,npm是从海外镜像仓库下载,cnmp 是从阿里淘宝镜像仓库下载

npm install -g cnpm --registry=https://registry.npm.taobao.org

安装完成使用:cnpm -v 查看版本

3.安装webpack

npm install webpack -g

安装完成使用:npm webpack -v 查看版本

4. 下载vue脚手架

1.下载脚手架资源

cnpm install -g vue-cli@2.x

2.去到你的gloab目录查看是否有vue开头的文件

  1. 到别的文件夹下创建一个空的文件夹,在文件夹中按住shift+鼠标右键,点击在此处打开pwershell窗口
  1. 打开窗口输入:vue init webpack

5.初始化构建vue脚手架


6.运行vue项目

在项目根目录下按住shift+鼠标右键,点击在此处打开pwershell窗口,执行 npm run dev

2. vue项目中安装axios组件(ajax组件)

1.在项目目录下使用cmd执行

//1. 在项目窗口中执行
cnpm install axios


代表安装成功

2.main.js配置导入相关组件

import axios from 'axios'
Vue.prototype.$axios = axios //全局属性

3. 编写一个请求工具类

作用: 封装关于http请求和响应处理的代码

// 1. 导入axios组件
import axios from "axios";// 导入el组件
import ElementUI from 'element-ui'// 导入路由组件
import router from '@/router'const service = axios.create({// get post delete putbaseURL:'/api',  // 后端服务地址timeout:30000 // 请求超时时间
});// http request 请求拦截器
service.interceptors.request.use(config => {// 需要所有的请求都带有tokenconfig.headers.token = window.localStorage.getItem("token");return config;
}, error => {// 对请求错误做些什么return Promise.reject(error);});// 响应拦截器
service.interceptors.response.use(response => {// 当后端返回数据或者后端请求错误,我们需要处理相关内容if(response.status==200){// 请求发送响应成功if(response.data.code=="-1"){// 认证失败ElementUI.Notification.error({title: '系统异常',message: response.data.msg+",请重新登录"});router.push("/");}else if(response.data.code=="200"){if(response.data.msg){ElementUI.Message.success(response.data.msg);}}else if(response.data.code=="500"){ElementUI.Message.error(response.data.msg);}return response.data;}else{ElementUI.Notification.error({title: '系统异常',message: error.response.data.msg+",请联系管理员"});return response.data;}});export default service;

4.设置跨域请求问题


在vue中配置一个代理注册工具

3. 使用VSCode构建Vue项目

下载VsCode

https://code.visualstudio.com/

组件下载


创建vue项目

  1. 创建一个空的项目文件夹
  2. 使用vsCode打开这个文件夹
  3. 设置vsCode语言:ctrl+shift+P 输入指令:Display language 先选择英文重启后再选择中文再重启就好了
  4. 打开终端
vue init webpack

会出现错误:not promite 。。。。 vsCode终端控制台没有系统写入权限

使用本机自带的cmd窗口使用管理员权限启动

将目录跳转至项目路径再执行vue init webpack指令

5.启动项目

npm run dev

6.退出运行

ctrl+c

4. 编写第一个vue文件

<!-- Dom页面 -->
<template><!-- 所有的页面元素都要卸载div之内 --><div id='UserIndex'></div>
</template><!-- 组件js -->
<script>
export default {name:'UserIndex',data(){}
}
</script><!-- CSS代码 -->
<style scoped></style>

使用VSCode创建一个自定义代码片段

文件–》首选项—》配置用户代码片段

{"Print to console": {"prefix": "myvue",// 代码段名称"body": [ //代码内容"<!-- Dom页面 -->","<template>","<div id=''>","","</div>","</template>","","<!-- 组件js -->","<script>","export default {","name:'',","data(){","","}","}","</script>","","<!-- CSS代码 -->","<style scoped>","","</style>"],"description": "myvue"}
}

业务实现部分

1.用户注册与登录

1.用户注册功能

后端部分代码

  1. 后端接收到注册信息,需要将密码进行MD5加密
    引入hutool工具包加密方法加密
<!-- hutool工具 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.15</version></dependency>
  1. 注册controller 方法修改
@PostMapping("/add")public MyResult add(@RequestBody User user){log.debug("-- 注册用户");MyResult result = new MyResult();// 密码加密String pwd_md5Hex = DigestUtil.md5Hex(user.getPwd());user.setPwd(pwd_md5Hex);boolean save = userService.save(user);result.setMsg("用户注册成功!");return result;}

2.用户登录功能

后端代码部分

前端传递了明文的密码需要将明文密码加密后用密文去比对数据库

@PostMapping("/login")public MyResult login(@RequestBody User user){log.debug("-- 登录");MyResult result = new MyResult();// 1. 查询数据库中和用户名相同的数据QueryWrapper<User> queryWrapper = new QueryWrapper<>(); // from t_user// where nickName = ""queryWrapper.eq("nickName",user.getNickName());// 2. mp 查询   select * from t_user where nickName = "user.getNickName()"List<User> list = userService.list(queryWrapper);if(list.size()>0){ // 用户名存在User dbUserData = list.get(0);String pwdMD5 = dbUserData.getPwd();// 取出数据库中保存的密码-密文String pwd_md5Hex = DigestUtil.md5Hex(user.getPwd()); // 将前端的明文密码加密比较if(pwd_md5Hex.equals(pwdMD5)){ // 密码输入正确result.setCode(200);result.setMsg("登录成功!");}else{ // 密码输入错误result.setCode(500);// 已错误次数累加1dbUserData.setErrCount(dbUserData.getErrCount()+1);// 剩余几次可以输入密码的机会 = errCount - 已错误的次数int lessCount  = errCount - dbUserData.getErrCount();// 判断是否需要锁定if(lessCount<=0){ //需要锁定dbUserData.setIsLock(1); // 设置账号锁定// 返回错误信息给前端result.setMsg("错误次数过多,账号已锁定!");}else{result.setMsg("用户名或密码错误,还剩【"+lessCount+"】次机会!");}// 更新数据库userService.updateById(dbUserData);}}else{// 用户名不存在result.setCode(500); // 业务编码500描述业务不成功result.setMsg("用户名或密码错误!");}

2. 实现系统鉴权功能

验证用户是否已经完成了登录,只有用户正常登录之后才能访问系统当中的接口

1.实现方法使用JWT框架

1. 引入jwt依赖

<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.19.0</version></dependency>

2. 创建一个JWT工具类

作用:生成token和验证token功能

package com.webchartserver.core.config;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;import java.util.Date;/*** 模块名称:JWT权限验证工具包* 模块类型:* 编码人:高靖博* 创建时间:2023/4/14* 联系电话:18587388612*/
public class JWTUtil {private JWTUtil(){}// 过期时间,单位秒private static final long EXP_TIME = 60 * 30L;// 秘钥关键字private static final String SECRET = "webchart";/*** 生成token* @param userName 登录用户名* @return*/// 生成token时,需要添加token信息// userName : 签名信息,保证token无法重复或者无法被篡改public static String getToken(String userName){// 创建Token构造器JWTCreator.Builder builder = JWT.create();//设置过期时间,设置什么时候过期:EXP_TIME计算一个过期的日子Date date = new Date(System.currentTimeMillis() + EXP_TIME * 1000);//创建tokenString sign = builder.withExpiresAt(date).withClaim("userName", userName).withClaim("claimDate", new Date().getTime()).sign(Algorithm.HMAC256(SECRET));return sign;}/*** 验证签名token* @param token* @return*/public static boolean verify(String token){try{DecodedJWT verify = JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);System.out.println("------- [token认证通过] ---------");System.out.println("------- userName:"+verify.getClaim("userName")+" ---------");System.out.println("------- 过期时间:"+verify.getExpiresAt()+" ---------");return true;}catch (Exception e){return false;}}
}

3.创建一个拦截器拦截业务请求去验证token是否有效

  1. 编写一个验证token的拦截器

package com.webchartserver.core.intercetes;import com.alibaba.fastjson.JSON;
import com.webchartserver.core.config.JWTUtil;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;/*** 模块名称:是否登录过的拦截器(用于验证token是否有效)* 模块类型:拦截器* 编码人:高靖博* 创建时间:2023/4/14* 联系电话:18587388612*/
public class LoginInterceptor implements HandlerInterceptor {// 请求访问controller方法之前会指向性/**** @param request http请求对象* @param response http响应对象* @param handler 执行链路对象* @return 返回值: true: 拦截器放行 false:拦截器阻止* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {response.setCharacterEncoding("UTF-8");response.setContentType("application/json; charset=utf-8");// 所有的token都要放在请求头中  headerString token = request.getHeader("token");//验证if(token==null||token==""){Map<String,String> json = new HashMap<>();json.put("msg","认证失败,token不存在!");json.put("code","-1");PrintWriter writer = response.getWriter();writer.write(JSON.toJSONString(json));writer.flush();writer.close();return false;}else{// 验证boolean verify = JWTUtil.verify(token);if(verify){return true;}else{Map<String,String> json = new HashMap<>();json.put("msg","认证失败!");json.put("code","-1");PrintWriter writer = response.getWriter();writer.write(JSON.toJSONString(json));writer.flush();writer.close();return false;}}}
}
  1. 配置注册拦截器
    规定那些地址会被拦截,哪些地址可以放行
package com.webchartserver.core.intercetes;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 模块名称:配置注册拦截器类* 模块类型:配置类* 编码人:高靖博* 创建时间:2023/4/14* 联系电话:18587388612*/
@Configuration
public class InterceptConfig implements WebMvcConfigurer {//注册拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册自定义的登录拦截器InterceptorRegistration ic = registry.addInterceptor(new LoginInterceptor());// 设置要拦截的路径有哪些ic.addPathPatterns("/**"); // 所有请求服务端的路径地址都会被拦截// 设置拦截器白名单ic.excludePathPatterns("/user/login/**", // 登录接口不需要拦截"/js/**", // 访问数据监控中心不需要拦截"/css/**","/imgs/**","/druid/**","/v2/**","/webjars/**");}
}
  1. 修改登录接口,当登录成功时从服务器返回一个token令牌
if(pwd_md5Hex.equals(pwdMD5)){ // 密码输入正确result.setCode(200);result.setMsg("登录成功!");// 要返回token令牌到前端String token = JWTUtil.getToken(user.getNickName());result.setData(token);

postman测试

3. 好友列表的添加和历史信息的记录

1. 建表语句


CREATE TABLE `t_user_f`  (`infoID` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '记录主键',`insertID` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录插入者帐号',`insertIP` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录插入者IP',`updateTime` datetime(0) NULL DEFAULT NULL COMMENT '记录更新时间',`updateID` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录更新者帐号',`updateIP` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录更新者IP',`isDelete` int(11) NULL DEFAULT 0 COMMENT '是否删除',`comment` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',`userID` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户id',`fUserID` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '好友用户id',`fNickName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '好友昵称(用户名)',`fRealName` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '好友真实姓名',PRIMARY KEY (`infoID`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;CREATE TABLE `t_msg`  (`infoID` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '记录id',`insertID` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录插入者帐号',`insertIP` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录插入者IP',`updateTime` datetime(0) NULL DEFAULT NULL COMMENT '记录更新时间',`updateID` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录更新者帐号',`updateIP` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '记录更新者IP',`isDelete` int(11) NULL DEFAULT 0 COMMENT '是否删除',`comment` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',`sendUserID` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '发送人的用户id',`sendNickName` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '发送人的用户名',`saveUserID` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '接收人的用户id',`saveNickName` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '接收人的用户名称',`msg` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '消息内容',`saveAndSendTime` datetime(0) NULL DEFAULT NULL COMMENT '接收消息时间',PRIMARY KEY (`infoID`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

使用mp代码生成

4. 实现聊天的敏感信息过滤

自定义工具类

package com.webchartserver.core.utils;import cn.hutool.core.collection.ConcurrentHashSet;
import org.springframework.stereotype.Component;import java.io.*;/*** 敏感信息过滤* 2023/4/18*/
@Component
public class FilterWordsUtil {private FilterWordsUtil(){}// 敏感词汇集合private static ConcurrentHashSet<String> wordsSet = new ConcurrentHashSet<>();// 初始化加载敏感词汇static{System.out.println("------------敏感词汇过滤工具加载-------------------");loadTextFile();}/*** 加载敏感词汇文件*/private static void loadTextFile(){try {InputStream resourceAsStream = FilterWordsUtil.class.getResourceAsStream("filterword.txt");Reader reader = new InputStreamReader(resourceAsStream);BufferedReader bufferedReader = new BufferedReader(reader);String line;while ((line = bufferedReader.readLine()) != null) {wordsSet.add(line);}bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}/*** 替换敏感字符* @param words 原字符串* @param replaceStr 替换的文本* @return*/public static String changeWord(String words,char replaceStr){for(String mgStr:wordsSet){if(words.indexOf(mgStr)!=-1){// 根据敏感词的长度生成*int length = mgStr.length();String repStr = "";for(int i=0;i<length;i++){repStr += replaceStr;}words = words.replaceAll(mgStr,repStr);}}return words;}}

5.前端实现表情包的选择和发送

mysql配置可以存放unicode字符文字

[client]
default-character-set = utf8mb4[mysql]#设置mysql客户端默认字符集default-character-set = utf8mb4[mysqld]
#服务端使用的字符集默认为8比特编码的latin1字符集character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect='SET NAMES utf8mb4'

重启mysql服务

【项目实战】- 基于SpringBoot+WebScoket+Vue+ElementUI实现一个网页版地球聊天软件相关推荐

  1. vue企业项目demo_基于SpringBoot和Vue的企业级中后台开源项目

    简介: 项目简介 SpringBoot和Vue,前后端分离,我们开源一套漂亮的代码和一套整洁的代码规范,让大家在这浮躁的代码世界里感受到一股把代码写好的清流!同时又让开发者节省大量的时间,减少加班,快 ...

  2. 基于 SpringBoot + Vue 框架开发的网页版聊天室项目

    ‍ ‍简介 微言聊天室是基于前后端分离,采用SpringBoot+Vue框架开发的网页版聊天室.使用了Spring Security安全框架进行密码的加密存储和登录登出等逻辑的处理,以WebSocke ...

  3. 基于Springboot和VUE的聊天项目,仿PC端微信

    项目介绍 仿PC微言聊天室是基于前后端分离,采用SpringBoot+Vue框架开发的网页版聊天室. 使用了Spring Security安全框架进行密码的加密存储和登录登出等逻辑的处理,以WebSo ...

  4. SpringBoot实现代码生成器——基于SpringBoot和Vue的后台管理系统项目系列博客(十)

    系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...

  5. SpringBoot实现1对1、1对多、多对多关联查询——基于SpringBoot和Vue的后台管理系统项目系列博客(十八)

    系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...

  6. SpringBoot和Vue集成Markdown和多级评论——基于SpringBoot和Vue的后台管理系统项目系列博客(二十三)

    系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...

  7. SpringBoot实现分页查询——基于SpringBoot和Vue的后台管理系统项目系列博客(七)

    系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...

  8. 基于Springboot+Mybatisplus+Vue的科研项目管理系统

    基于Springboot+Mybatisplus+Vue的科研项目管理系统 1.1 项目概述 开发语言:Java8 数据库:Mysql5 前端技术:bootstrap 后端框架:Springboot ...

  9. java基于springboot+nodejs+vue网上投标招标系统ssm项目介绍

    在网络技术的快速前行和生活水平的逐步提高的背景下,投标招标的方式已经有了革命性的变化,即由以往的多人员手工手动作业转换为在互联网上的实时的人员操作.网上投标招标系统不光是操作快捷.省时.省力,而且实现 ...

最新文章

  1. C功底挑战Java菜鸟入门概念干货(一)
  2. python函数(三)
  3. 基于FPGA的目标点的提取与定位系统设计
  4. 小黑小波比.Ubuntu下的截图
  5. 【GitLab】与idea的搭配
  6. 第二学期-第一次作业
  7. 二叉树---树的深度递归理解
  8. 在Silverlight中使用DynamicMethod(动态方法)
  9. linux/windows下查看目标文件.a/.lib的函数符号名称
  10. 写得蛮好的linux学习笔记[转]
  11. linux的vi命令详解,linux vi命令详解
  12. JavaScript 中URL编码方式
  13. 小球弹跳及MATLAB实现
  14. 人机对战初体验—四子棋游戏
  15. 中国历史各王朝的知识点总结记忆
  16. 浏览器-点击预览视频文件(自动播放、循环播放)
  17. NB-IoT下行链路简单实现
  18. 配置数据源失败:未指定“url”属性,无法配置嵌入的数据源。
  19. exploit-db图文教程
  20. Springboot中Bean的具体含义

热门文章

  1. img图片没找到onerror事件 Stack overflow at line: 0
  2. Python3+Robot Framework+RIDE安装使用教程
  3. 压缩加压 linux 命令,linux下tar加压、压缩命令
  4. OpenGL粒子系统详解及编程实现
  5. ajax布林德,GIF-这哪是角球!简直是巡航导弹 布林德一战成神
  6. win10重置进度条不动了_win10系统更新进度条不动了的解决方法
  7. spool for oracle
  8. 优思学院|六西格玛的意义是什么?
  9. 通过js在控制台输出彩色字体和placeholder的样式设置(记录)
  10. 职场中,宁可装傻,也不要自作聪明!