博主介绍:✌全网粉丝5W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌
博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+MySQL+Vue等前后端分离项目,可以在左边的分类专栏找到更多项目。《Uniapp项目案例》有几个有uniapp教程,企业实战开发。《微服务实战》专栏是本人的实战经验总结,《Spring家族及微服务系列》专注Spring、SpringMVC、SpringBoot、SpringCloud系列、Nacos等源码解读、热门面试题、架构设计等。除此之外还有不少文章等你来细细品味,更多惊喜等着你哦
🍅uniapp微信小程序🍅面试题软考题免费使用,还可以使用微信支付,扫码加群。由于维护成本问题得不到解决,可能将停止线上维护。
抖音体验版
🍅文末获取联系🍅精彩专栏推荐订阅👇🏻👇🏻 不然下次找不到哟
Java项目案例《100套》
https://blog.csdn.net/qq_57756904/category_12173599.html
uniapp小程序《100套》https://blog.csdn.net/qq_57756904/category_12173599.html
有需求代码永远写不完,而方法才是破解之道,抖音有实战视频课程,某马某千等培训都是2万左右,甚至广东有本科院校单单一年就得3万4年就12万学费,而且还没有包括吃饭的钱。所以很划算了。另外博客左侧有源码阅读专栏,对于求职有很大帮助,当然对于工作也是有指导意义等。在大城市求职,你面试来回一趟多多少少都在12块左右,而且一般不会一次性就通过,还得面试几家。而如果你对源码以及微服务等有深度认识,这无疑给你的面试添砖加瓦更上一层楼。
最后再送一句:最好是学会了,而不是学废了!!
目录
前言
早在大学懵懵懂懂的阶段,本人就接受了SpringBoot、SpringCloud、MyBatis框架教育,如果没有她的启蒙本人应该也不会比较顺利踏进软件行业吧,即使进了也会一路布满荆棘。还是非常感谢学校的教育之恩,带我从一个从来没有摸过电脑就敢闯计算机行业。也非常感谢一个同学,因为在本人空闲的时间甚至可以说无所事事的时候,带我走进了前端大框架Vue的世界。大三那年,正好碰上疫情,刚好有充足的时间去研究Vue,一次次打击与十万个为什么,不得不说太苦了。功夫不负有心人,我还是有幸摸索出了Vue的的一些东西,至少可以改动页面调通后端了。那年在孤独无助之下,一个人扛起了整个小组微服务大作业的项目,而且还是前后端完全分离的SpringCloud+SpringBoot+MyBatis+MySQL+Vue2+Elementui等。大三拿下了全国英语六级,同年拿下了软考软件设计师中级证书。
大四那年,走出了学校大门,凭借一个软件设计师中级证书,赢得了本人第一个老板的赏识。那年也扛下了整个已经高度封装前端Vue项目的统一系统风格优化,让一个凌乱不堪的系统变得井井有条,获得了老总的高度认可。公司平时会组织召开会议,老板谈论时说:“你们要不断学习,我在教育这块一个月支出就10万,去培养小孩的各个方面,将来小孩带给你的回报将是非常丰厚的”。确实本人也是认同的,本人也花了10万在教育方面,只不过本人是分4年付款罢了。本人出生于一个普普通通的农村家庭,非常感谢老妈四处借款,以及这么多年的经济支持。这些人情,改日一一报答你们。滴水之恩当涌泉相报。
第二家公司技术栈是微服务,非常吸引我,于是本人依依不舍地离开了自己的舒适小窝,搬家到了一个陌生的地方,开启了新的人生旅程。那个时候,接触了最先进的技术,内心欣喜若狂,构思着那美好的未来。
那时候整个人都是精神紧绷的,那个时候本人的步伐都是很匆匆的,那个时候的我几乎可以说把时间都花在了研究上面,每天工作日下班后吃完饭马上就打开电脑,每个周末都是在打开电脑的路上,因此错过了很多美好。假如身边有位大佬指导,我不需要走那么长的路,走那些坑坑洼洼的路,走那些布满泥泞的路,甚至是掉进沼泽。
所幸的是本人进入了华为大厂,有意思的是有一个月带薪培训,而且公司资源非常丰富,文档博客高端大气上档次低调奢华有内涵。本人也总算是开了眼界,当然大公司就是不一样,拥有完善的管理体系,还有不定时的技术分享以及业务分享,还有导师一对一带你快速进入工作状态。以前所在的公司,去到一个星期内你就领着任务开始干活了。在进入这家公司之前,本人也已经把上家公司的微服务项目研究搭建起来了,只不过当时还有着知其然而不知其所以然。后来的我带着大学期间,用自己干兼职赚来的钱,买的MyBatis核心原理以及设计模式,以及这么多年在大大小小的公司穿梭积累的经验,还有对Spring、SpringCloud、Nacos、RocketMQ等源码框架的研究,终于梳理通了公司的项目架构。于是本人以多年的经验积累,最近再次把框架搭建了一边,这次用视频记录了多年的战果。分析了重要组件的职责,画了系统架构图,以一种来源于生活的思路去打开大家软件认识的壁垒。
2023年,以以往的经验,自研了uniapp微信小程序,基于Vue3+TypeScript+Uniapp,发布上线到了微信端。2024年初,以同一套代码,部署到了客户量在国内数一数二的抖音,实现了多端部署。当然,这套框架也给软件商业带来了一定的价值。在B站可以看看企业级解决方案Uniapp微信小程序实战。2024年同样实现了Shell脚本自动部署的技术突破,尤其在微服务方面带来了更高的便捷性,也分享在了B站,感兴趣的可以过去看看Shell脚本部署SpringCloud实战
如今老哥也将近三十了,精力有限。所幸的是也找到了打开软件技术的钥匙,老哥在后端、前端、测试、部署等方面都积累了经验,更多技术分享在视频里面,B站还有抖音。以下是SpringCloud Alibaba的视频内容
单点登录架构:
客户端服务端架构:
抖音视频:抖音搜索 卡布奇诺海晨 找到小店
除了上面的这些内容还有一些在补充的路上,企业级干货满满。抖音搜索 卡布奇诺海晨
B站视频教程
项目结构:
工具类之一:
package org.example.common.utils;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author CeaM
* 2024/4/28
*/
@Slf4j
@Component
@SuppressWarnings("all")
public class RedisUtils {
private final ObjectMapper mapper;
/**
* 从 spring 容器中注入自定义的 redisTemplate
*/
private final RedisTemplate<String, Object> redisTemplate;
public RedisUtils(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
}
/**
* 对 redis 中指定键对应的数据设置失效时间
*
* @param key 键
* @param time 时间(秒)
*/
public boolean expire(String key, long time) {
boolean result = false;
try {
if (!ObjectUtils.isEmpty(key)) {
result = this.redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
return result;
}
/**
* 从 redis 中根据指定的 key 获取已设置的过期时间
*
* @param key 键,不能为null
* @return 时间(秒),返回0代表为永久有效
*/
public long getExpire(String key) {
long time = 0L;
try {
if (!ObjectUtils.isEmpty(key)) {
time = this.redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
return time;
}
/**
* 判断 redis 中是否存在指定的 key
*
* @param key 键,不能为null
* @return true表示存在,false表示不存在
*/
public boolean exists(String key) {
boolean result = false;
try {
if (!ObjectUtils.isEmpty(key)) {
result = this.redisTemplate.hasKey(key);
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
return result;
}
/**
* 从 redis 中移除指定 key 对应的数据
*
* @param keys 可以传一个值或多个
*/
public long remove(String... keys) {
long count = 0L;
if (keys != null && keys.length > 0) {
if (keys.length == 1) {
boolean result = this.redisTemplate.delete(keys[0]);
if (result) {
count = keys.length;
}
} else {
count = this.redisTemplate.delete(CollectionUtils.arrayToList(keys));
}
}
return count;
}
// ============================ String =============================
/**
* 从 redis 中获取指定 key 对应的 string 数据
*
* @param key 键,不能为null
* @return key 对应的字符串数据
*/
public Object get(String key) {
Object t = null;
try {
if (!ObjectUtils.isEmpty(key)) {
t = this.redisTemplate.opsForValue().get(key);
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
return t;
}
/**
* 从 redis 中获取指定 key 对应的 string 数据,并转换为 T 类型
*
* @param key 键,不能为null
* @param clazz 类型,从 redis 获取后的对象直接转换为 T 类型
* @return key 对应的数据
*/
public <T> T get(String key, Class<T> clazz) {
T t = null;
try {
if (!ObjectUtils.isEmpty(key)) {
String str = (String) this.redisTemplate.opsForValue().get(key);
t = mapper.readValue(str, clazz);
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return null;
}
return t;
}
/**
* 判断 redis 中指定 key 的数据对应偏移位置的 bit 位是否为 1
*
* @param key 键,不能为null
* @param offset 偏移位置
* @return true表示存在,false表示不存在
*/
public boolean getBit(String key, long offset) {
boolean result = false;
try {
if (!ObjectUtils.isEmpty(key)) {
result = this.redisTemplate.opsForValue().getBit(key, offset);
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
return result;
}
/**
* 将指定的 key, value 放到 redis 中
*
* @param key 键,不能为null
* @param value 值,不能为null
* @return true表示成功,false表示失败
*/
public <T> boolean set(String key, T value) {
boolean result = false;
try {
if (!ObjectUtils.isEmpty(key)) {
this.redisTemplate.opsForValue().set(key, value);
result = true;
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
return result;
}
/**
* 将指定的 key, value 放到 redis 中,并设置过期时间
*
* @param key 键,不能为null
* @param value 值,不能为null
* @param time 时间(秒),time要大于0,如果time小于等于0,将设置无限期
* @return true表示成功,false表示失败
*/
public <T> boolean set(String key, T value, long time) {
try {
if (time > 0) {
this.redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
this.set(key, value);
}
return true;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 将 redis 中指定 key 对应数据的偏移位置的 bit 位设置为 0/1
*
* @param key 键,不能为null
* @param offset 偏移位置
* @param flag true表示设置为1,false表示设置为0
* @return true表示成功,false表示失败
*/
public boolean setBit(String key, long offset, boolean flag) {
boolean result = false;
try {
if (!ObjectUtils.isEmpty(key)) {
this.redisTemplate.opsForValue().setBit(key, offset, flag);
result = true;
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
return result;
}
/**
* 对 redis 中指定 key 的数据递增,并返回递增后的值
*
* @param key 键,不能为null
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0。");
}
return this.redisTemplate.opsForValue().increment(key, delta);
}
/**
* 对 redis 中指定 key 的数据递减,并返回递减后的值
*
* @param key 键,不能为null
* @param delta 要减少几(大于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0。");
}
return this.redisTemplate.opsForValue().decrement(key, delta);
}
// ================================ hashmap=================================
/**
* 判断 redis 中指定 key 对应的 hash 表中是否有 hashKey
*
* @param key 键,不能为null
* @param hashKey hash表中的键,不能为null
* @return true表示存在,false表示不存在
*/
public boolean hExists(String key, String hashKey) {
return this.redisTemplate.opsForHash().hasKey(key, hashKey);
}
/**
* 从 redis 中获取指定 key 对应的 hash 表中的指定 hashKey 所对应的值
*
* @param key 键,不能为null
* @param hashKey hash表中的键,不能为null
* @return 值
*/
public <T> T hGet(String key, String hashKey) {
return (T) this.redisTemplate.opsForHash().get(key, hashKey);
}
/**
* 向 redis 中指定 key 对应的 hash 表(如果 hash 表不存在则自动创建)中放入 hashKey,value 数据
*
* @param key 键,不能为null
* @param hashKey hash表中的键,不能为null
* @param value 值,不能为null
* @return true表示成功,false表示失败
*/
public <T> boolean hSet(String key, String hashKey, T value) {
try {
this.redisTemplate.opsForHash().put(key, hashKey, value);
return true;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 向 redis 中指定 key 对应的 hash 表(如果 hash 表不存在则自动创建)中放入 hashKey,value 数据,并设置过期时间
*
* @param key 键,不能为null
* @param hashKey hash表中的键,不能为null
* @param value 值,不能为null
* @param time 过期时间(秒),注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true表示成功,false表示失败
*/
public <T> boolean hSet(String key, String hashKey, T value, long time) {
try {
this.redisTemplate.opsForHash().put(key, hashKey, value);
if (time > 0) {
this.expire(key, time);
}
return true;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 删除 redis 中指定 key 对应的 hash 表中等于 hashKeys 的数据
*
* @param key 键,不能为null
* @param hashKeys hash表中的键,可以使多个,不能为null
*/
public <T> void hDel(String key, T... hashKeys) {
this.redisTemplate.opsForHash().delete(key, hashKeys);
}
/**
* 从 redis 中获取指定 key 对应的 hash 表,并返回相应的 map 对象
*
* @param key 键,不能为null
* @return map对象,包含所有的键值对
*/
public Map<?, ?> hmGet(String key) {
return this.redisTemplate.opsForHash().entries(key);
}
/**
* 向 redis 中放入指定 key,并设置对应的数据类型为 map
*
* @param key 键,不能为null
* @param map 多个键值对应的map,不能为null
* @return true表示成功,false表示失败
*/
public boolean hmSet(String key, Map<String, ?> map) {
try {
this.redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 向 redis 中放入指定 key,并设置对应的数据类型为 map 以及过期时间
*
* @param key 键,不能为null
* @param map 对应多个键值,不能为null
* @param time 时间(秒),time要大于0,如果time小于等于0,将设置无限期
* @return true表示成功,false表示失败
*/
public boolean hmSet(String key, Map<String, ?> map, long time) {
try {
this.redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
this.expire(key, time);
}
return true;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 对 redis 中指定 key 对应的 hash 表(如果 hash 表不存在则自动创建)递增,并返回新增后的值
*
* @param key 键,不能为null
* @param item 项,不能为null
* @param delta 要增加几(大于0)
* @return 新增后的值
*/
public double hIncr(String key, String item, double delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0。");
}
return this.redisTemplate.opsForHash().increment(key, item, delta);
}
/**
* 对 redis 中指定 key 对应的 hash 表(如果 hash 表不存在则自动创建)递增,并返回新增后的值
*
* @param key 键,不能为null
* @param item 项,不能为null
* @param delta 要减少几(大于0)
* @return
*/
public double hDecr(String key, String item, double delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0。");
}
return this.redisTemplate.opsForHash().increment(key, item, -delta);
}
/**
* 从 redis 中移除指定 key 对应 hash 表中键为 values 的数据
*
* @param key 键,不能为null
* @param values 值,不能为null
* @return 移除的个数
*/
public <T> long hRemove(String key, T... values) {
try {
Long count = this.redisTemplate.opsForHash().delete(key, values);
return count;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return 0;
}
}
// ============================set=============================
/**
* 判断 redis 中是否存在指定 key 对应的 set 对象
*
* @param key 键,不能为null
* @param value 值,不能为null
* @return true表示存在,false表示不存在
*/
public <T> boolean sExists(String key, T value) {
try {
return this.redisTemplate.opsForSet().isMember(key, value);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 从 redis 中根据指定 key 对应的值,并返回 set 对象
*
* @param key 键,不能为null
* @return
*/
public Set<?> sGet(String key) {
try {
return this.redisTemplate.opsForSet().members(key);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return null;
}
}
/**
* 向 redis 中放入指定 key 和数据,并设置其数据类型为 set
*
* @param key 键,不能为null
* @param values 值,不能为null
* @return 成功个数
*/
public <T> long sSet(String key, T... values) {
try {
return this.redisTemplate.opsForSet().add(key, values);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return 0;
}
}
/**
* 向 redis 中放入指定 key 和数据,并设置其数据类型为 set 以及过期时间
*
* @param key 键,不能为null
* @param time 过期时间(秒),注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @param values 值,不能为null
* @return 成功个数
*/
public <T> long sSet(String key, long time, T... values) {
try {
Long count = this.redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
return count;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return 0;
}
}
/**
* 获取 redis 中指定 key 对应 set 的大小
*
* @param key 键,不能为null
*/
public long sSize(String key) {
try {
return this.redisTemplate.opsForSet().size(key);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return 0;
}
}
/**
* 从 redis 中移除指定 key 对应 set 中键为 values 的数据
*
* @param key 键,不能为null
* @param values 值,不能为null
* @return 移除的个数
*/
public <T> long sRemove(String key, T... values) {
try {
return this.redisTemplate.opsForSet().remove(key, values);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return 0;
}
}
// =============================== list =================================
/**
* 从 redis 中获取指定 key 对应 list 的大小
*
* @param key 键,不能为null
*/
public long lSize(String key) {
try {
return this.redisTemplate.opsForList().size(key);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return 0;
}
}
/**
* 从 redis 中获取指定 key 对应 list 中 index 位置的值
*
* @param key 键,不能为null
* @param index 当index>=0时,0为表头,1为第二个元素,依次类推;当index<0时,-1为表尾,-2为倒数第二个元素,依次类推
*/
public <T> T lIndex(String key, long index) {
try {
return (T) this.redisTemplate.opsForList().index(key, index);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return null;
}
}
/**
* 从 redis 中获取指定 key 对应 list 指定范围的值(start~end设置为0~-1将返回所有值)
*
* @param key 键,不能为null
* @param start 起始位置,0表示起始位置
* @param end 结束位置,-1表示结束位置
* @return
*/
public List<?> lGet(String key, long start, long end) {
try {
return this.redisTemplate.opsForList().range(key, start, end);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return null;
}
}
/**
* 向 redis 中放入指定 key,并设置数组类型为 list,将 value 加入到 list 尾部
*
* @param key 键,不能为null
* @param value 值,不能为null
* @return
*/
public <T> boolean lSet(String key, T value) {
try {
this.redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 向 redis 中放入指定 key,并设置数组类型为 list,将 value 加入到 list 尾部,同时设置过期时间
*
* @param key 键,不能为null
* @param value 值,不能为null
* @param time 时间(秒),time要大于0,如果time小于等于0,将设置无限期
* @return
*/
public <T> boolean lSet(String key, T value, long time) {
try {
this.redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
this.expire(key, time);
}
return true;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 向 redis 中放入指定 key,并设置数组类型为 list,并以 value 填入 list
*
* @param key 键,不能为null
* @param value 值,不能为null
* @return
*/
public boolean lSet(String key, List value) {
try {
this.redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 向 redis 中放入指定 key,并设置数组类型为 list,并以 value 填入 list,同时设置过期时间
*
* @param key 键,不能为null
* @param value 值,不能为null
* @param time 时间(秒),time要大于0,如果time小于等于0,将设置无限期
* @return
*/
public boolean lSet(String key, List value, long time) {
try {
this.redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
this.expire(key, time);
}
return true;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 将 redis 中指定 key 对应的 list 数据中指定 index 位置的数据更新为 value
*
* @param key 键,不能为null
* @param index 索引
* @param value 值,不能为null
* @return
*/
public <T> boolean lUpdate(String key, long index, T value) {
try {
this.redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return false;
}
}
/**
* 从 redis 中指定 key 对应的 list 中移除 n 个值为 value 的数据
*
* @param key 键,不能为null
* @param count 移除多少个
* @param value 值,不能为null
* @return 移除的个数
*/
public <T> long lRemove(String key, long count, T value) {
try {
return this.redisTemplate.opsForList().remove(key, count, value);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return 0;
}
}
public boolean setNx(String key, Serializable value, long exptime) {
return redisTemplate.opsForValue().setIfAbsent(key, value, exptime, TimeUnit.SECONDS);
}
}
这是使用了一个清晰录记视频的软件录记的,在5月份初开放,敬请期待!这是企业级的有一定的挑战性,由0到1的搭建过程,这次也给自己微微的的带来了新的认识,所以极力推荐,视听结合。