前言
2024年7月17日,最近终于在低效率的情况下把java及其生态的知识点背的差不多了,投了两个礼拜的简历,就一个面试,总结了几点原因。
-
市场环境不好
要知道,前两年找工作,都不需要投简历,把简历公开就会有各种hr打电话进来,今年我给了一个之前的hr,她特别委婉的拒绝了我的简历,她那关都过不去 -
太tm卷了
java需要会vue的公司真的很多, -
自己只有基础,应用,深入和优化的东西没有
基础的话就那些八股嘛,全部掌握肯定没有,但哪个知识点都能7788的说一些,暂时只能做到这些
应用就是例如声明式多线程的使用,分布式事务、session的使用,秒杀的涉及等,这些也是7788能说一些,还有完整的流程,总归是还说的过去深入和优化的话,就是普通java程序员用不到的,jvm及其调优,sql优化这些,重要也重要,但是都是在大数据量的前提下,并不是所有公司都有这么大的数据量的。
-
项目是商城
这个问题,额,培训班都是这种项目,所以可能直接hr就直接筛掉了。正好,尚硅谷刚发布了一个
乐尚代驾
的项目,40个小时,之前谷粒商城是105个小时,算了一下,除了运维的部分,实际上是87个小时,所以整体的体量的话乐尚代驾
要小的多
这个项目我不打算敲,有了谷粒商城
的打底,感觉可以直接看代码,老师讲的,然后把重点抓一下,关键也是没有那么多时间,需要学的太多了
乐尚代驾 项目概述
背景 功能
- 代驾项目
- 采用微信小程序方式
技术概述
项目中也用了前端技术,但是在该项目中我们主要做后端部分。
- Knife4J,加强版Swagger
使用的云服务
技术架构图
项目包括乘客端、司机端和平台管理端。我们只做前两个。
项目访问的基本结构
- service-client中定义的是远程调用的接口
业务流程
业务流程详细描述
乘客端
-
登录
- 乘客端只有登录,没有注册,登录方式为微信小程序登录,乘客(司机)登录我们根据微信接口拿到微信OpenId(全局唯一),到乘客表查询OpenId是否存在,如果不存在即为注册,将该乘客添加到乘客表中,存在则根据用户信息生成token返回
- 如何判断是否第一次登录,通过OpenId进行判断
- 登录流程
-
小程序端通过
wx.login()
获取code(临时票据),有效期5min -
后端接收到code之后,可以获取到该用户的唯一标识OpenId和session_key
- 在服务器端,使用session_key和openid向微信服务器请求一个有效的Token和refresh token,用于后续服务器端和微信服务器的特殊 API 调用
-
后端接口根据三个值,小程序id+密钥+code请求腾讯接口,返回的信息中就包含唯一标识OpenId
-
根据OpenId判断是否第一次登录,如果是就注册返回token,如果不是就直接返回token,放到localstorage中,登录成功后把用户信息放到ThreadLocal中
- 这儿的token应该不能使用明码放到redis中,而应该使用Jwt,使用的类是
import io.jsonwebtoken.Jwts
,因为它本身就可以存储用户的信息,所以直接与数据库进行交互就行了,不需要放到redis中,过期时间就先说14天吧
- 小程序端每次向后端发送请求的时候,把token放到请求头中
- 这儿的token应该不能使用明码放到redis中,而应该使用Jwt,使用的类是
-
使用AOP来进行认证
- 原始的方式是在需要判断登录的Controller上进行是否登录,会造成大量的冗余代码
- 我们使用AOP来优化
- 使用@interface自定义一个注解
- 使用@Aspect定义一个切面类,在环绕通知上,定义切入点(对所有Controller进行增强 && 包含我们的自定义注解)
- 在环绕增强中我们判断用户是否登录,只有Controller中才能直接获取请求头,在这里我们使用
RequestContextHolder
-
使用,哪个Controller需要进行登录判断,就在这个Controller上添加这个自定义注解,这里说的Controller实际上指的是请求路径,也就是方法,
-
-
选择代驾地址
- 选择代驾地址之前应该先查找该乘客当前的订单,因为无论是乘客还是司机每个人在同一时间只能有一个订单
- 预估代驾距离、费用、时间
-
调用腾讯地图Direction API,获取路线、距离和时间信息,一共会返回三条,我们选择第一条,默认是最优的,地点定位传的全是经纬度
-
费用规则
- 里程费:基础里程费 + 超出起步里程费
- 等候费:司机到达代驾起始点后,可免费等候10分钟,超出后每一分钟收取一元
- 远途费:订单行程超出12km后每公里收取1元远途费
-
规则虽然是上面这样的,但是实际中,规则可能随时进行调整,比如油价上涨收取燃油附加费,比如大雪大雨天气,费用增加等等
对于不经常变化的业务,我们通常是硬编码到程序中。但是经常变化的业务,我们就得把业务流程从代码中剥离出来,我们怎么从程序中剥离出去?这里就需要用到
规则引擎
了。规则引擎可以做到把算法剥离出程序,你可以保存到TXT文件或者数据库表里面,用的时候再加载回程序。虽然加载回来的算法是字符串,但是规则引擎有办法运行这些字符串。例如遇到雨雪天气,代驾费用就得上调一些。如果是业务淡季,代驾费用可以下调一点。既然代驾费的算法经常要变动,我们肯定不能把算法写死到程序里面。
-
规则引擎动态更新的实现
通过Nacos Config Service获取.drl配置内容,并且加了监听器,监听规则文件的更新
-
- 呼叫代驾
- 生成订单
封装订单信息,驾驶路线、费用、距离
- 等待司机接单
-
搜索附近5km可以接单司机
- redis的GEO,GEOADD添加位置信息和GEORADIUS寻找距离多少公里的地点
- 司机开启接单服务之后,司机端小程序实时把司机当前位置信息上传到Redis里面GEO
- 会判断接单的里程(司机与乘客距离)和代驾的里程(乘客与目的地的距离),最后搜索附近满足条件的司机
-
乘客下单之后,开启定时任务,XXL-JOB每隔一段时间(30s合理么)会搜索附近符合要求的司机,如果超过15min,则取消该订单
-
搜索附近代驾司机的逻辑
- 查询订单状态,如果是接单状态的话,继续执行,否则停止
- 远程调用地图服务搜索附近满足条件的司机
- 遍历司机集合,以订单id为key,司机 id为值,存放到redis的set集合中,防止重复推送
- 把订单推送给合适的司机,过期时间就设置为该订单的剩余时间,然后存放到redis的list集合中,key为司机,val为订单信息
-
15min没有司机接单,取消订单
使用Redisson获取延迟队列,接收队列利用while true实现监听
我们这里还是说使用rabbitmq来实现取消订单的这个功能,因为不太了解while true能不能这么用
-
有司机接单
- 司乘同显
- 到达终点,乘客根据司机发送的账单,进行支付
微信支付成功后先给用户返回支付结果,再利用消息队列完成其他操作,例如更新订单状态为已支付,将系统奖励添加到司机账户等等。
现在先假设支付完成后的操作都是在一个方法中调用的吧,然后这块儿用的是Seata做分布式事务管理
司机端
- 登录
- 身份认证
- 创建司机人脸识别模型(腾讯云神图·人脸识别,上传一张人像即可)
- 司机登录,流程与乘客登录一样,只是如果是第一次登录的话需要添加一些信息
- 初始化司机相关设置(比如接单范围)
- 腾讯云对象存储COS,存储司机认证相关资料(身份证、驾驶证)
- 腾讯云OCR证件(身份证、驾驶证)识别,本接口支持中国大陆居民二代身份证(驾驶证)正反面所有字段的识别
- 腾讯云人脸模型库创建
- 开始接单
- 更新司机接单状态
- 人脸识别(该司机是否与腾讯云神图上认证的照片一致)
- 人脸静态活体检测(用于判别人脸是否为真实活体,而不是通过照片、视频或其他非真实的方式呈现的)
- 这两个每天都得检测一次
- 司机抢单
- 并发问题,类似于超卖问题,两个司机都抢到同一个订单,使用redisson锁来解决
-
前往代驾地址
-
司乘同显,司机抢单成功后要赶往上车点,我们要计算司机赶往上车点的最佳线路,司机端与乘客端都要显示司机乘同显,这样乘客就能实时看见司机的动向。
就是将司机的位置实时上传到redis中,乘客也来读取就可以了。
-
司机到达代驾起始点之后,更新当前代驾订单数据。
更新订单状态:司机到达;更新订单到达时间
-
司机更新代驾车辆信息
就是对车辆拍照,然后记录车牌号
-
-
开始代驾
-
司机录入车辆信息后,就开始代驾了。开始代驾后,司机端与乘客端同样要进入司乘同显页面,司乘同显的起始点与终点就是代驾订单的起始点与终点,这里我们不需要提供额外的接口,直接使用“计算最佳驾驶线路”接口即可。
-
订单在在代驾过程中,我们需要保存驾驶途中的GPS定位,将来我们计算代驾真实里程的时候,就需要用到这些坐标点。那么这些定位点保存在MySQL中可以吗?当然不行,MySQL单表记录超过千万行就开始变慢了。那么保存再哪里呢?保存到MongoDB中。
司机开始代驾之后,司机端会实时收集司机代驾位置,定时批量上传位置到后台服务,保存到MongoDB里面
-
订单在代驾的过程中,司机端小程序要实时采集录音,把录音和对话文本上传到后端系统,将录音监控保存到Minio,对话文本保存到MongoDB中
-
订单监控审核,我们之前功能里面很多地方使用腾讯云COS服务,比如司机认证上传图片,包含身份证、驾驶证等图片。因为上传这些图片,目前无法保证图片是否违规。如果使用人工审核,速度太慢。使用腾讯云数据万象实现自动审核
-
计算订单实际里程,在MongoDB保存代驾过程中司机位置信息,把MongoDB存储司机位置信息获取出来,以时间排序,连接成一条线,这条线是实际距离
-
计算系统奖励,完成不同的单数有不同的奖励
计算分账信息,结束代驾之后,计算分账信息,平台按照一定规则抽成处理,和订单数和订单金额有关这两个也还是使用Drools,计算分账信息
-
判断司机刷单行为
什么是刷单行为?
司机还没有到达代驾地点就点击到达,司机还没有到达终点就点击结束代驾,这样做是为了争取更多的订单,争取更多的平台奖励。- 司机到达代驾开始位置(或者到达代驾结束位置)判断,超过100米就认为是刷单
- 判断预估里程和实际里程差别,超过1km认为是刷单行为
-
-
代驾到达终点(代驾结束),生成账单发送给乘客
司机结束代驾,有很多远程调用的
- 获取订单信息 1s
- 计算实际里程 1s
- 计算实际费用 1s
- 计算系统奖励 1s
- 计算账户分账 1s
上面方式,一个一个执行,操作执行效率低下的,这种方式进行优化,可以多线程方式完成这些操作,使用CompletableFuture实现异步编排进行优化
-
远程调用订单服务根据orderId获取订单信息,判断当前订单是否是该司机接单,主要为了获取订单中代驾结束位置的经纬度
远程调用地图服务获取代驾结束位置的经纬度,这两个合并,并且获取结果 -
判断刷单,终点订单的位置和订单的位置不能超过1km
-
调用地图服务计算订单实际里程(从MongoDb中把每个点找出来连成线就行了,有工具类)
3.1 计算代驾实际费用,需要用到实际里程,使用thenApplyAsync可以获取到上面的结果
-
计算系统奖励
-
计算分账信息
使用allof等以上5个全部执行完毕,更新订单信息
最后司机端获取账单并推送给乘客
微服务项目导入
是一个架子,没有核心的代码,导入微服务项目之后,需要修改mvn的地址和jdk,该项目使用的是jdk17。
nacos配置中心的配置
搭建项目前端环境
注册微信开发者账号
我们开发的是微信小程序,开通这些就相当于开通了微信小程序的权限。
注册完成后添加类目
开通服务与插件
获取appid和app密钥
小程序首页–》开发管理–》开发设置–》生成
生成之后将id和密钥记录在本地,这里下次是看不到的
开通服务
开发管理–》接口设置–》地理位置–》开通 获取用户收货地址、打开地图选择位置、获取当前的模糊地理位置
可以选择批量开通,老师说的是一天就开通了,我的是半个小时左右
开通插件
设置–》第三方设置–》插件管理
添加微信同声传译和腾讯位置服务地图选点,在这儿找不到这两个插件,需要去微信服务市场去找
安装nodejs和微信开发者工具
小程序首页=》开发=》开发工具=》微信开发者工具=》下载
装两次的原因是因为司机端和乘客端都需要进行测试
微信开发者工具运行前端项目
前端代码是老师直接写好的
在微信开发者工具的安全中,需要开启服务端口,默认是没有开放的
搭建项目后端环境
安装mysql
如果顺利进入,安装成功。
安装rabbitmq
安装redis
安装nacos
安装minio (min io)
分布式文件存储服务
导入数据库
老师现成的表导入数据库即可
导入配置文件到nacos中
导入有的时候可能会不好用
启动项目测试
allow-bean:bean相同覆盖,就是说如果有名称相同的两个bean,后一个会覆盖前一个,简单百度了解了一下,反馈是最好不要用,会出现诡异的情况。
此项目由尚硅谷老师完全讲述:
https://www.bilibili.com/list/ml1175311151?spm_id_from=333.999.0.0&oid=1856043192&bvid=BV1nW421R7qJ&p=3
科学就是好奇心驱动,有些理论和论文发表了,可能一、两百年以后才能发挥作用。爱因斯坦年纪轻轻就有伟大的发现,大家不理解,他不也是很寂寞,到处找人喝咖啡,各说各的,生命这么长时间,有多少人有兴趣与他喝咖啡呀,你以为天天会有人与他喝咖啡。伟大与孤独是同义词。比如,孟德尔的豌豆杂交实验从1856年至1863年共进行了八年,他将研究结果整理成论文《植物杂交试验》发表,他发现了遗传基因,但当时未能引起学术界的重视,孟德尔的思想和实验太超前了。经历百年后,人们才认识到遗传基因对人类社会的巨大价值。
https://baijiahao.baidu.com/s?id=1760664270073856317&wfr=spider&for=pc
擦亮花火、共创未来——任正非在“难题揭榜”花火奖座谈会上的讲话
任正非
文章评论