基于天气的服装推荐系统
[toc]
项目简介
项目包结构:
项目技术栈
- SpringBoot
- MyBatis-plus
- SpringCloud
- Nacos
- SpringSecurity
- Oauth2.0+JWT
- Netty+WebSocket
- Swagger
- Mysql+Redis
项目中每个微服务的增删改查操作用的老三样SSM架构,比如用户和服装的添加修改删除操作,SpringBoot整合了Spring和SpringMVC配合Mybatis-Plus还是很方便的,也是学习java后端的基础架构。用来确实方便但是这也导致很多人对于手写sql和动态sql标签不够熟练,比如我在mapper文件里写一些方法的时候就出了一些小问题没注意到。还是需要多练习一下。
SpringCloud完成项目的微服务架构,Nacos主要使用注册发现和配置中心功能。微服务架构带来了很多好处,比如服务可以独立部署、易于扩展、技术选型灵活等。这同时也有一些缺陷,分布式系统的复杂性较高、测试难度提升、分布式事务管理等内容。在我编写的过程中还是碰到了不少问题这里就不赘述。Nacos的注册发现功能配合SpringGateway完成了网关的路由功能,外部只需要访问网关ip:端口/api/服务名/接口
就可以由网关转发到对应的微服务。使用nacos的配置中心,在bootstrap.properties
里配置好需要读取的配置文件,可以动态更新部分配置文件内容不需要重启服务,还可以把一些配置抽取出来作为公共配置文件比如数据库的连接配置。
SpringSecurty+Oauth2.0+JWT为系统加上鉴权功能,用户需要有特定权限才能够访问服务。使用java的keytools生成证书并解析出公钥文件,采取非对称加密公私钥的形式使用JWT生成token,在用户发送请求时根据公钥解密token。在服务中配置ResourceServerConfig
在该配置类中配置好公钥文件位置以及无需token的放行路径等内容。在springsecurity中需要把token生成策略证书加密方式、Oauth的认证授权方式策略等内容编写完善。
在用户反馈微服务中使用Netty+websocket实现在线聊天功能。注册一个组件其中启动netty服务器,在项目启动时同时启动netty服务,并且添加http编解码器HttpServerCodec
、ChunkedWriteHandler
、HttpObjectAggregator
、WebSocketServerProtocolHandler
以及自定义的SimpleChannelInboundHandler
来完成消息的相关处理。
Swagger主要是在为了生成接口文档给前端使用,这里同样需要配合springgateway编写SwaggerResourcesProvider
配置其他服务路由,访问gateway的swagger文档index,通过选项切换到不同的服务接口文档。在接口文档中可以看到被@Api(value = "",tags = "")
标注的controller中被@ApiOperation(value = "")
标注的方法,注解中可以设置更多的内容,记得要在启动类上标注@EnableOpenApi
注解
mysql用来存储系统中的数据、redis主要是用来做缓存内容,使用@Cacheable(value="",key="")
和@CacheEvict(value="",key="")
实现向redis中存放缓存信息和删除缓存信息,避免多次重复查询mysql。缓存的实体类需要实现Serializable
接口来表明该对象是可以被序列化的。序列化方面使用alibaba的FastJson
,有关fastjson的序列化的配置在这篇文章有写到:springboot中使用@Cacheable结合redis和FastJson遇到的类型转换问题 - 乌冬。
微服务划分
用户微服务
包结构:
在用户微服务(reco-user)中完成对于用户实体的增删改查功能以及缓存内容,同时因为有关权限相关的业务内容没有设计很多所以也一并放在security包中了。
服装微服务
包结构:
在服装微服务(reco-clothes)中主要实现了服装实体类的增删改查以及根据天气推荐服装的功能,这里的推荐暂时没有比较好的思路,暂时是根据衣物的保暖程度(用户添加服装时设置的值)和今日气温进行上衣下装和外套的推荐。获取天气是使用RestTemplate
的exchange
方法调用的外部的接口.
公共微服务
包结构:
在公共微服务(reco-common)一开始设想是作为无需启动的包,只在pom中引入其他微服务需要的依赖,其他微服务则依赖common服务就行,并且将一些通用配置类都写在公共微服务中,但是后来发现上传图片以及下载图片的方法在多个服务中都需要使用,干脆就写在commonController里了。关于图片的存储是直接file.transferTo
到本地文件夹,并且记录路径和文件名,在下载方法中返回给前端文件的url。这里要注意配置一个WebMvcConfigurer
接口的配置类,在里面写好静态资源的映射。图片的存储也可以考虑买一个oss对象存储服务,也不是很贵。
反馈微服务
包结构:
在反馈微服务(reco-feedback)的controller中没有写很多内容,主要是将聊天信息存入数据库。这一部分的主要内容是通过netty+websocket协议实现双向通信,完成在线聊天的功能,这一块写的还是比较吃力,还有很多需要改进学习的地方。目前实现了用户私聊和图片传输功能。使用TextWebsocketFrame
传输消息,中途学习中试过使用BinaryWebsocketFrame
传输二进制内容(这里只试过图片),虽然可以顺利的发送和接收,但是指定接收用户时有些不太方便(我没有找到比较好的解决方式)。最后还是通过上传图片接口将图片存储后返回url给前端,前端将url作为文本消息传输。
网关微服务
包结构:
在网关微服务(reco-gateway)中在application.yml
(nacos配置中心)填写网关路由,实现路由转发功能。config中写了swagger的配置和网关的跨域配置。在filiters中配置的token的不为空验证(cookies和header中查找)以及放行路径。
一些废话
在这个学习项目中有很多心得体会,分开来一点点说吧。
首先在项目还没开始动手写的时候就遇到了第一个问题:自己设计项目架构以及数据库。在自己以往的学习过程以及项目的编写中,大多数时候都是根据现有的项目去照猫画虎,这种方式确实可以提升自己的一部分编码能力,但是在自己设计的过程中让我更切实的体会到了架构、数据库设计的难度。我自以为已经考虑的比较周到了,而且在开始前和编写过程中一旦有了一些新思路都会加到备忘录中,但是没有这些经验,最后还是出现了很多问题。比如数据库字段设计不合理、创建了无用表或者少创建了需要的表。不得不说这一块搞错了还是比较麻烦的,需要重新写实体类以及部分增删改查的代码都需要改。还好库中数据都是自己模拟的测试数据。再比如项目依赖会冲突,各种冲突!要在pom中去配置<exclusions>
或者修改配置。个人碰到的冲突印象比较深的有spring-boot-starter-web
和spring-cloud-starter-gateway
上出现一次。还有就是swagger
和springboot
配合使用时,因为版本问题需要在yml中配置spring.mvc.pathmatch.matching-strategy=ant_path_matcher
。最后还有就是微服务的划分,最开始分的有点太细了,导致某个服务中只有一两个接口,反而降低了开发效率还增加的内存占用。
其次就是在前端的问题上,一开始我后端代码编写了差不多以后就去找学前端的朋友帮忙编写页面,但是我发现对于前端开发来说不是很方便。一方面是没有大致的页面设计风格和结构(最后是给他画了草图,剩余部分让他自由发挥哈哈哈哈哈),再就是前端发送请求时没有接口文档可太要命了,最开始后端是没有加swagger的,还好在他编写请求之前完成了文档。在前后端联调的时候还发现一些小问题比如有一个方法的返回类型我为了图省事,全塞到map里了问题就在这个map的key和value还搞得有点乱,给我朋友看麻了,最后老老实实把返回类型的结构修改了一下。
最后,项目中使用了一些以前自己从未使用过或者不够熟练的技术,尤其是netty学的晕乎。通过自己设计编写一个项目让我更深刻地认识了自己的不足,未来的学习任重而道远。再就是很多框架分开使用都ok,但是在把他们结合到一起之后会出现一些新问题,有时候还是会有些头疼。还有就是在git方面的使用还是比较生疏,虽然使用过程没有碰到什么问题,成功推送到了gitee,但是还有很多版本管理相关的知识内容需要去熟练,毕竟在实际地开发工作中是离不开这些的。
关于这个自己练手的项目还是有很多不足之处,以后有机会再看看完善一下,关于其中的部分内容可能还是需要单独记录下来,就不全塞到这一篇文章中了。比如搞了我比较久的springsecurity+oauth+jwt的用户授权认证,还有netty实现聊天功能的具体细节等。整个放在了gitee仓库有兴趣可以去看看,如果有建议就更好了,个人认为这个项目还有很多很多不足之处。
大概就写到这里吧!有机会再写项目中的细节!
Gitee仓库地址:乌冬/recommend (gitee.com)
欢迎留言提建议或者提问!