Groza项目技术文档


项目代码来源于github,觉得和自己专业很贴近,就clone下来去分析了一下,源代码地址是
https://github.com/sanshengshui/Groza

一、概述

首先说一下大体架构。

ModulePositionReference
groza-applicationConfiguration,Base MVC, ControllerSpringBoot Application Entrance, Authentication and Authorization(JWT)
groza-common-dataModellombok,Enum
groza-common-messageSpring AwareBeanFactoryManager
groza-common-transportDevice Transport ModelDevice Connection API
groza-daoDAO,Service,ServiceImpl,ModelJpa lombok
groza-rule-enginemqttDevice Client
groza-tools
groza-transport-coapcoap轻量级HTTP协议
groza-transport-httpControllerJpa
groza-transport-mqttchannelssl,mqtt

项目环境搭建需要,用可视化工具连接上数据库,启动redis就可以启动了。

项目思路:用硬件作为数据源,将mqtt作为channel,订阅相关主题,接收http请求,对于channel使用Netty进行了简单的优化之后,进行端口转发,域名匹配和过滤,到达controller,进行service的业务操作,总体使用了简单的jpa持久层框架进行开发,并且在硬件之间的通信采用了coap协议,最终呈现在前端。

项目可改进之处(本人认为):

  1. UUID可以改为snowFlake,但小并发其实UUID也可以,目的都是保证不会哈希碰撞。
  2. 在http请求发出去之后是携带header的,header本身也占用一定的资源,在端口转发,域名匹配等等在控制层接收之前的操作,可以用Netty的思路进行改进。同时用servlet以外的思路对项目进行优化。
  3. 既然是轻量级的项目,可以将Spring Security的认证授权改成shiro,开发比较简单。
  4. 在硬件发送过来数据之后,单纯的消息队列无法做到彻底解耦,项目可对数据进行异步操作,同时用缓存,进行压力的减小,用RedisTemplate的模板方法即可(模板设计模式)
  5. 从项目风格来讲,个人觉得model dao controller写在一个Module是不是会更好呢,增加可读性。

二、Module Reference

太简单的东西就一带而过了。

Annotation API

@Configuration:留下一个Spring Bean,将配置添加到spring IOC容器,自动生效,封装了一层Component,所以可直接将标记的类注册进去。

ConfigurationProperties:标记具有相同前缀的分层属性,给这个类加一个特殊的标记让程序运行的时候可以识别,标记的种类可以任选。

@Primary:在@Component标记之后会注册方法或者类,注册之后需要自动注入到容器才能生效,如果我们用@Component、@Bean等等添加入容器的方法属性或者类,拥有多个(比如一个类我实例化两次),那么@Primary就可以让被注册的这个属性、方法、类提前注入,来调整被注入的顺序,以防报错(被同时注入就会报错).

@Qualifier:和上面是一组注解,@Primary表示提前注入,@Qualifier是标记谁注入谁,通常和@Autowired同时出现。

@RestController:以json形式返回给后端

@RequestMapping:域名匹配,http请求匹配。

@RequestBody:以对象的形式作为请求体

@PreAuthorize:源于SpringSecurity,将登录用户的roles/permissions参数传到方法中

@Component:注册方法或类或属性。

@SuppressWarnings("unchecked"):屏蔽编译器的警告

@Slf4j:lombok的注解,实现输出日志

@JsonCreator:Jackson里的一个有意思的注解,json反序列化为java对象的时候,此注解可以定义无参构造函数,如果不标记这个注解,也可以自己定义无参构造,但是不定义就会报错了。

@Service:标记Service层

@JsonIgnore:用于属性或者方法上,忽视bean的一些属性。

@PostConstruct:其实也是作用于Servlet生命周期的注解,

  1. 只有一个方法可以使用此注释进行注解
  2. 被注解方法不得有任何参数;
  3. 被注解方法返回值为void;
  4. 被注解方法不得抛出已检查异常;
  5. 被注解方法需是非静态方法;
  6. 此方法只会被执行一次;

作用:在构造方法之后,init方法之前进行调用。

@PreDestroy:在Servlet生命周期结束后执行

@Builder:对外无法进行修改数据,保持private setter操作

@Data:lombok全家桶注解,实现get set 无参 有参构造 equals hashcode toString

@AllArgsConstructor:lombok注解,实现全参数构造

@EqualsAndHashCode:复写equals hashcode

@Getter @Setter @toString:实现getter setter toString

@MappedSuperclass:用在父类上面。当这个类肯定是父类时,加此标注。如果改成@Entity,则继承后,多个类继承,只会生成一个表,而不是多个继承,生成多个表

@Id:主键

@Column:列簇

Reference

Lombok

Lombok插件及其系列注解在写javaweb相关方面,用到的是很多的。其作用就是去生成get set toString hashCode equals 有参/全参构造。

但是Lombok都是注解,可以在上面查阅到对应的注解,需要注意的是,如果你使用了Lombok,需要手动再安装plugin才能生效。

SpringBoot

先说一下纯SpringBoot语法。其使用起来比ssm还是要简单很多的,但是又成功的让我们更加忘记servlet的正常生命周期了。在这里建议大家去学一下Netty。

其实SpringBoot也大多都是一些注解类的东西去让你少写一些代码。

我在这里说一下架构思路。

  • Model

一般情况下,Model里面的都是你数据库每张表的映射类,你可以用上面某个注解去匹配字段,起别名,但一定要标记主键。在Model里,这个项目比较纯粹,没有比较复杂的联合表,就不多解释了。

Model层你在类里面写了什么字段,和数据库里对应表的列簇匹配就好了。

  • Dao

项目中主要用了JPA去实现,我主要说说JPA吧,JPA在持久层主要是靠实现接口(JpaRespository JpaSpecifical BaseEntity等等)的方式,去使用,这样你在实例化Dao的时候,就可以使用封装好的api了。

我简单举几个JpaRespository Crud封装例子:

findById:在对应的表的持久层中,通过主键去寻找到主键对应的对象各个属性。
findAll:这个返回的是List,意思是将对象的各个信息打包放入List内,去return。
find*byId:根据主键查询到某某,可返回一个列表
delete*byId:void类型,直接依照主键删除
save:你set进来之后,update整行的sql表

并且JPA也支持在接口层,进行自定义的api,内部会自动进行sql拼接。

在这里说一个项目涉及到比较多的一个返回类型:ListenableFuture

这东西呢,也是concurrent包下的,所以自带了一定并发相关的封装,意思就是要求定义的方法一定得是异步去执行的,和反应式查询不同的区别是,异步查询的结果会直接提交给Spring TaskExecutor,如果对任务调度不熟悉的,可以看官方文档。
https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/integration.html#scheduling

而在项目中最精髓也最蛋疼的就是的地方就是:

  1. 它明明有关联的Entity类,方便了我们表与表之前的关联查询,但是却和其他的Model不写在一起,而且似乎关联的还是挺多的。建议画一下图。
  • Service&ServiceImpl

Service一般来说,只需要吧DAO层的再写一遍,然后将返回类型自己重新定义一下就行了,用JPA的Service其实不需要过多的写代码,都写在ServiceImpl就行了。

ServiceImpl中可以看出过多的使用到了异步的JPA的api。

  • Controller

基本都是业务性代码,但是有一些SpringSecurity的语法需要注意。

MQTT&Netty

因为MQTT在这单纯起了一个订阅发布的作用,我主要想说一下消息进入Channel之后,Netty的操作,并且在这里简单介绍一下Netty。

Netty属于一种线程模型框架,是一种比较底层的框架了,并且应用广泛,不光针对于mq,web也可以,取代servlet的思路,然后改成Netty的思路。

Netty正常的流程,分为几个关键阶段:

  1. 首先Netty自己作为一种轻量级的服务器,你可以把他的地位理解成Tomcat,创建服务器的时候,要创建事件循环组两枚,一个是bossGroup,用于创建连接,一个是workerGroup,用于连接之后的业务操作,然后bind个端口,连接一下就行了。
  2. 初始化过滤器,因为毕竟你得选一下消息过来的类型,可能是httpObject,可能是String,是啥都有可能,你得addLast或者在其他是简单,Filter一些东西,但是肯定要做的两个操作是,编码和解码,其他的得看个人需求。
  3. 建立控制器,继承ChannelInboundHandlerAdapter,或者其子类SimpleChannelHandler,这种继承方式是一种适配器模式的选择,可以看看设计模式上是咋说的。另外Handler需要重写很多方法的,这个可以借鉴我写过的一篇博客https://blog.csdn.net/qq_41936805/article/details/100610827
    Netty的理论方面的可以看我这篇博客,有对相关api详细的解释https://blog.csdn.net/qq_41936805/article/details/100557748

然后我们可以看出,项目中确实也是这个意思,Handler层也有比较好的注释,另外还做了SSL方面的安全保证。

  • SpringSecurity

JWT

全称Json Web Token,是一种将加密信息存储在客户端减轻服务端压力的一种加密模式,其Token的加密可以使用多种加密模式,比起sessionId,OAuth的相比都要好很多,此项目是用的JWT结合的SpringSecurity。

但JWT最大的缺点是,token一旦生成了,因为服务端是不存储数据的,所以没办法中途废除数据,换句话说,一旦客户端有了这个token,在到时之后,权限是不会被改变的。

JWT一共分为三个段落,分别是header payload signature。

header信息一般是存储jwt的元数据信息,一般就是一个json格式,然后标记签名的加密算法(默认HS256算法进行加密),然后还有种类等信息,最后用Base64URL转换成为string。
然后当客户端在使用token登录的时候,服务端会自动去匹配到固定请求头的信息,这里的请求头是Bearer ,并且项目中也已经说到了。

payload信息存储一些官方字段:

在这里插入图片描述
默认不加密,也可以加密。

  • signature信息是根据header指定的加密算法去加密,默认是HS256,然后按照一定公式生成签名。

以上一共三段的信息拼接一起就是Token了。项目中对于header的加密,刷新,失效,认证授权都有详细的说明,而且还有认证授权失败和成功的结果。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值