企业开发中,往往将常见工具类封装抽取,以简洁便利的方式供其他工程模块使用。而SpringBoot的自动装配机制可以方便的实现组件抽取。SpringBoot执行流程如下
-
扫描依赖模块中META-INF/spring.factories
-
执行装配类中方法
-
对象存入容器中
-
核心工程注入对象,调用方法使用
配置类
模块创建配置信息类SmsProperties
发送短信模板对象
>模块创建模板对象发送信息
自动装配类
模块创建自动装配的配置类
自动装配配置
根据自动装配原则,在模块创建文件
测试
工程加入短信配置
工程编写单元测试类
正常的企业开发返回值一般会有一个对象来包裹,这个对象叫做ResponseEntity,这个对象是Spring提供的返回值对象
JSON Web token简称JWT, 是用于对应用程序上的用户进行身份验证的标记。也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据。此特性便于可伸缩性, 同时保证应用程序的安全
格式
-
JWT就是一个字符串,经过加密处理与校验处理的字符串,形式为:A.B.C
-
A由JWT头部信息header加密得到
-
B由JWT用到的身份验证信息json数据加密得到
-
C由A和B加密得到,是校验部分
官方网站:JSON Web Tokens - jwt.io
流程
示例
导入依赖:
编写测试用例:
通过解析Token得知,如果抛出SignatureException异常表示token不合法,如果抛出ExpiredJwtException异常表示token已过期
设置密钥和生成密钥一致
JWT工具类
模块创建JWT工具类
可能存在的问题
序列化异常
注意 : Dubbo的传输需要将对象序列化为字节在网络上传输 , 实体类需要实现
为了简化实体类中created和updated字段,抽取BasePojo
对于created和updated字段,每次操作都需要手动设置。为了解决这个问题,mybatis-plus支持自定义处理器的形式实现保存更新的自动填充
哪个服务调用数据库哪个服务就要配置handler
创建Bucket
使用OSS,首先需要创建Bucket,Bucket翻译成中文是水桶的意思,把存储的图片资源看做是水,想要盛水必须得有桶,就是这个意思了。
进入控制台,https://oss.console.aliyun.com/overview
选择Bucket后,即可看到对应的信息,如:url消耗流量等 :
抽取模板工具
和发送短信类似,阿里云OSS也是采用自定义工具的形式进行封装
OssProperties
创建配置类
OssTemplate
创建模板对象
TanhuaAutoConfiguration
的加入配置
测试
tanhua-app-server加入配置内容,并测试
编写测试类
人脸识别(Face Recognition)基于图像或视频中的人脸检测分析和比对技术,提供对您已获授权前提下的私有数据的人脸检测与属性分析人脸对比人脸搜索活体检测等能力。灵活应用于金融泛安防零售等行业场景,满足身份核验人脸考勤闸机通行等业务需求
概述
地址:https://ai.baidu.com/tech/face
创建应用
按需创建应用
抽取模板工具
AipFaceProperties
中添加配置对象
spring中@Bean是可以不配合@Configuration单独使用的
加了@Configuration和不加有本质上有什么区别的?
当在配置类中一个@Bean 使用方法的方式引用另一个Bean如果不加注解就会重复加载Bean 如果加了@Configuration 则会在这里创建cglib代理,当调用@Bean方法时会先检测容器中是否存在
AipFaceTemplate
中创建AipFaceTemplate
TanhuaAutoConfiguration
模板类测试
tanhua-app-server加入百度AI的配置信息
编写单元测试类
@RequestHeader获取请求头信息
BeanUtils.copyProperties(userInfo,userinfoVo)只会copy同类型的属性!
在实际开发过程中经常可能会有实体类字段和客户端要求的返回数据字段 数量/类型/名称 不一致的情况,这种情况我们可以定义Vo对象 , 通过Vo对象封装数据返回给客户端
vo字段的字段名称和类型完全与接口文档保持一直 , 返回数据时, 我们需要把POJO对象中的数据, 复制到Vo中
每一个控制方法中都需要解析token , 获取当前用户id , 代码重复度比较高
-
重复性的登录验证
-
繁琐的token获取及解析
基于ThreadLocal + 拦截器的形式统一处理
拦截器(Interceptor)
-
是一种动态拦截方法调用的机制;
-
类似于Servlet 开发中的过滤器Filter,用于对处理器进行前置处理和后置处理。
ThreadLocal
-
线程内部的存储类,赋予了线程存储数据的能力。
-
线程内调用的方法都可以从ThreadLocal中获取同一个对象。
-
多个线程中ThreadLocal数据相互隔离
Threadlocal使用方法很简单
ThreadLocal工具类
定义ThreadLocal工具类,仅需要调用set方法即可将数据存入ThreadLocal中
定义拦截器
定义拦截器,在前置拦截方法preHandle中解析token并验证有效性,如果失效返回状态码401。如果有效,解析User对象,存入ThreadLocal中
注册拦截器
拦截器需要注册到MVC容器中
统一异常处理
软件开发过程中,不可避免的是需要处理各种异常,常见的形式就是逐层向上抛出,web层进行处理。使用try {...} catch {...}很方便就能对异常做到业务处理
-
冗余代码多,影响代码可读性
-
异常处理和业务代码耦合
SpringMVC提供了一套解决全局异常的处理方案,可以在代码无侵入的前提下完成异常处理。遵循逐层抛出,异常处理器统一处理的思路
项目中可能存在不可预知的各种异常,如:空指针,数组越界等。针对这类异常,可以直接在异常处理器中统一处理;
还有一类是可预知的错误,如图片不合法,验证码错误等等。这类错误也可以理解为业务异常,可以通过自定义异常类来处理;
业务异常对象
为了方便操作,将一些常见的业务错误封装到ErrorResult对象中
业务异常类
自定义业务异常类,针对业务错误之间抛出业务异常即可
异常处理器
UserInfoMapper
在中编写查询方法
配置分页插件
IPage是mybatisplus内置的分页配置bean!
引导类开启mybatis-plus分页插件支持
使用mybatis-plus的分页:
-
创建分页对象:Page,指定当前页和每页查询条数
-
基础查询:mapper.selectPage(page,查询条件)
-
自定义查询:Ipage 方法名称(Page对象,xxx查询条件)
MongoDB简介
对于社交类软件的功能,我们需要对它的功能特点做分析:
-
数据量会随着用户数增大而增大
-
读多写少
-
价值较低
-
非好友看不到其动态内容
-
地理位置的查询
-
……
针对以上特点,我们来分析一下:
-
mysql:关系型数据库(效率低)
-
redis:redis缓存(微博,效率高,数据格式不丰富,占用内存大)
-
对于数据量大而言,显然不能够使用关系型数据库进行存储,我们需要通过MongoDB进行存储
-
对于读多写少的应用,需要减少读取的成本
-
比如说,一条SQL语句,单张表查询一定比多张表查询要快
-
探花交友
-
mongodb:存储业务数据(圈子,推荐的数据,小视频数据,点赞,评论等)
-
redis:承担的角色是缓存层(提升查询效率)
-
mysql:存储和核心业务数据,账户
MongoDB:是一个高效的非关系型数据库(不支持表关系:只能操作单表)
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。
MongoDB最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
官网:https://www.mongodb.com
MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。具体特点总结如下:
-
面向集合存储,易于存储对象类型的数据
-
模式自由
-
支持动态查询
-
支持完全索引,包含内部对象
-
支持复制和故障恢复
-
使用高效的二进制数据存储,包括大型对象(如视频等)
-
自动处理碎片,以支持云计算层次的扩展性
-
支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl及C++语言的驱动程 序, 社区中也提供了对Erlang及.NET 等平台的驱动程序
-
文件存储格式为 BSON(一种 JSON 的扩展)
MYSQL : 用于存储安全性要求比较高的数据
REDIS : 存储数据格式简单 , 并且查询非常多的数据(用户缓存)
MONGDB : 用户存储海量数据, 并且数据的安全性要求不高
通过docker安装MongoDB
在课程资料的虚拟机中已经提供了MongoDB的镜像和容器,我们只需要使用简单的命令即可启动
可以看到mongoDB已经启动,对外暴露了27017的操作端口
MongoDB体系结构
MongoDB 的逻辑结构是一种层次结构。主要由: 文档(document) 集合(collection) 数据库(database)这三部分组成的。逻辑结构是面 向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。
-
MongoDB 的文档(document),相当于关系数据库中的一行记录。
-
多个文档组成一个集合(collection),相当于关系数据库的表。
-
多个集合(collection),逻辑上组织在一起,就是数据库(database)。
-
一个 MongoDB 实例支持多个数据库(database)。 文档(document) 集合(collection) 数据库(database)的层次结构如下图:
为了更好的理解,下面与SQL中的概念进行对比:
-
数据格式:BSON {aa:bb}
-
null:用于表示空值或者不存在的字段,{“x”:null}
-
布尔型:布尔类型有两个值true和false,{“x”:true}
-
数值:shell默认使用64为浮点型数值。{“x”:3.14}或{“x”:3}。对于整型值,可以使用 NumberInt(4字节符号整数)或NumberLong(8字节符号整数), {“x”:NumberInt(“3”)}{“x”:NumberLong(“3”)}
-
字符串:UTF-8字符串都可以表示为字符串类型的数据,{“x”:“呵呵”}
-
日期:日期被存储为自新纪元依赖经过的毫秒数,不存储时区,{“x”:new Date()}
-
正则表达式:查询时,使用正则表达式作为限定条件,语法与JavaScript的正则表达式相 同,{“x”:/[abc]/}
-
数组:数据列表或数据集可以表示为数组,{“x”: [“a“,“b”,”c”]}
-
内嵌文档:文档可以嵌套其他文档,被嵌套的文档作为值来处理,{“x”:{“y”:3 }}
-
对象Id:对象id是一个12字节的字符串,是文档的唯一标识,{“x”: objectId() }
-
二进制数据:二进制数据是一个任意字节的字符串。它不能直接在shell中使用。如果要 将非utf-字符保存到数据库中,二进制数据是唯一的方式。
在MongoDB中,存储的文档结构是一种类似于json的结构,称之为bson(全称为:Binary JSON)。
update() 方法用于更新已存在的文档。语法格式如下:
参数说明:
-
query : update的查询条件,类似sql update查询内where后面的。
-
update : update的对象和一些更新的操作符(如$,$inc.$set)等,也可以理解为sql update查询内set后面的
-
upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
-
multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
-
writeConcern :可选,抛出异常的级别。
通过remove()方法进行删除数据,语法如下:
参数说明:
-
query :(可选)删除的文档的条件。
-
justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
-
writeConcern :(可选)抛出异常的级别。
实例:
MongoDB 查询数据的语法格式如下:
-
query :可选,使用查询操作符指定查询条件
-
fields :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
条件查询:
实例:
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。
这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构
MongoDB 查询分析可以确保我们建议的索引是否有效,是查询语句性能分析的重要工具。
Spring-data对MongoDB做了支持,使用spring-data-mongodb可以简化MongoDB的操作,封装了底层的mongodb-driver。
地址:https://spring.io/projects/spring-data-mongodb
使用Spring-Data-MongoDB很简单,只需要如下几步即可:
-
导入起步依赖
-
编写配置信息
-
编写实体类(配置注解 @Document,@Id)
-
操作mongodb
-
注入MongoTemplate对象,完成CRUD操作
-
编写Repository接口,注入接口完成基本Crud操作
-
第一步,导入依赖:
第二步,编写application.yml配置文件
第三步,编写启动类
第一步,编写实体类
第二步,通过MongoTemplate完成CRUD操作
当我们在项目中引入了MongoDB依赖之后启动时会报如下错误
原因 : 实体类模块中引入了MongoDB的依赖,根据自动装配的原理 和中会自动查找默认MongoDB的地址(localhost:27017),而本地没有开启Mongo所以连接失败。
解决方案 : 和中排除掉MongoDB 自动配置类即可
同理 : 在项目中排除MongoDB 自动配置类即可
在的和中添加方法
TanhuaController
这里传递的是请求参数而不是请求体body参数,所有不需要RequestBody进行转化,但条件是dto属性名要和参数名保持一致
tanhua-dubbo-mongo
在模块的中实现查询推荐用户列表方法
tanhua-dubbo-db
在模块的中实现根据推荐用户id集合和条件查询用户信息的方法
CollUtill.fieldValueMap能够将list集合元素的某一个属性作为键值,元素作为值构造成一个Map集合
CollUtill.getFieldValues能够将list集合元素的某一个属性提取出来构造成一个新的list集合
在保存动态的时候需要有一个字段 , 该字段是一个唯一自增的值, 用于后期的动态推荐,但是Mongodb没有自增的机制,需要实现自增的方式有两种:Redis或者MongoDB
IdWorker工具类
在中配置工具类IdWorker
注入IdWorker,调用内部的getNextId即可获取唯一的数字ID
MovementController
@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的);
GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。
在后端的同一个接收方法里,@RequestBody与@RequestParam可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。
注:一个请求,只有一个RequestBody;一个请求,可以有多个RequestParam。
为什么有的需要加@requestBody,有的不需要。加与不加的区别如下:
使用@requestBody.当请求content_type为:application/json类型的请求,数据类型为json时, json格式如下:{“aaa”:“111”,“bbb”:“222”}
不使用@requestBody.当请求content_type为:application/x-www-form-urlencoded类型的或multipart/form-data时,数据格式为aaa=111&bbb=222。
form-data
就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息;
由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。
form-data和x-www-form-urlencode的区别
x-www-form-urlencoded
就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如,name=java&age = 23
multipart/form-data与x-www-form-urlencoded区别
multipart/form-data:既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信息; x-www-form-urlencoded:只能上传键值对,并且键值对都是间隔分开的。
movement.setId(ObjectId.get());mongodb会自动生成id,也可以利用内置的工具类手动设置
异步处理优化
问题 :
-
在类中发布动态方法中 , 需要保存好友时间线数据 , 如果用户的好友比较多, 则需要插入的数据比较多, 效率低下
解决 : 可以采用异步线程池, 开启线程来异步保存好友时间线数据 , 提高保存的效率
-
将需要异步执行的代码抽取成独立的方法
-
在方法上使用标注该方法是一个异步调用方法
-
在项目启动引导类上开启异步支持
开启异步支持
异步处理类
在模块创建异步处理的
调用异步方法
修改的publish方法
使用mongodb插入数据时,每个document中必须有一个_id字段,且可以是任意类型,但如果没有单独设置_id字段,mongo会自动生成一个_id字段,类型是ObjectId
方法将ObjectID id作为24字节十六进制字符串表示返回
基于LIst实现分页处理
MongoDB获取随机数据
findAndModify方法的好处是能够在更新之后得到最终的更新结果,不需要再去查询一遍,提高代码效率
查询条件参数的类型必须一致,不然查询不到数据
publishId类型为ObjectId
movementId类型为String
转化为ObjectId类型:
枚举类,Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等。
Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。
输出:
enum是没有构造函数的,准确的来说是没有public类型的构造函数, 它的构造函数只能是private类型的;enum是单例模式;enum中有一个values方法来获取枚举实例对象数组;
使用枚举的目的就是规范和限制好参数类型
- 客户端用户注册
- 注册用户好友关系(联系人)
- 客户端获取环信身份信息
环信账号是环信服务器分配的,不是我们自己的
环信账号登录跟我们自己的服务器没有关系
- 手机端在线聊天
在线聊天和自己的服务器没有关系,全部借助的是环信服务器
自己的服务器主要是为了提供数据,而真正的即时通讯全部在客户端完成
application.yml
HuanXinProperties
HuanXinTemplate
TanhuaAutoConfiguration
原因:环信通信的API依赖放到了父级pom.xml,而没有放到autoconfig模块的pom.xml
WHY?
注意:
客户端的环信appkey要和服务端的环信appkey保持一致
必须登录的是在环信已经注册了的用户
测试
我们暂时通过环信的控制台进行发送:
消息格式内容:
按照条件随机查找并过滤数据
操作redis中的set
mongodb更新操作
实体类
注意:GeoJsonPoint对象不支持序列化
查询当前坐标附近的目标
查询并获取距离
导入依赖
找到的pom文件,打开fastdfs的依赖如下
application.yml
找到的application.yml,添加FastDFS的配置
测试
@Autowired相当于setter,在注入之前,对象已经实例化,是在这个接口注解的时候实例化的;
而new只是实例化一个对象,而且new的对象不能调用注入的其他类
设置缓存失效时间
引导类
在模块配置引导类
跨域问题配置类
配置文件
以前是直接访问到tanhua-app-server,现在是先访问网关再通过网关路径匹配路由访问
网关过滤器
在模块中添加引导文件bootstrap.yml,并设置
springboot会优先读取bootstrap.yml的配置
服务就会读取nacos中的配置了,后面就可以通过nacos修改服务配置
获取验证码图片
出现问题
重启DubooMongoApplication服务报错
错误原因:192.168.89.238:20882端口号莫名被占用
解决方案一:更改服务配置,将dubbo服务端口改成其他的,如20883
解决方案二:杀死当前192.168.89.238:20882端口进程
启动成功
mybatis-plus直接查询分页数据
mongodb追加查询条件
冻结解冻用户需要添加UserInfo字段userStatus,但是修改后就与数据库不映射了,所以需要设置不映射此属性
在redis中设置数据保存时间
将String数据类型转换为Integer数据类型
将JSON字符串转换为Map集合
RabbitMQ能将用户日志数据业务与系统进行解耦,用户日志数据业务也可能会异常从而影响系统
pom.xml
application.yml
在模块中配置发送消息的工具类
在模块中配置监听器
遇到问题,tb_analysis插入不了数据,也不报错
原因:数据库tb_analysis表设计有问题,没有向created字段,updated字段注入值,但表中的设计要求不能为null
解决
1.往created字段,updated字段注入值
2.改变表的设计,created字段,updated字段可以为null
内容安全是识别服务,支持对图片、视频、文本、语音等对象进行多样化场景检测,有效降低内容违规风险。
目前很多平台都支持内容检测,如阿里云、腾讯云、百度AI、网易云等国内大型互联网公司都对外提供了API。
按照性能和收费来看,探花交友项目使用的就是阿里云的内容安全接口,使用到了图片和文本的审核。
阿里云内容审核
准备工作
1,前往阿里云官网注册账号
2,打开云盾内容安全产品试用页面,单击立即开通,正式开通服务
3,在AccessKey管理页面管理您的AccessKeyID和AccessKeySecret
文本内容垃圾检测
文本垃圾内容检测:点击访问
文本垃圾内容Java SDK: 点击访问
图片审核
图片垃圾内容Java SDK: 如何使用JavaSDK接口检测图片是否包含风险内容_内容安全-阿里云帮助中心
抽取工具
GreenProperties
AliyunGreenTemplate
TanhuaAutoConfiguration
配置文件
测试
根据日期查询数据
接收消息的工作需要新创建tanhua-recommend工程,在此工程中完成相关的操作。
创建tanhua-recommend工程
配置文件
application.yml
RecommendMovementListener