那些年,我写过的项目(一)

一 前提

近一个多月没有更新文章了,因为二月初过新年,耽搁了一两个星期,然后在二月尾,发生了一些事情,心情不佳,就懒于提笔了。进来无事,在一个好久不用的网盘上,找到了自己刚毕业出来工作时做的项目,内心深处有一些触动,于是想写一篇文章来总结下这四年里做的事情。

二 介绍前的碎碎念

不知道各位有没有过这种感觉,随着工作时间变长,回望过去,总能得到一些不一样的理悟。以前一直理解不了,觉得晦涩的底层逻辑,现在拿来看,一下子觉得清晰明了,甚至可以马上产生联想,对映上某些场景,往自己的知识树上挂。

举一例子,刚毕业时,只知道拿 Synchronized,volatile 等书面原理照着背,背得滚瓜烂熟,却不晓得它们真正用在了哪里。之后在看一些并发同步组件时,才发现它们经常出没在这里。而那些同步组件底层不光有这些,以 同步器 为例,它还有 FIFO队列 数据结构,生产-消费设计模式等待唤醒,封装组件代码提供api使用时,又以模版模式给予使用。这种感觉,就像是玩剧本杀一样,所有的线索都连在了一起,一切豁然开朗。

流转好几个公司,参与开发不同的项目,怀着这种心情,开始平静地回顾自己过去做的项目代码。  

三 毕业工作做的项目

刚出来工作时,入职了一家在线教育创业公司。开始上班时,师傅还没有给项目让自己弄,只和自己说,现在整个公司后台系统想做一个统一登录鉴权的服务,你自己去学习调研下,看看怎么弄吧。自己有些懵,之前只了解单体的服务,啥是统一登录服务,微服务呢?赶快抓紧时间恶补了一下。之后一边学习微服务知识,一边询问请求师傅的意思,一路跌跌撞撞,后面逐渐明白,要做的服务要做些什么事,结构该长什么样子。

 

中台-登陆验证服务

项目背景:

各个项目后台管理系统,需要每个组对应哪些操作权限,有些页面并不是对所有人可操作的。业务层面划分三大模块,用户,群组,后台接口api。其中 api 应该对应 group 进行划分代表着有某些权限,而 user 用户想要有权限,应该属于哪些群组。

  image.png  

  整体架构图如图所示:

image.png

一 SpringCloud 微服务

整体服务是要在 Springcloud微服务基础上,各服务和 zuul 交互都需要注册到 eureka。

二 部署一个单独的 auth-center 服务系统

1 主要负责提供用户信息权限,用户群组,url权限分配的增删查改接口调用

public class User implements Serializable {
    private int id;
    private String userName;
    private String password;
    private int status;
    private int role;
    private String email;
    private String phone;
    private Date createTime;
    private Date modifyTime;
}


public class Group implements Serializable {
    private int id;
    private String groupName;
    private int status;
    private String server;
    private String url;
}


public class UserGroupRelation implements Serializable {
    private int userId;
    private int groupId;
   }
复制代码

  2 单独一个rpc接口给 zuul 服务进行权限验证, 使用 Feign 进行RPC 远程调用

@FeignClient("auth-center")
@RequestMapping("/authCenter")
public interface CheckTokenService {
 
    @RequestMapping(value = "/verifyToken", method = RequestMethod.POST)
    AuthenUser test(@RequestParam("token") String token,
                    @RequestParam("url") String url,
                    @RequestParam("server") String server);
复制代码

 

3 开发一个统一的servlet jar 包,利于反射的原理,获取到所有 RequestMapping 注解下的url,供权限分配。各服务直接将该servlet注入Spring IOC容器即可。

RequestMappingHandlerMapping rmhp = springContextHelper.getObject(RequestMappingHandlerMapping.class);
try {
    Map<RequestMappingInfo, HandlerMethod> map = rmhp.getHandlerMethods();
    for (RequestMappingInfo info : map.keySet()) {
        HandlerMethod hm = map.get(info);
        Class<?> scannerClass = hm.getBeanType();
        ClassScanInfo classScanInfo = scannerHelper.getAllMappingUrl(scannerClass);
        projectUrls.add(classScanInfo);
    }
    print(resp, new Protocol(ResponseCode.OK, projectUrls));
} catch (Exception e) {
    e.printStackTrace();
}
复制代码

三 zuul 服务

zuul 中核心的Filter组件,改写其中类型为 pre 的Filter,调用 auth-center接口,进行判断该URL是转发还是拒绝请求。

AuthenUser authenUser = verifyTokenService.test(token, uri, server);
复制代码

公司主业务项目

随后工作进入正轨,开始接手公司里的项目。公司里项目大部分是购买会员,背英语单词打卡返学费的形式。

业务场景有用户购课,生成订单,上课体验,娱乐互动,打卡返学费,分销等。这里简单回忆几个当时印象比较深刻的业务场景。

一 开口读排行榜

项目面对的对象是 k12,都是些小朋友,产品想设计一个开口读英语的排行榜,增加产品的趣味性,吸引小朋友开口读单词。

底层用 redis 的 zset 对象实现,score 为开口次数,value 为 childId,加一的时候,用 redis 自带的 incr 方式实现自增。因为产品只需要展示前五百名用户,用一个 Math.random() 函数当概率小于等于百分之十时,隔一段时间,无用的数据被清理,保证查询不超时。

if (temp <= 0.1) {
    RedisClient.expire(weekSpeakRankRedisTemplate, weekCache, 42L, TimeUnit.DAYS);
    RedisClient.zremoveRange(weekSpeakRankRedisTemplate, weekCache, 0, -501);
}
复制代码

二 兑换码

redis 的 Set 集合对象存储 兑换码,兑换码生成用UUID简单生成,在集合对象底部去重。每次用户调用接口获取兑换码时,从 Set 集合 spop 取出元素,再插入数据库保存用户与兑换码使用状态。

String code = UUID.randomUUID().toString().substring(0, 18).replaceAll("-", "").replaceAll("0", "o").toUpperCase();
复制代码

 

三 定时job

当年还记得是在服务器上,用 cron 命令定时调度一个 controller 来实现定期任务执行。有时业务为了避免定时任务并发执行的情况,还需在代码最前面加上公司研发的 redis 分布式锁。之后工作的公司结合 Spring的scheduled + 时间轮自定义框架实现任务调度,如今自己使用 XXL_Job实现定时任务。哈哈,不禁感受良多。

 

四 服务降级

比较重要的一些接口调用外部服务api时,防止超时报错,采用 Hystrix进行服务降级。之后开发时,用的还是比较少,主要是catch到异常后,进行一些代码逻辑处理。

 

四 总结

还未完,下篇文章接着说~

Guess you like

Origin juejin.im/post/7075198776901632031