# smilehappiness-spring-cloud **Repository Path**: jamno/smilehappiness-spring-cloud ## Basic Information - **Project Name**: smilehappiness-spring-cloud - **Description**: 该项目基于 Spring Boot+ Spring Cloud + MyBatis-Plus,基于Hoxton.SR12这个Spring Cloud版本,开发了这一套Spring Cloud微服务项目脚手架。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 7 - **Created**: 2022-08-22 - **Last Updated**: 2022-12-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README @[TOC] # 1 前言 Spring Cloud 官网,`2021-07-06` 发布了**Hoxton.SR12** 这个版本, **本来想使用 `Hoxton.SR12`这个Spring Cloud版本,查了一些资料,发现基于这个版本,好用的微服务架构体系并且开源的项目不是很多,可能是这个版本刚出来两三个月,就自己折腾了一个基础架构**。在进行依赖管理的过程中,走了不少坑,各种jar冲突或者版本不兼容等等,这里总结记录下,防止以后再次踩坑。 该脚手架项目基于 `Spring Boot`+ `Spring Cloud` + `MyBatis-Plus`,为了提高项目的开发效率,降低项目的维护成本,避免重复造轮子,我基于我上一篇博客中的基础架构,搭建了一套脚手架,可以直接拿来使用。 # 2 脚手架主要提供哪些功能 **该项目主要包括以下功能模块:** * `统一管理项目依赖,核心依赖的版本控制` * `缓存管理以及分布式锁的处理` * `预警通知功能` * `异常管理` * `限流Api管理` * `Mock Server管理` * `消息中间件MQ管理` * `操作日志管理` * `定时任务管理` * `Swagger-Ui管理` * `工具类管理` # 3 如何使用该脚手架 ## 3.1 项目统一依赖管理 * **集成基础设施项目:** **在自己的maven项目中,在最顶层项目的pom文件中,继承该基础设施项目:** ```xml com.smilehappiness smilehappiness-architecture 1.0.0 ``` ## 3.2 集成基础模块功能到自己的项目中 **下面的这些依赖的功能模块,可以根据实际情况,选择集成哪些功能模块,添加如下依赖,即可把基础设施项目的核心功能,集成到自己的项目中:** ```xml com.smilehappiness smilehappiness-cache HdrHistogram org.hdrhistogram com.smilehappiness smilehappiness-common com.smilehappiness smilehappiness-early-warning-notice com.smilehappiness smilehappiness-exception com.smilehappiness smilehappiness-limit-api com.smilehappiness smilehappiness-mq com.smilehappiness smilehappiness-operation-log com.smilehappiness smilehappiness-schedule com.smilehappiness smilehappiness-swagger-ui com.smilehappiness smilehappiness-utils ``` # 4 基础核心功能模块的使用 ## 4.1 集成缓存管理模块 分布式、微服务背景下,对于性能的要求也越来越高,所以缓存越来越受到了重视。现在使用比较流行的缓存是Redis,所以,笔者也基于Redis做缓存处理。 **Redis常见的场景有:** `普通缓存`、`分布式锁`、`分布式限流`、`幂等性校验`、`短信登录限定次数`等等 ### 4.1.1 添加cache模块依赖 ```xml com.smilehappiness smilehappiness-cache ``` ### 4.1.2 cache模块的功能使用 * Redis工具的基本使用示例 **注入以下工具类:** ```java @Autowired private RedissonClient redissonClient; @Autowired private RedisUtil redisUtil; @Autowired private RedissonLockRedisUtil redissonLockRedisUtil; ``` 然后使用以下测试用例: ```java public void testRedisUtil() { //赋值 redisUtil.set("test1", "你好"); //该工具类,默认过期单位为秒 redisUtil.set("test2", "测试一下过期时间", 30); //取值 System.out.println(redisUtil.get("test1")); System.out.println(redisUtil.get("test2")); //删除值 redisUtil.del("test1"); } ``` * Redis分布式锁工具的基本使用示例 ```java /** *

* 测试分布式锁的使用,基于Redisson客户端实现(该方法的实现推荐使用) *

* * @param * @return void * @Date 2021/10/4 16:51 */ @Test public void testDistributeLock() { String bizLockKey = "smilehappiness:trialOrder:orderNumberxxxxxxx"; //支持过期解锁功能,10秒钟以后自动解锁, 无需调用unlock方法手动解锁,当然,为了不占用资源,使用锁处理完业务,一般还是建议手动释放锁 RLock lock = redissonLockRedisUtil.lock(bizLockKey, 60L); if (lock.tryLock()) { try { //处理业务方法。。。 } catch (Exception e) { log.error("获取分布式锁失败,失败原因:{}", e); throw new SystemInternalException("获取分布式锁失败,失败原因:" + e.getMessage()); } finally { lock.unlock(); } } else { log.error("系统繁忙,请稍后再试!"); throw new BusinessException("系统繁忙,请稍后再试!"); } } /** *

* 测试分布式锁的使用,基于Redisson客户端实现(该方法的实现推荐使用) *

* * @param * @return void * @Date 2021/10/4 16:51 */ @Test public void testDistributeLockTwo() { String bizLockKey = "smilehappiness:trialOrder:orderNumberxxxxxxx"; //尝试加锁,最多等待30秒,上锁以后120秒自动解锁 boolean lockFlag = redissonLockRedisUtil.tryLock(bizLockKey, 30L, 2 * 60L); if (lockFlag) { try { //处理业务方法。。。 } catch (Exception e) { log.error("获取分布式锁失败,失败原因:{}", e); throw new SystemInternalException("获取分布式锁失败,失败原因:" + e.getMessage()); } finally { redissonLockRedisUtil.unlock(bizLockKey); } } else { log.error("系统繁忙,请稍后再试!"); throw new BusinessException("系统繁忙,请稍后再试!"); } } /** *

* 测试分布式锁的使用,基于Redisson客户端实现方式 *

* * @param * @return void * @Date 2021/10/4 16:51 */ @Test public void testDistributeLockOriginal() { String bizLockKey = "smilehappiness:trialOrder:orderNumberxxxxxxx"; RLock lock = redissonClient.getLock(bizLockKey); if (lock.tryLock()) { try { //处理业务方法。。。 } catch (Exception e) { log.error("获取分布式锁失败,失败原因:{}", e); throw new SystemInternalException("获取分布式锁失败,失败原因:" + e.getMessage()); } finally { lock.unlock(); } } else { log.error("系统繁忙,请稍后再试!"); throw new BusinessException("系统繁忙,请稍后再试!"); } } ``` ## 4.2 集成通知预警管理模块 目前,只设计了`钉钉预警通知`,后续可以集成邮件通知等等 ### 4.2.1 添加通知预警模块依赖 ```xml com.smilehappiness smilehappiness-early-warning-notice ``` ### 4.2.2 添加yml配置 **在yml文件或者properties配置文件中添加如下内容:** ```yml # 钉钉预警通知 earlyWarning: notice: # 一般预警通知 generalDingNoticeUrl: xxx # 高频异常通知预警 errorDingNoticeUrl: xxx ``` 记录好机器人的Webhook 地址,可以在自己项目中调用此地址向群聊发送相关消息通知,做到`项目异常的预警通知`或者一些`其它业务通知`,至此已经设置完成,剩下的只需要自己在项目中需要预警的地方调用接口通知即可。 如果你设定的机器人类型是关键字,内容需要包含关键字,才可以发送通知成功 注:这里分为了两个地址,可以根据实际情况,来决定用一个还是用两个,使用的时候非常简单,在钉钉上创建一个机器人,把webhook地址复制过来即可,限于篇幅,就不再详细说明,玩不转的小伙伴,可以参考资料:[https://blog.csdn.net/nbskycity/article/details/106068455](https://blog.csdn.net/nbskycity/article/details/106068455) ### 4.2.3 钉钉预警使用示例 * 首先注入工具类 ```java @Autowired private DingTalkWarningNoticeServer dingTalkWarningNoticeServer; ``` * 参考代码示例 ```java /** * 钉钉预警通知测试,注意,如果你设定的机器人类型是关键字,内容需要包含关键字,才可以发送通知成功 */ @Test public void testDingTalkNotice() { dingTalkWarningNoticeServer.sendWarningMessage("smile:这是一个警告的通知"); //第一个参数title,可以理解为关键信息标识,后续跟踪日志可以使用该关键信息标识快速找到 dingTalkWarningNoticeServer.sendWarningMessage("hello,", "smile:这是一个警告的通知"); try { log.info("结果:{}", 1 / 0); } catch (Exception e) { dingTalkWarningNoticeServer.sendErrorMessage(StringUtils.join("smile:异常通知,原因:", e.getMessage())); dingTalkWarningNoticeServer.sendErrorMessage("world", StringUtils.join("smile:异常通知,原因:", e.getMessage())); } } ``` ## 4.3 集成异常管理模块 项目中,经常会遇到各种各样的异常,有时候异常信息可以给用户看,比如说:**银行卡号填写错误、邮箱格式不合法等**、而有的信息不能给用户看,比如说:**系统走神了...** 还有一种场景,针对异常信息,有时候需要进行文字翻译,比如:系统返回的失败信息是 AAA,可能需要在适配层翻译为BBB返回给用户,可以做对照表等等进行处理 ### 4.3.1 添加异常模块依赖 ```xml com.smilehappiness smilehappiness-exception ``` ### 4.3.2 使用异常 #### 4.3.2.1 两种异常说明 **目前定义了两种异常:** `一种是业务异常,另外一种是系统级异常` * 使用业务异常(`BusinessException`)时,异常信息会直接返回给用户端,业务异常支持添加了普通code,业务code,以及异常信息。在设计的时候,**业务异常类这里额外添加一个业务`bizCode`参数**,`为了后续扩展性更强(可以基于业务bizCode做不同的信息对照展示,对于前端而言,基于普通的code,200或者非200即可判断是否请求接口成功)` * 使用系统级异常(`SystemInternalException`)时,针对这种系统异常,会统一降级处理,比如可以友好的返回:`系统升级中,请您稍后再试...`,而不是返回系统走神了或者一大串英文异常给客户 #### 4.3.2.2 异常使用示例 **具体使用可参考如下示例:** ```java @GetMapping("/getApiLoggerInfoByRequestUrlAndMethodName") public CommonResult> getApiLoggerInfoByRequestUrlAndMethodName(@RequestParam("requestUrl") String requestUrl, @RequestParam("methodName") String methodName) { LocalDateTime bizTimeStart = LocalDateTime.now(); CommonResult> commonResult = new CommonResult<>(); try { List apiLoggerList = apiLoggerService.getApiLoggerInfoByRequestUrlAndMethodName(requestUrl, methodName); if (CollectionUtils.isEmpty(apiLoggerList)) { throw new BusinessException(FrameworkBusinessExceptionEnum.API_LOGGER_INFO_NULL); } log.info("通过请求url和方法名称,获取日志信息接口返回结果:{}", JSON.toJSONString(commonResult)); log.info("通过请求url和方法名称,获取日志信息方法执行耗时(毫秒):{}", DateUtil.getTakeTime(bizTimeStart, LocalDateTime.now(), TimeUnit.MILLISECONDS)); return commonResult; } catch (BusinessException e) { log.error("【业务异常】通过请求url和方法名称,获取日志信息异常,异常原因:{}", e.getMessage()); log.info("通过请求url和方法名称,获取日志信息方法执行耗时(毫秒):{}", DateUtil.getTakeTime(bizTimeStart, LocalDateTime.now(), TimeUnit.MILLISECONDS)); throw new BusinessException(e.getCode(), e.getBizCode(), "通过请求url和方法名称,获取日志信息异常,异常原因:" + e.getMessage()); } catch (Exception e) { log.error("【系统异常】通过请求url和方法名称,获取日志信息异常,异常原因:{}", e.getMessage()); log.info("通过请求url和方法名称,获取日志信息方法执行耗时(毫秒):{}", DateUtil.getTakeTime(bizTimeStart, LocalDateTime.now(), TimeUnit.MILLISECONDS)); throw new SystemInternalException("通过请求url和方法名称,获取日志信息异常,异常原因:" + e.getMessage()); } } ``` 限于篇幅,这里就不详细介绍了,**详细的使用教程,可以参考我另外的博客,写的非常详细:** * [Spring Cloud 微服务基础功能架构来啦](https://blog.csdn.net/smilehappiness/article/details/120623974) * [基于Spring Cloud 的微服务架构脚手架,满满的干货来啦](https://blog.csdn.net/smilehappiness/article/details/120624307) *** * **GitHub下载地址:** [smilehappiness-spring-cloud](https://github.com/smilehappinessli/smilehappiness-spring-cloud.git) * **Gitee下载地址:** [smilehappiness-spring-cloud](https://gitee.com/smilehappiness/smilehappiness-spring-cloud)