当我们使用RedisTemplate向我们的Redis数据库中set(“originName”)时,我们在服务端中获取该key的时候出现了乱码\xac\xed\x00\x05t\x00\noriginName` 原因:因为我们springboot中的RedisTemplate将我们的key保存的时候会将其进行序列化,此时我们在别的客户端获取的时候机会出现乱码。 解决:我们需要自己定义我们的RedisTemplate中的序列化机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Configuration public class RedisTemplateConfig { @Bean public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory connectionFactory){ RedisTemplate<Object, Object> objectObjectRedisTemplate = new RedisTemplate<>(); objectObjectRedisTemplate.setKeySerializer(new StringRedisSerializer()); objectObjectRedisTemplate.setHashKeySerializer(new StringRedisSerializer()); objectObjectRedisTemplate.setConnectionFactory(connectionFactory); return objectObjectRedisTemplate; } } |
由于我们获取值时会将它进行反序列化,我们就无须设置value的反序列化 from:https://blog.csdn.net/ebdbbd/article/details/126266968 另一个版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory , GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer , StringRedisSerializer stringRedisSerializer) { RedisTemplate objectObjectRedisTemplate = new RedisTemplate(); objectObjectRedisTemplate.setConnectionFactory(redisConnectionFactory); objectObjectRedisTemplate.setKeySerializer(stringRedisSerializer); objectObjectRedisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer); objectObjectRedisTemplate.setHashKeySerializer(stringRedisSerializer); objectObjectRedisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer); return objectObjectRedisTemplate; } |
View Details
1、Java中拷贝的概念 在Java语言中,拷贝一个对象时,有浅拷贝与深拷贝两种 浅拷贝:只拷贝源对象的地址,所以新对象与老对象共用一个地址,当该地址变化时,两个对象也会随之改变。 深拷贝:拷贝对象的所有值,即使源对象发生任何改变,拷贝的值也不会变化。 在User类的基础上,介绍两种浅拷贝案列 User类:
1 2 3 4 5 |
@Data public class User { private String name; private Integer age; } |
案列①:普通对象的浅拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.shuizhu.study; //浅拷贝案例1 public class Study01 { public static void main(String[] args) { User user1 = new User(); user1.setName("张三"); user1.setAge(18); User user2 = user1; System.out.println("user1未改变前,user2的名字为:" + user2.getName()); user1.setName("李四"); System.out.println("user1未改变前,user2的名字为:" + user2.getName()); } } |
结果:改变user1后,user2的值也随之变化 案列②:List浅拷贝(这也是我们平时项目中,经常遇到的情况)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
package com.shuizhu.study; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; //Java浅拷贝案列2 public class Study02 { public static void main(String[] args) { List<User> list1 = new ArrayList<>(); User user1 = new User(); user1.setName("张三"); user1.setAge(18); User user2 = new User(); user2.setName("李四"); user2.setAge(19); list1.add(user1); list1.add(user2); //TODO 以下是开发中,经常发生的浅拷贝 //方式1:通过new ArrayList方式,把list01拷贝给list02 List<User> list2 = new ArrayList<>(list1); System.out.println("list1未改变前,list2的结果为:" + list2); //方式2:通过addAll方法,把list01拷贝给list02 List<User> list3 = new ArrayList<>(); list3.addAll(list1); System.out.println("list1未改变前,list3的结果为:" + list3); //方式3:通过stream流的方式,把list01拷贝给list02 List<User> list4 = list1.stream().collect(Collectors.toList()); System.out.println("list1未改变前,list4的结果为:" + list4); //改变list1集合中的user1对象 System.out.println("--------------------------------------------"); user1.setName("老六"); user1.setAge(78); System.out.println("list1改变后,list2的结果为:" + list2); System.out.println("list1改变后,list3的结果为:" + list3); System.out.println("list1改变后,list4的结果为:" + list4); } } |
结果:对List的3种拷贝,其实都是浅拷贝,当源集合中对象发生改变时,新的List也会随之变化 2、常见的深拷贝方式 构造函数方式(new的方式) 重写clone方法 Apache Commons Lang序列化 Gson序列化 Jackson序列化 2.1、构造函数方式 这种方式就是创建一个新的对象,然后通过源对象的get方法与新对象set方法,把源对象的值复制新对象,这里就不再演示了。 缺点:在拷贝的对象数量较少时,可以使用,但是对象数量过多时,会大大增加系统开销,开发中应避免使用。 2.2、重写clone方法 步骤: 1>需要拷贝对象的类,去实现Cloneable接口 2>重写clone方法 3>使用"对象.clone()"的方式进行拷贝 根据上面的案列,进行对应的改造: 首先是User实体类 ,如下:
1 2 3 4 5 6 7 8 9 10 |
@Data public class User implements Cloneable{ private String name; private Integer age; @Override protected User clone() throws CloneNotSupportedException { return (User) super.clone(); } } |
改造案列①:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.shuizhu.study; //Java深拷贝案列 public class Study03 { public static void main(String[] args) throws CloneNotSupportedException { User user1 = new User(); user1.setName("张三"); user1.setAge(18); User user2 = user1.clone(); System.out.println("user1未改变前,user2的名字为:" + user2.getName()); user1.setName("李四"); System.out.println("user1未改变前,user2的名字为:" + user2.getName()); } } |
结果:当user1改变后,user2的值不会改变 改造案列②:List类型深拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package com.shuizhu.study; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; //Java深拷贝案列 public class Study04 { public static void main(String[] args) { List<User> list1 = new ArrayList<>(); User user1 = new User(); user1.setName("张三"); user1.setAge(18); User user2 = new User(); user2.setName("李四"); user2.setAge(19); list1.add(user1); list1.add(user2); / //通过clone方式,把list01拷贝给list02 List<User> list2 = new ArrayList<>(); //TODO 当数据量多时,建议使用对象的方式,把List当做属性,然后拷贝哦到一个新的对象中,从而不需要循环,可以见Apache Commons Lang序列化深拷贝方式 list1.forEach(user->{ try { list2.add(user.clone()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } }); System.out.println("list1未改变前,list2的结果为:" + list2); //改变list1集合中的user1对象 System.out.println("--------------------------------------------"); user1.setName("老六"); user1.setAge(78); System.out.println("list1改变后,list2的结果为:" + list2); } } |
结果:list1中的每个对象通过clone()添加list2中,当list1中的对象改变时,list2不会改变 2.3 、Apache Commons Lang序列化 步骤: 1>导入Commons包
1 2 3 4 5 |
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3:3.5</version> </dependency> |
2>实体类实现Serializable接口
1 2 3 4 5 |
@Data public class User implements Serializable { private String name; private Integer age; } |
3>调用SerializationUtils工具类,实现深拷贝(注意:SerializationUtils不能直接拷贝List类型) 案列如下: 案列①:对象深拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.shuizhu.study2; import org.apache.commons.lang3.SerializationUtils; //Apache Commons Lang序列化实现对象的深拷贝 public class Study01 { public static void main(String[] args) { User user1 = new User(); user1.setName("张三"); user1.setAge(18); User user2 = SerializationUtils.clone(user1); System.out.println("user1未改变前,user2的名字为:" + user2.getName()); user1.setName("李四"); System.out.println("user1改变后,user2的名字为:" + user2.getName()); } } |
结果:user1的改变不会导致user2的改变,从而实现深拷贝 案列②:List类型深拷贝 (1)改造开始,我们先创建一个专门用于拷贝List<User>类型的实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.shuizhu.study2; import java.io.Serializable; import java.util.List; /** * @author 睡竹 * @date 2022/12/10 * 用于深拷贝时,不需要去遍历List<User>集合,只需要拷贝UserCopyDTO 对象就可以 * 获取到新的List<User>集合 */ @Data public class UserCopyDTO implements Serializable {//必须实现Serializable接口 private List<User> users; } |
(2)拷贝List类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package com.shuizhu.study2; import org.apache.commons.lang3.SerializationUtils; import java.util.ArrayList; import java.util.List; //Apache Commons Lang序列化实现List的深拷贝 public class Study02 { public static void main(String[] args) { List<User> list1 = new ArrayList<>(); User user1 = new User(); user1.setName("张三"); user1.setAge(18); User user2 = new User(); user2.setName("李四"); user2.setAge(19); list1.add(user1); list1.add(user2); //使用UserCopyDTO对象,专门用于拷贝List<User>类型数据,不需要再去遍历list1 UserCopyDTO userCopyDTO = new UserCopyDTO(); userCopyDTO.setUsers(list1); //通过Apache Commons Lang序列化方式,把list01拷贝给list02 UserCopyDTO clone = SerializationUtils.clone(userCopyDTO); List<User> list2 = clone.getUsers(); System.out.println("list1未改变前,list2的结果为:" + list2); //改变list1集合中的user1对象 System.out.println("--------------------------------------------"); user1.setName("老六"); user1.setAge(78); System.out.println("list1改变后,list2的结果为:" + list2); } } |
结果: 2.4、Gson序列化 步骤: 1、导入Gson依赖
1 2 3 4 5 |
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.5</version> </dependency> |
2>创建Gson对象,使用该对象进行深拷贝(实体类不再需要实现Serializable接口) 案例如下:只演示对象的深拷贝,LIst类型的深拷贝与之前的流程是相似的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package com.shuizhu.study3; import com.google.gson.Gson; //Gson序列化实现对象的深拷贝 public class Study01 { public static void main(String[] args) { User user1 = new User(); user1.setName("张三"); user1.setAge(18); Gson gson = new Gson(); User user2 = gson.fromJson(gson.toJson(user1), User.class); System.out.println("user1未改变前,user2的名字为:" + user2.getName()); user1.setName("李四"); System.out.println("user1改变后,user2的名字为:" + user2.getName()); } } |
重点: 结果: 2.5、Jackson序列化 该方式与Gson原理、使用方式相似,但是Jackson序列化深拷贝,要求拷贝的对象必须有无参构造函数 步骤: 1>导入Jackson依赖
1 2 3 4 5 6 7 8 9 10 |
<dependency> <groupId>com.fasterxml.jackson</groupId> <artifactId>core</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson</groupId> <artifactId>databind</artifactId> <version>2.2.2</version> </dependency> |
2>创建ObjectMapper对象,进行深拷贝(用法与Gson一致) […]
View Details【问题】在配置文件application.properties中配置一个值含有中文的变量。 spring加载配置之后,读取的变量中文部分出现乱码。 根据CSDN说的一堆办法,改encoding为UTF-8,都试过了统统不好使。 【解决方法】知乎上有人说: 配置文件可以用yml文件来代替properties文件, yml文件是支持中文的,并且利用换行缩进来避免重复的前缀。 照做之后问题解决。但是注意:data source中jdbc url中的转义符号反斜杠“\”必须去掉。 from:https://www.cnblogs.com/tigerhsu/p/9794072.html
View Details今天开始学习并转载大神【纯洁的微笑】的文章。 收集 Spring Boot 相关的学习资料,Spring Cloud点这里 重点推荐:Spring Boot 中文索引 推荐博客 纯洁的微笑-Spring Boot系列文章 林祥纤-从零开始学Spring Boot Mkyong-Spring Boot教程(国外) baeldung-Spring Boot教程(国外) liaokailin的专栏-Spring Boot实战 catoop的专栏-Spring Boot 学习 方志朋-SpringBoot 非官方教程 嘟嘟-Spring-Boot干货系列 小柒-SpringBoot开发案例 江南一点雨-关于Spring Boot 天码营-Spring Boot 猿天地-Spring Boot 刘冬的博客-Spring Boot 唐亚峰 Battcn-Spring Boot sylvanassun-Spring Boot dalaoyang-Spring Boot 开源 纯洁的微笑 Spring Boot 示例 Spring Boot 官方示例 Spring Boot开源软件 云收藏 Docker+SpringBoot+Mybatis+thymeleaf等技术实现的Java博客系统 Spring boot & Shiro 权限管理系统 Spring Boot实现支付服务:支付宝,微信… Spring Boot后台商城 h5 小程序 基于Spring Boot响应式文件浏览管理器 Spring Boot开源博客 邮件发送服务多种实现,队列,线程定时任务 Spring Boot视频展示项目 Spring Boot项目实践总结 Vue+SpringBoot实现的多用户博客管理平台 Vue+SpringBoot实现的人力资源管理系统 hsweb企业后台管理系统基础框架 一个基于spring boot 实现的股票指数💹爬虫 KKFileView-SpringBoot实现在线预览 boot-websocket-log-SpringBoot实现日志WEB输出 SpringBoot+MyBatis+A pacheShiro+Ehcahe基础平台 leelance Spring Boot各种示例 一个基于Spring […]
View DetailsFile >Project Structure Artifacts >> JAR >> From……. 第一,选择要打包成jar包的class(对应图中1) 第二,将依赖包一起打包(对应图中2,选择这个) 第三,将依赖包一起下载(对应图中3) 第四, 这是生成 META-INF文件的路径,不能是默认路径,一般直接把src后面的路径删掉就行。 最后点击OK 此时在这里会有META-INF文件,如果选择默认路径这里是没有这个文件的,该文件是指向要运行的class的。 然后右击左上方的JAR文件,选择ADD copy of >>>> Libraby 选择需要的jar包,然后点OK 然后点击上面的Build >> Build Artifacts… 点击Build 此时jar包就会生产在项目的out目录下 此时运行可能会出现 找不到或无法加载主类 的问题 解决办法 借鉴:启动jar包报错: 找不到或无法加载主类亮一点的博客-CSDN博客运行jar包找不到或无法加载主类 打开jar包找到META-INF 原文写 删除jar包META-INF目录下的.SF .DSA ,RSA 后缀文件,但是我只删除了DSA文件就可以了 from:https://zhuanlan.zhihu.com/p/558914730
View DetailsError:(39,24) java: constant string too long 问题解决: file -> setting -> build, execution, deployment -> compiler -> java compiler -> user compiler: 选择 Eclipse 保存即可;(原本是 javac) from:https://www.cnblogs.com/xj63183/p/15868267.html
View Details反序列化保持字段顺序
1 2 3 4 |
JSONObject respondeBodyJson = JSONObject.parseObject(jsonStr, Feature.OrderedField); // 初始华有序对象 JSONObject retObj = new JSONObject(true); |
序列化保持字段顺序
1 2 3 4 |
JSON.DEFAULT_GENERATE_FEATURE &= ~SerializerFeature.SortField.getMask(); // 序列化时加上参数 String result = JSON.toJSONString(data, new SerializeConfig(true)); |
保留null值的序列化
1 |
String dataStr = JSONObject.toJSONString(dataJSON,SerializerFeature.WriteMapNullValue); |
View Details
非对称加密算法中,提供一个公钥一个私钥。一般情况下,采用公钥加密、私钥解密的方式。 假设有这样一个场景:服务A与服务B需要通信,通信内容为了安全需要进行加密传输,并且服务A与服务B不能互相持有对方的钥匙。
View Details目录 一、主方法 二、Java实现hello world 三、用static修饰的方法就是静态方法 四、编译java文件 1、通过javac编译java文件 2、执行编译后的java文件 3、如何运行class文件中的main方法 五、数据类型 1、四种整型 2、浮点型 3、char 4、boolean 六、数据类型默认值 1、基础数据类型默认值 2、代码实例 七、大数值 八、装箱与拆箱 九、特殊的转义字符 一、主方法
1 2 3 |
public static void main(String[] args) { } |
在main中使用了两个修饰符public和static,public修饰符使它可以从应用程序的任何地方访问被访问,静态修饰符使它成为一个类方法,可以直接用类名进行调用。 返回值为void,因为这个访问不需要返回值。 它的名字是main,参数是String[] args。 二、Java实现hello world 需要插图 三、用static修饰的方法就是静态方法 需要插图
1 2 3 4 5 6 7 8 9 10 11 |
package com.nezha.javase; public class Test { private void test(){ System.out.println("你好,我是哪吒"); } public static void main(String[] args) { Test.test(); } } |
可以使用类名.方法名的形式访问static方法,但是不能访问非静态方法。 四、编译java文件 1、通过javac编译java文件
1 |
javac Test.java |
编译后的文件Test.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.nezha.javase; public class Test { public Test() { } public static void main(String[] var0) { System.out.println("hello world"); } } |
2、执行编译后的java文件
1 |
java Test |
输出结果:hello world 3、如何运行class文件中的main方法 假设如下目录有个class文件,并且里面有main方法: E:\nezha\JavaseProject\com\nezha\javase\Test.class 首先进入cmd命令行:
1 2 3 |
cd /d E:\nezha\JavaseProject java com\nezha\javase.Test |
也可以带参数运行:
1 |
java com.nezha.javase.Test com.nezha.javase.Test nezha |
五、数据类型 Java是一种强类型的语言,有8种基本类型,其中4种整型,2种浮点型,1种用于表示Unicode编码的字符单元的字符类型char、1种boolean型。 1、四种整型 int 4字节 -2147483648~2147483647 short 2字节 -32768~32767 long 8字节 很大很大 byte 1字节 -128~127 通常情况下int最常用,byte和short类型用于特定的应用场合,例如底层的文件处理或需要控制占用存储空间量的大数组。 长整型有一个后缀L或l(如123456789L)。十六进制数值有一个前缀0x或0X(如0xFFFF)。 八进制有一个前缀0,例如010表示八进制中的8。 2、浮点型 double 8字节 float 4字节 double的数值精度是float的两倍,double一般也可称作双精度浮点型。 一般都使用double,不使用float。 3、char char类型表示单个字符。 char类型的字面量值要用单引号括起来。 例如’A’是编码值为65所对应的字符常量。它与"A"不同,"A"表示一个字符串A。 char类型可以表示为十六进制值,范围从\u0000到\Uffff。 4、boolean boolean类型只有两个值,true和false。 […]
View Details