Redis框架与SpringBoot的整合及详细学习汇总

news/2024/5/4 10:37:09/文章来源:https://blog.csdn.net/swy2560666141/article/details/130317328

目录

springBoot整合Redis

Redis 的优势

Redis安装

Redis数据类型

springboot操作Redis

springboot 配置redis

RedisTemplate及其相关方法

springBoot实现上传下载

RedisTemplate及其相关方法

springBoot实现上传下载

springBoot CORS(跨域资源共享)

springBoot聚合工程


springBoot整合Redis

Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库.

Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。

  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。

  • Redis支持数据的备份,即master-slave模式的数据备份。

Redis 的优势

  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s

  • 丰富的数据类型 – Redis支持二进制案例的 String, List, Hash, Set 及 zset数据类型操作。

  • 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。

  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性

  • Redis 是单线程的,6.0版本开始支持开启多线程。

Redis安装

下载地址:Releases · tporadowski/redis · GitHub。

解压下载后的压缩文件,解压后文件列表如下:

 

 

使用cmd窗口打开Redis

安装Redis数据库客户端

 

库相关指令:

flushdb  清空当前库
​
flushall  清空所有库
​
select   1    切换库

key的相关指令

指令作用语法
del删除一个或多个keydel keyname
exists判断一个或多个key是否存在,多个key时有一个存在则就会返回1exists keyname
expire设置key的生存时间 单位 :秒expire keyname seconds
keys查询所有匹配模式的key ?匹配一个字符 *匹配0-n个字符 [] 满足其中的一个key * key h?llo
move将key移动到指定的库中move keyname db
pexpire设置key的生存时间 单位 :毫秒 设置成功返回1 否则返回0pexpire keyname milliseconds
ttl以秒为单位返回key的剩余生存时间,返回-1表示永久存储,-2表示key不存在ttl keyname
randomkey从当前数据库中随机的返回一个keyrandomkey
rename重命名key,成功返回ok,否则返回错误信息。rename key newkey
type返回key所存储的值的类型type keyname

Redis数据类型

1.String(字符串)

  • string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。

  • string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。

  • string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

操作指令:

命令描述
SET设置指定 key 的值
GET获取指定 key 的值。
GETRANGE返回 key 中字符串值的子字符
GETSET将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
SETEX将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。
SETNX只有在 key 不存在时设置 key 的值
STRLEN返回 key 所储存的字符串值的长度。
MSET同时设置一个或多个 key-value 对。
MSETNX同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
INCR将 key 中储存的数字值增一
INCRBY将 key 所储存的值加上给定的增量值(increment)
INCRBYFLOAT将 key 所储存的值加上给定的浮点增量值(increment)
DECR将 key 中储存的数字值减一。
DECRBYkey 所储存的值减去给定的减量值(decrement)
APPEND如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾

2.Hash(哈希)

  • Redis hash 是一个键值(key=>value)对集合。

  • Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

操作指令:

命令描述
hset设置一个key/value对
hget获取key对应的value
hgetall获取所有的key/value对
hdel删除某个key/value对
hexists判断一个key是否存在
hkeys获取所有的key
hvals获取所有的value
hmset设置多个key/value
hmget获取多个key的value
hsetnx设置一个不存在的key的值
hincrby为value的值进行加法运算
hincrbyfloat为value的值进行加浮点类型值运算

3.List(列表)

  • Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

操作指令

命令描述
LINDEX通过索引获取列表中的元素 lindex lists 0
LINSERT key BEFORE|AFTER在列表的元素前或者后插入元素
LLEN获取列表长度
LPOP移出并获取列表的第一个元素
LPUSH将一个或多个值插入到列表头部
LPUSHX将一个值插入到已存在的列表头部
LRANGE获取列表指定范围内的元素 (0 -1)
LREM移除列表重复元素
LSET通过索引设置列表元素的值 ,但是索引必须存在,实质是根据索引修改值
LTRIM对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
RPOP移除列表的最后一个元素,返回值为移除的元素
RPOPLPUSH移除列表的最后一个元素,并将该元素添加到另一个列表并返回
RPUSH在列表中添加一个或多个值
RPUSHX为已存在的列表添加值

4.Set(集合)

  • Redis 的 Set 是 string 类型的无序集合。

  • 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

操作指令:

命令描述
sadd为集合添加元素
smembers显示集合中所有元素 (无序)
scard返回集合中元素的个数
spop随机返回一个元素,并将这个元素删除
smove从一个集合向令一个集合中转移元素
srem从集合中删除一个元素
sismember判断集合中是否包含这个元素
srandmember随机返回一个元素
sinter求交集
sunion求和集

5.zset(sorted set:有序集合)

  • Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

  • 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

  • zset的成员是唯一的,但分数(score)却可以重复。

操作指令:

命令描述
zadd添加一个有序集合元素
zcard返回集合中元素的个数
zrange升序 zrevrange降序返回一个范围内的元素
zrangebyscore按照分数查找一个范围内的元素
zrank返回排名
zrevrank倒叙排名
zscore显示某个元素的分数
zrem移除某个元素
zincrby给某个特定元素加分

springboot操作Redis

spring boot data redis中提供了RedisTemplate和StringRedisTemplate,其中StringRedisTemplate是Redistemplate的子类,两个方法基本一致,不同之处主要体现在操作的数据类型不同,RedisTemplate中的两个泛型都是Object,意味着存储的key和value都可以是一个对象,而StringRedisTemplate的两个泛型都是String,意味着StringRedisTemplate的key和value都只能是字符串。

引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

springboot 配置redis

 

RedisTemplate及其相关方法

1.RedisTemplate

Spring封装了RedisTemplate对象来进行对Redis的各种操作,它支持所有的Redis原生的api。RedisTemplate位于spring-data-redis包下。RedisTemplate提供了redis各种操作、异常处理及序列化,支持发布订阅。

2.Redis5种数据结构操作

  • redisTemplate.opsForValue(); //操作字符串

  • redisTemplate.opsForHash(); //操作hash

  • redisTemplate.opsForList(); //操作list

  • redisTemplate.opsForSet(); //操作set

  • redisTemplate.opsForZSet(); //操作有序set

或者:

  • redistempalate.boundValueOps

  • redistempalate.boundSetOps

  • redistempalate.boundListOps

  • redistempalate.boundHashOps

  • redistempalate.boundZSetOps

opsForXXX和boundXXXOps的区别:XXX为value的类型,前者获取一个operator,但是没有指定操作的对象(key),可以在一个连接(事务)内操作多个key以及对应的value;后者获取了一个指定操作对象(key)的operator,在一个连接(事务)内只能操作这个key对应的value。

SpringBootTest 实现Redis数据库增删改查

/*** 使用RedisTemplate 操作Redis数据的不同数据类型*/
@SpringBootTest
public class Springbootday03ApplicationTests {@Autowiredprivate RedisTemplate<String, String> redisTemplate;/*** String 类型数据操作*/@Testpublic void operateString() {//添加值redisTemplate.opsForValue().set("str", "strValue1");//添加值  判定是否存在 存在则不添加Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("str", "strAbsent");System.out.println("str设置成功:" + aBoolean);//获取值String str = redisTemplate.opsForValue().get("str");System.out.println("str = " + str);//更新值redisTemplate.opsForValue().set("str", "strValue2");str = redisTemplate.opsForValue().get("str");System.out.println("newStr = " + str);//删除值Boolean b = redisTemplate.delete("str");System.out.println("str删除成功:" + b);}/*** 操作string类型数据  设置过期时间*/@Testpublic void operateString2() {redisTemplate.opsForValue().set("str", "strTimeout", 10, TimeUnit.SECONDS);//判定值是否存在 不存在则设置值 同时设置过期时间Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("str2", "strTimeoutAbsent", 20, TimeUnit.SECONDS);System.out.println("setIfAbsent:" + aBoolean);}/*** 操作hash类型数据*/@Testpublic void operateHash() {//添加hash类型数据  key - valueredisTemplate.opsForHash().put("hash", "username", "admin");//修改hash类型数据redisTemplate.opsForHash().put("hash", "username", "tom");redisTemplate.opsForHash().put("hash", "password", "123456");//添加hash类型数据  key - mapHashMap<String, String> map = new HashMap<>();map.put("driverName", "com.mysql.jdbc.Driver");map.put("url", "jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC");redisTemplate.opsForHash().putAll("hash", map);//获取hash类型数据  entriesMap<Object, Object> hash = redisTemplate.opsForHash().entries("hash");hash.forEach((key, value) -> {System.out.println(key + "::" + value);});//获取所有的keySet<Object> keys = redisTemplate.opsForHash().keys("hash");for (Object key : keys) {System.out.println("key:" + key);}//获取所有valueList<Object> values = redisTemplate.opsForHash().values("hash");values.forEach(value -> System.out.println("value:" + value));//删除hash类型数据  删除一个  返回删除的个数Long delete = redisTemplate.opsForHash().delete("hash", "username");System.out.println("delete = " + delete);//删除hash类型数据  删除多个  返回删除的个数delete = redisTemplate.opsForHash().delete("hash", "username", "password", "driverName");System.out.println("delete = " + delete);//删除hash类型数据  删除所有Boolean delHash = redisTemplate.delete("hash");System.out.println("delHah:" + delHash);}/*** 操作List类型  有序 可重复*/@Testpublic void operateList() {//左压栈// redisTemplate.opsForList().leftPush("list", "listValue1");// redisTemplate.opsForList().leftPush("list", "listValue1");// redisTemplate.opsForList().leftPush("list", "listValue2");// redisTemplate.opsForList().leftPush("list", "listValue3");//右压栈redisTemplate.opsForList().rightPush("list", "listValue0");redisTemplate.opsForList().rightPush("list", "listValue2");redisTemplate.opsForList().rightPush("list", "listValue0");//左出栈String list1 = redisTemplate.opsForList().leftPop("list");System.out.println("leftPop list1 = " + list1);//右出栈String list2 = redisTemplate.opsForList().rightPop("list");System.out.println("rightPop list2 = " + list2);//获取所有数据List<String> lists = redisTemplate.opsForList().range("list", 0, 		        redisTemplate.opsForList().size("list") - 1);lists.forEach(list -> System.out.println(list));//设置指定位置的数据redisTemplate.opsForList().set("list", 0, "listValue0");/*** 从存储在键中的列表中删除等于值的元素的第一个计数事件。* count> 0:删除等于从左到右移动的值的第一个元素;* count< 0:删除等于从右到左移动的值的第一个元素;* count = 0:删除等于value的所有元素。*/Long remove = redisTemplate.opsForList().remove("list", -1, "listValue0");System.out.println("remove:" + remove);//删除指定key的list数据Boolean list = redisTemplate.delete("list");System.out.println("list集合删除成功:" + list);}/*** 操作Set类型  无序 不可重复*/@Testpublic void operateSet() {//设置set值redisTemplate.opsForSet().add("set", "setValue0");redisTemplate.opsForSet().add("set", "setValue0");redisTemplate.opsForSet().add("set", "setValue1");//判定是否包含Boolean member = redisTemplate.opsForSet().isMember("set", "setValue0");System.out.println("isMember:" + member);//删除set中的值Long remove = redisTemplate.opsForSet().remove("set", "setValue0");System.out.println("remove = " + remove);//获取set类型值Set<String> set = redisTemplate.opsForSet().members("set");set.forEach(str -> {System.out.println("str = " + str);});}/*** 操作 ZSet  有序 不可重复*/@Testpublic void operateZSet() {//存储值Boolean add = redisTemplate.opsForZSet().add("zset", "zsetValue0", 10);System.out.println("add = " + add);System.out.println("add = " + add);add = redisTemplate.opsForZSet().add("zset", "zsetValue2", 2);System.out.println("add = " + add);//获取值// Boolean zset = redisTemplate.delete("zset");// System.out.println("delete zset = " + zset);}
}

 

Redis工具类的封装

 
/*** Redis 工具类* @author mosin* date 2021/11/30* @version 1.0*/
@Component
public final class RedisUtil {private RedisUtil(){};@Autowiredprivate RedisTemplate<String,String> redisTemplate;//设置值public void  setValue(String key,String value){redisTemplate.opsForValue().set(key, value);}// 设置值 同时设置有效时间public void setValue(String key, String value, Long timeOut, TimeUnit timeUnit){redisTemplate.opsForValue().setIfAbsent(key, value, timeOut, timeUnit);}//设置值 没有则设置 有则不设置public void  setNx(String key,String value){redisTemplate.opsForValue().setIfAbsent(key, value);}//设置值 没有则设置 同时设置有效时间 有则不设置public void  setNx(String key,String value,long timeOut,TimeUnit timeUnit){redisTemplate.opsForValue().setIfAbsent(key, value,timeOut,timeUnit);}//删除值public boolean del(String key){return redisTemplate.delete(key);}//获取值public String getValue(String key){return  redisTemplate.opsForValue().get(key);}
}

业务实践(redis存储token,实现非法请求拦截)

1.编写拦截器

2.配置拦截器  

3.编写统一返回数据格式类  

4.编写控制器

@Controller
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate RedisUtil redisUtil;@ResponseBody@RequestMapping("/login")public Object login(User user) throws JsonProcessingException {User usr = User.builder().id(1).name("admin").password("123456").build();//获取token  放入redisString token = UUID.randomUUID().toString().replace("-", "");//将user 转为json格式放入 redisObjectMapper objectMapper = new ObjectMapper();String s1 = objectMapper.writeValueAsString(usr);//将 token 和用户信息存入 redisredisUtil.setValue(token, s1, 2L, TimeUnit.MINUTES);//将token 存入map集合返回HashMap<String, String> map = new HashMap<>();map.put("token", token);return map;}@ResponseBody@RequestMapping("/register")public Object register(User user){HashMap<String, String> map = new HashMap<>();map.put("msg", "ok");return map;}@ResponseBody@RequestMapping("/add")public Object add(User user){HashMap<String, String> map = new HashMap<>();map.put("msg", "ok");return map;}
}

 

5.编写业务类和Mapper接口

6.使用postman接口测试工具测试接口

springBoot实现上传下载

1.编写控制器

/*** 文件上传下载控制类* @author mosin* date 2021/12/1* @version 1.0*/
@Controller
@RequestMapping("/file")
public class FileController {@RequestMapping("/toupload")public String toUpload(){ //跳转上传页return "upload";}@RequestMapping("/upload")public Object fileUpload(MultipartFile file, Model model){if( !file.isEmpty()){String originalFilename = file.getOriginalFilename();String uuid = UUID.randomUUID().toString().replace("-", "");String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));String fileName = uuid+suffix;File f = new File("D:\\upload",fileName);try {file.transferTo(f);model.addAttribute("downloadName", fileName);model.addAttribute("originalFilename", originalFilename);} catch (IOException e) {e.printStackTrace();}}return "download";}@RequestMapping("/download")@ResponseBodypublic Object fileDownLoad(String fileName, HttpServletResponse response){HashMap<String, String> map = new HashMap<>();try {FileInputStream fis= new FileInputStream(new File("D:\\upload", fileName));//设置以附件形式输出response.setHeader("Content-disposition", "attachment; filename="+fileName);//获取输出流ServletOutputStream outputStream = response.getOutputStream();//org.springframework.util.FileCopyUtils  工具类FileCopyUtils.copy(fis, outputStream);map.put("msg", "上传成功!");} catch (Exception e) {e.printStackTrace();map.put("msg", "上传失败!");}return map ;}
}

2.编写上传页面

3.编写下载页面  

设置上传文件大小限制 ​​​​​​​ 

RedisTemplate及其相关方法

1.RedisTemplate

Spring封装了RedisTemplate对象来进行对Redis的各种操作,它支持所有的Redis原生的api。RedisTemplate位于spring-data-redis包下。RedisTemplate提供了redis各种操作、异常处理及序列化,支持发布订阅。

2.Redis5种数据结构操作

  • redisTemplate.opsForValue(); //操作字符串

  • redisTemplate.opsForHash(); //操作hash

  • redisTemplate.opsForList(); //操作list

  • redisTemplate.opsForSet(); //操作set

  • redisTemplate.opsForZSet(); //操作有序set

或者:

  • redistempalate.boundValueOps

  • redistempalate.boundSetOps

  • redistempalate.boundListOps

  • redistempalate.boundHashOps

  • redistempalate.boundZSetOps

opsForXXX和boundXXXOps的区别:XXX为value的类型,前者获取一个operator,但是没有指定操作的对象(key),可以在一个连接(事务)内操作多个key以及对应的value;后者获取了一个指定操作对象(key)的operator,在一个连接(事务)内只能操作这个key对应的value。

SpringBootTest 实现Redis数据库增删改查

/*** 使用RedisTemplate 操作Redis数据的不同数据类型*/
@SpringBootTest
public class Springbootday03ApplicationTests {@Autowiredprivate RedisTemplate<String, String> redisTemplate;/*** String 类型数据操作*/@Testpublic void operateString() {//添加值redisTemplate.opsForValue().set("str", "strValue1");//添加值  判定是否存在 存在则不添加Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("str", "strAbsent");System.out.println("str设置成功:" + aBoolean);//获取值String str = redisTemplate.opsForValue().get("str");System.out.println("str = " + str);//更新值redisTemplate.opsForValue().set("str", "strValue2");str = redisTemplate.opsForValue().get("str");System.out.println("newStr = " + str);//删除值Boolean b = redisTemplate.delete("str");System.out.println("str删除成功:" + b);}/*** 操作string类型数据  设置过期时间*/@Testpublic void operateString2() {redisTemplate.opsForValue().set("str", "strTimeout", 10, TimeUnit.SECONDS);//判定值是否存在 不存在则设置值 同时设置过期时间Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("str2", "strTimeoutAbsent", 20, TimeUnit.SECONDS);System.out.println("setIfAbsent:" + aBoolean);}/*** 操作hash类型数据*/@Testpublic void operateHash() {//添加hash类型数据  key - valueredisTemplate.opsForHash().put("hash", "username", "admin");//修改hash类型数据redisTemplate.opsForHash().put("hash", "username", "tom");redisTemplate.opsForHash().put("hash", "password", "123456");//添加hash类型数据  key - mapHashMap<String, String> map = new HashMap<>();map.put("driverName", "com.mysql.jdbc.Driver");map.put("url", "jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC");redisTemplate.opsForHash().putAll("hash", map);//获取hash类型数据  entriesMap<Object, Object> hash = redisTemplate.opsForHash().entries("hash");hash.forEach((key, value) -> {System.out.println(key + "::" + value);});//获取所有的keySet<Object> keys = redisTemplate.opsForHash().keys("hash");for (Object key : keys) {System.out.println("key:" + key);}//获取所有valueList<Object> values = redisTemplate.opsForHash().values("hash");values.forEach(value -> System.out.println("value:" + value));//删除hash类型数据  删除一个  返回删除的个数Long delete = redisTemplate.opsForHash().delete("hash", "username");System.out.println("delete = " + delete);//删除hash类型数据  删除多个  返回删除的个数delete = redisTemplate.opsForHash().delete("hash", "username", "password", "driverName");System.out.println("delete = " + delete);//删除hash类型数据  删除所有Boolean delHash = redisTemplate.delete("hash");System.out.println("delHah:" + delHash);}/*** 操作List类型  有序 可重复*/@Testpublic void operateList() {//左压栈// redisTemplate.opsForList().leftPush("list", "listValue1");// redisTemplate.opsForList().leftPush("list", "listValue1");// redisTemplate.opsForList().leftPush("list", "listValue2");// redisTemplate.opsForList().leftPush("list", "listValue3");//右压栈redisTemplate.opsForList().rightPush("list", "listValue0");redisTemplate.opsForList().rightPush("list", "listValue2");redisTemplate.opsForList().rightPush("list", "listValue0");//左出栈String list1 = redisTemplate.opsForList().leftPop("list");System.out.println("leftPop list1 = " + list1);//右出栈String list2 = redisTemplate.opsForList().rightPop("list");System.out.println("rightPop list2 = " + list2);//获取所有数据List<String> lists = redisTemplate.opsForList().range("list", 0, 		        redisTemplate.opsForList().size("list") - 1);lists.forEach(list -> System.out.println(list));//设置指定位置的数据redisTemplate.opsForList().set("list", 0, "listValue0");/*** 从存储在键中的列表中删除等于值的元素的第一个计数事件。* count> 0:删除等于从左到右移动的值的第一个元素;* count< 0:删除等于从右到左移动的值的第一个元素;* count = 0:删除等于value的所有元素。*/Long remove = redisTemplate.opsForList().remove("list", -1, "listValue0");System.out.println("remove:" + remove);//删除指定key的list数据Boolean list = redisTemplate.delete("list");System.out.println("list集合删除成功:" + list);}/*** 操作Set类型  无序 不可重复*/@Testpublic void operateSet() {//设置set值redisTemplate.opsForSet().add("set", "setValue0");redisTemplate.opsForSet().add("set", "setValue0");redisTemplate.opsForSet().add("set", "setValue1");//判定是否包含Boolean member = redisTemplate.opsForSet().isMember("set", "setValue0");System.out.println("isMember:" + member);//删除set中的值Long remove = redisTemplate.opsForSet().remove("set", "setValue0");System.out.println("remove = " + remove);//获取set类型值Set<String> set = redisTemplate.opsForSet().members("set");set.forEach(str -> {System.out.println("str = " + str);});}/*** 操作 ZSet  有序 不可重复*/@Testpublic void operateZSet() {//存储值Boolean add = redisTemplate.opsForZSet().add("zset", "zsetValue0", 10);System.out.println("add = " + add);System.out.println("add = " + add);add = redisTemplate.opsForZSet().add("zset", "zsetValue2", 2);System.out.println("add = " + add);//获取值// Boolean zset = redisTemplate.delete("zset");// System.out.println("delete zset = " + zset);}
}

 Redis工具类的封装

/*** Redis 工具类* @author mosin* date 2021/11/30* @version 1.0*/
@Component
public final class RedisUtil {private RedisUtil(){};@Autowiredprivate RedisTemplate<String,String> redisTemplate;//设置值public void  setValue(String key,String value){redisTemplate.opsForValue().set(key, value);}// 设置值 同时设置有效时间public void setValue(String key, String value, Long timeOut, TimeUnit timeUnit){redisTemplate.opsForValue().setIfAbsent(key, value, timeOut, timeUnit);}//设置值 没有则设置 有则不设置public void  setNx(String key,String value){redisTemplate.opsForValue().setIfAbsent(key, value);}//设置值 没有则设置 同时设置有效时间 有则不设置public void  setNx(String key,String value,long timeOut,TimeUnit timeUnit){redisTemplate.opsForValue().setIfAbsent(key, value,timeOut,timeUnit);}//删除值public boolean del(String key){return redisTemplate.delete(key);}//获取值public String getValue(String key){return  redisTemplate.opsForValue().get(key);}
}

业务实践(redis存储token,实现非法请求拦截)

1.编写拦截器

@Component
public class AdminInterceptor implements HandlerInterceptor {@Autowiredprivate RedisUtil redisUtil;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("拦截器以拦截请求");//从请求头中获取token  验证用户是否登录String token = request.getHeader("token");System.out.println(token);String tokenValue = redisUtil.getValue(token);System.out.println("tokenValue = " + tokenValue);if(tokenValue!=null){ //用户已登录 放行请求return  true;}else{//重定向到登录页面response.sendRedirect(request.getContextPath()+"/login.jsp");return false;}}
}

2.配置拦截器

3.编写统一返回数据格式类  

4.编写控制器

@Controller
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate RedisUtil redisUtil;@ResponseBody@RequestMapping("/login")public Object login(User user) throws JsonProcessingException {User usr = User.builder().id(1).name("admin").password("123456").build();//获取token  放入redisString token = UUID.randomUUID().toString().replace("-", "");//将user 转为json格式放入 redisObjectMapper objectMapper = new ObjectMapper();String s1 = objectMapper.writeValueAsString(usr);//将 token 和用户信息存入 redisredisUtil.setValue(token, s1, 2L, TimeUnit.MINUTES);//将token 存入map集合返回HashMap<String, String> map = new HashMap<>();map.put("token", token);return map;}@ResponseBody@RequestMapping("/register")public Object register(User user){HashMap<String, String> map = new HashMap<>();map.put("msg", "ok");return map;}@ResponseBody@RequestMapping("/add")public Object add(User user){HashMap<String, String> map = new HashMap<>();map.put("msg", "ok");return map;}
}

 

5.编写业务类和Mapper接口

6.使用postman接口测试工具测试接口

springBoot实现上传下载

1.编写控制器

/*** 文件上传下载控制类* @author mosin* date 2021/12/1* @version 1.0*/
@Controller
@RequestMapping("/file")
public class FileController {@RequestMapping("/toupload")public String toUpload(){ //跳转上传页return "upload";}@RequestMapping("/upload")public Object fileUpload(MultipartFile file, Model model){if( !file.isEmpty()){String originalFilename = file.getOriginalFilename();String uuid = UUID.randomUUID().toString().replace("-", "");String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));String fileName = uuid+suffix;File f = new File("D:\\upload",fileName);try {file.transferTo(f);model.addAttribute("downloadName", fileName);model.addAttribute("originalFilename", originalFilename);} catch (IOException e) {e.printStackTrace();}}return "download";}@RequestMapping("/download")@ResponseBodypublic Object fileDownLoad(String fileName, HttpServletResponse response){HashMap<String, String> map = new HashMap<>();try {FileInputStream fis= new FileInputStream(new File("D:\\upload", fileName));//设置以附件形式输出response.setHeader("Content-disposition", "attachment; filename="+fileName);//获取输出流ServletOutputStream outputStream = response.getOutputStream();//org.springframework.util.FileCopyUtils  工具类FileCopyUtils.copy(fis, outputStream);map.put("msg", "上传成功!");} catch (Exception e) {e.printStackTrace();map.put("msg", "上传失败!");}return map ;}
}

2.编写上传页面

3.编写下载页面  

设置上传文件大小限制

 

 

springBoot CORS(跨域资源共享)

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

什么是同源策略? 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。

先来说说什么是源 • 源(origin)就是协议、域名和端口号。 若地址里面的协议、域名和端口号均相同则属于同源。 以下是相对于 http:// www.a.com/test/index.html 的同源检测 http://www.a.com/dir/page.html ----成功 http://www.child.a.com/test/index.html ----失败,域名不同 https://www.a.com/test/index.html ----失败,协议不同 http://www.a.com:8080/test/index.html ----失败,端口号不同

哪些操作不受同源限制

1.script

2.link

3.img

4.form

5.a

哪些操作受同源的限制

1.ajax

解决方案:

1.局部解决跨域

  • 使用注解@CrossOrigin(局部跨域)

2.全局解决跨域

  • 配置类解决跨域(全局跨域)

 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;import java.util.ArrayList;
import java.util.List;@Configuration
public class CorsConfig {private CorsConfiguration buildConfig() {CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.setAllowCredentials(true); //sessionid 多次访问一致// 允许访问的客户端域名List<String> allowedOriginPatterns = new ArrayList<>();allowedOriginPatterns.add("*");corsConfiguration.setAllowedOriginPatterns(allowedOriginPatterns);corsConfiguration.addAllowedHeader("*"); // 允许任何头corsConfiguration.addAllowedMethod("*"); // 允许任何方法(post、get等)return corsConfiguration;}@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", buildConfig()); // 对接口配置跨域设置return new CorsFilter(source);}
}方式2:@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("*").allowedMethods("*").allowedHeaders("*");}
}

 

springBoot聚合工程

多模块聚合工程:按照MVC的思想,将应用分成三层web、service、mapper/dao这三个主要模块,在实际的开发过程中可能会根据实际的业务将聚合工程分成如下的形式:

  1. common:通用工具类模块,专门用于项目中使用的一些工具类。

  2. entity:实体类模块,专门存放实体类对象,例如:DTO、BO、AO、VO等等对象。

  3. mapper:dao接口模块,专门存放操作数据库的dao接口。

  4. service:业务逻辑模块,专门进行业务逻辑的处理。

  5. web:控制器模块,用于页面请求控制模块。

搭建聚合工程步骤如下:

(1)IDEA创建maven工程

通过IDEA创建一个maven的quickstart类型项目,然后删除里面的src目录,保留pom.xml文件即可,如下图所示

(2)修改pom依赖,修改父工程项目中的pom.xml文件,添加【springboot】依赖。

 

(3)创建common子模块 ​​​​​​​ 

在弹出界面中,选择【quickstart】类型的项目,然后下一步,填入子工程信息即可  

在子工程中,删除多余的【test】目录和【App】启动类,修改pom文件,删除多余内容,添加父工程依赖  

按照以上步骤完成后续子模块的创建,web模块可创建一个webapp工程,形成如下的目录结构  

统一依赖管理

通过前面的步骤,我们已经将父工程和子工程都搭建完成了,并且引入了【springboot】父工程依赖。这里,我们为了方便管理每个子工程的依赖,以及其他第三方依赖,我们可以选择在父工程中的【pom】文件中,统一的定义依赖版本。

 

在子工程【-web】的pom文件中,添加【web】依赖,并且创建【Application】启动类。  

创建【Application】启动类。  

创建【src/main/resources】目录,新增【application.yml】配置文件  

创建【HelloController】测试类  

启动项目,打开浏览器,访问测试路径  

到这里,SpringBoot聚合项目已经创建好了,并且能够启动访问了。上面几个子工程虽然创建好了,但是每个子工程之间并没有依赖关系,现在我们就将这几个子工程进行依赖关联。

web----->service(---->表示依赖)

service----->mapper,app-common

mapper----->entity

依次给每个子工程添加上面的依赖即可

今天的分享就到此结束了

创作不易点赞评论互关三连

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_102113.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用opencv进行场景识别

opencv场景识别 文章目录 opencv场景识别一、需求1、现状2、设想 二、模型使用1、opencv dnn支持的功能2、ANN_MLP相关知识3、图像分类模型训练学习4、目标检测模型5、opencv调用darknet物体识别模型 三、模型训练1、现状2、步骤-模型编译3、步骤-模型训练 一、需求 1、现状 …

按照条件向Spring容器中注册bean

1.Conditional注解概述 Conditional注解可以按照一定的条件进行判断&#xff0c;满足条件向容器中注册bean&#xff0c;不满足条件就不向容器中注册bean。 package org.springframework.context.annotation;import java.lang.annotation.Documented; import java.lang.annota…

9. 树的进阶

9. 树的进阶 ​ 之前我们学习过二叉查找树&#xff0c;发现它的查询效率比单纯的链表和数组的查询效率要高很多&#xff0c;大部分情况下&#xff0c;确实是这样的&#xff0c;但不幸的是&#xff0c;在最坏情况下&#xff0c;二叉查找树的性能还是很糟糕。 例如我们依次往二叉…

RelativeLayout相对布局

一、官方地址&#xff1a; https://developer.android.google.cn/reference/kotlin/android/widget/RelativeLayout?hlen 二、概述 相对布局&#xff08;RelativeLayout&#xff09;是一种根据父容器和兄弟控件作为参照来确定控件位置的布局方式 三、基本格式 <RelativeLay…

Jenkins配置邮箱发送报告

本文以qq邮箱为例 1.下载Email Extension Plugin插件 2.在Manage Jenkins--System&#xff0c;Jenkins Location下配置理员邮件 Extended E-mail Notification 下配置Jenkins SMTP server&#xff08;邮箱服务&#xff09;、SMTP Port&#xff08;邮箱端口&#xff09;、Cred…

无法解析的外部符号 __mingw_vsprintf

windows下的ffmpeg是采取mingw平台上编译&#xff0c;本人采用的是msys2&#xff0c;本人需要h264&#xff0c;于是先在msys2里面编译了x264静态库&#xff0c;注意这里是静态库&#xff0c;动态库经过了链接&#xff0c;不会出现下面的问题&#xff0c;然后在ffmpeg里面用下面…

Java项目打包exe运行文件

Java项目打包exe运行文件 JavaSE打包成exe运行文件的方法有很多种&#xff0c;此处我们主要讲解我常用的一种exe4j&#xff0c;打包前我们需要先安装exe4j这个工具。 注意&#xff1a;exe4j仅支持最低JDK1.8最高JDK11&#xff0c;所以在安装之前一定要查看自己的JDK版本&#…

【移动端网页布局】移动端网页布局基础概念 ⑤ ( 视网膜屏技术 | 二倍图概念 | 代码示例 )

文章目录 一、视网膜屏技术二、二倍图概念三、代码示例 一、视网膜屏技术 PC 端 和 早期的 移动端 网页中 , CSS 中配置的 1 像素 对应的就是物理屏幕中的 1 像素 ; Retina 视网膜屏幕 技术出现后 , 将多个物理像素压缩到一块屏幕中 , 可以达到更高的分辨率 , 画面显示效果更好…

C/C++笔记-写一个Makefile并链接QtCore库使用QString,QDebug

如下cpp代码&#xff0c;调用QDebug打印程序&#xff1a; #include <QDebug> #include <QString>int main(int argc, char *argv[]){QString testStr "hello";qDebug() << testStr;return 0; } 如下makefile&#xff1a; test: main.cppg -c -…

自编码器简单介绍—使用PyTorch库实现一个简单的自编码器,并使用MNIST数据集进行训练和测试

文章目录 自编码器简单介绍什么是自编码器&#xff1f;自动编码器和卷积神经网络的区别&#xff1f;如何构建一个自编码器&#xff1f;如何训练自编码器&#xff1f;如何使用自编码器进行图像压缩&#xff1f;总结使用PyTorch构建简单的自动编码器第一步&#xff1a;导入库和数…

【JavaEE】社区版IDEA(2021.X版本及之前)创建SpringBoot项目

目录 下载Spring Boot Helper 创建项目 下载相关依赖 判断成功 删除多余文件 项目建好后添加依赖 输出Hello World SpringBoot的优点 下载Spring Boot Helper 创建项目 下载相关依赖 如果没有配置过国内源&#xff0c;参考【JavaEE】Spring项目的创建与使用_p_fly的博…

M_Map工具箱简介及地理图形绘制

M_Map工具箱简介及地理图形绘制 1 M_Map简介1.1 具体代码说明 2 地理图形绘制案例2.1 M_Map给定案例2.1.1 M_Map Logo2.1.2 Lambert Conformal Conic projection of North American Topography2.1.3 Stereographic projection of North Polar regions2.1.4 Colourmaps 2.2 案例…

【社区图书馆】 Go佬—Go程序开发实战宝典书评

文章目录 前言内容介绍文章大致划分总结 前言 《Go 程序开发实战宝典》是一本非常实用的 Go 语言开发工具书&#xff0c;本书由深入浅出的案例讲解、详细的技术实现、贴近实际的应用开发等组成&#xff0c;非常适合 Go 语言开发爱好者、从事相关行业的工程师、技术负责人以及深…

Spring依赖注入的三种方式使用及优缺点

初学Spring的时候,我们从Spring容器中获取Bean对象都是通过bean标签先将Bean对象注册到Spring容器中&#xff0c;然后通过上下文对象congtext的getBean方法进行获取&#xff0c;显然这种方法较为麻烦&#xff0c;所以有了更简单的存方法&#xff1a;五大类注解&#xff1b;取方…

Elasticsearch:了解和解决文档更新后 Elasticsearch 分数的变化

问题 问卷中有如下这样的文档&#xff0c;开发者想通过 match query 搜索这些文档来使用分数。 POST sample-index-test/_doc/1 {"first_name": "James","last_name" : "Osaka" } 以下是对上述文档的示例查询&#xff1a; GET sam…

贾其萃 : 笃行实践 筑梦扬帆 | 提升之路系列(二)

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

LeetCode特训 --- Week2 (主打滑动窗口 + 字符串匹配题目)

目录 滑动窗口原理 真懂了滑动窗口? 滑动 字符串细节 开干切题 滑动窗口原理 滑动窗口&#xff1a;维护一前一后两根指针, 或者说一左一右两个指针。更主要的是维护左右指针中的区间. 同时不断的向前滑动&#xff0c;直到整个序列滑动结束&#xff0c;前指针走到序列末尾…

有什么好用的远程工具吗

沟通在任何类型的工作中都扮演着重要的角色。但当谈到远程工作时&#xff0c;这一点就更为重要。因此&#xff0c;您的组织必须找到可以让您的团队保持一致的工具。 在某些方面&#xff0c;项目管理扮演着类似的角色。 您会注意到&#xff0c;下面的大多数工具都会直接影响您的…

Java核心技术 卷1-总结-10

Java核心技术 卷1-总结-10 通配符类型通配符概念通配符的超类型限定无限定通配符通配符捕获 通配符类型 通配符概念 通配符类型中&#xff0c;允许类型参数变化。 例如&#xff0c;通配符类型Pair<? extends Employee>表示任何泛型Pair类型&#xff0c;它的类型参数是…

【Linux】uptime命令详解平均负载

命令 ➜ ~ uptime 22:37 up 90 days, 21:45, 2 users, load averages: 2.91 3.46 3.81 具体含义 22:37&#xff1a;代表的是当前的系统时间&#xff0c;也即晚上10点37分。 up 90 days, 21:45&#xff1a;代表系统运行时间 2 users &#xff1a;当前两个用户 load averages: 2…