文章目录
- 接口接收数据并进行数据清洗
- mysql读取到redis
- 接口返回参数对象
- java函数使用备注
- 返回参数分析
- stream操作
- Thread线程
- 队列
- 集合
- 存储
- 统计
- 加密
- 日志以及aspect对接口的时间影响?
- war包和jar包的区别?
- filter、interceptor、aspect区别?
- 探针
- Gson
- JsonObject和JSONObject
- hutool包的request请求
- 网络传输 ByteBuffer
- Base64安全方式与非安全方式
- 最后
接口接收数据并进行数据清洗
- 基本信息
在Java Spring Boot环境中,可以使用Spring Data JPA和Hibernate ORM来操作SQLite数据库,来实现如何创建一个接收并同步数据到服务器端数据库的RESTful API接口;
参考博客:https://blog.csdn.net/u013735734/article/details/136361244#%E9%85%8D%E7%BD%AE%20SQLite%20&%20JPA项目基础配置:
需要确保配置:Spring Data JPA和SQLite连接
参考博客:https://blog.csdn.net/zyd573803837/article/details/109263219
mysql读取到redis
通过实现CommandLineRunner接口重写run方法可以实现。
具体的run方法中,使用xxxMapper读取mysql数据,然后向RedisOpreation对象写入数据。
@Component
public class RedisDataLoader implements CommandLineRunner {@Autowiredprivate RedisOperations redisOperations;@Autowiredprivate XXXMapper xxxMapper;@Overridepublic void run(String... args) throws Exception {Object object = xxxMapper.selectById(1);redisOperations.set(key, object);}
}
接口返回参数对象
通常不同的运行情况,返回的对象是不同的。
通过采用构造方法-重载形式,可以实现该效果。
通过重载不同的静态方法,实现调用不同的构造方案。
该类需要实现Seriaizable。
需要添加@JsonInclude(JsonInclude.Include.NON_NULL),不返回参数值为null的。
@Slf4j
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResultDto implements Serializable {private String xx1;private String xx2;private String xx3;public ResultDto(String xx1, String xx2, String xx3){this.xx1 = xx1;this.xx2 = xx2;this.xx3 = xx3;}public ResultDto(String xx1, String xx2){this.xx1 = xx1;this.xx2 = xx2;}public static ResultDto result(String xx1, String xx2, String xx3){return new ResultDto(xx1, xx2, xx3);}public static ResultDto result(String xx1, String xx2){return new ResultDto(xx1, xx2);}
}
java函数使用备注
Math.min 和 Math.max函数
int min = Math.min(111111, 111111);// 如果两个数相同,则返回其中任意一个。int max = Math.max(22,22);// 如果两个数相同,返回其中任意一个。System.out.println(min);System.out.println(max);
List集合
问题:
一个list集合执行add命令,报java.lang.NullPointerException: null 这是什么原因
分析:
List本身没有初始化,导致使用add方法的时候会报错;
list是由map.get(key)获取到的,但是key对应的value为null,也会报上述错误。
返回参数分析
一般采用JSON格式,该格式是轻量级的数据交换格式,易于人阅读和编写;
但返回值格式需要经过如下过程加以判断:
1. 使用@RestController 或 @Controller + @ResponseBody
表示控制类的返回值直接写入HTTP的响应体,而不作为视图模型返回给视图层;2. 返回值类型
可以是原生的java对象(map)、自定义对象或者String。如果返回的是java对象,Spring自动将去转换为JSON对象;3. 响应头Content-Type
当返回为JSON格式时,响应头的Content-Tpye字段会被赋值为application/json
stream操作
情况1:
Collection<LzKey> lzKeys
LzKey errorKey = lzKeys.stream().filter(lzKey -> !validateId(lzKey.getId())).findAny().orElse(null);// 理解:
lzKeys.stream() --》 集合转换成流Stream,可以对其中的元素继续流式操作;
.filter(lzKey -> !validateId(lzKey.getId())) --》 过滤出通过getId获取到的lzKey对象无法通过validateId验证的lzKey
.findAny() --》 从结果中随机选择一个元素
.orElse(null) --》 如果存在元素就返回元素,不存在就返回null
情况2:
下划线是java7以及之后版本的数字分割符,即50000000 等于 5000_0000
情况3:
Collection<LzKey> lzKeys
Map<Integer, List<LzKey>> map = lzKeys.stream().collect(Collectors.groupingBy(lzKey -> getTableIndex(lzKey.getId())));// 理解;
lzKeys.stream() --》 将lzKeys列表转化成一个流;
.collect(....) --》 流操作的终止操作之一,收集元素并将其转化为Map类型;
Collectors.groupingBy(....) --》 Collector工厂方法,用于创建一个Collector实例,元素根据分类函数groupingBy进行分组;
lzKey -> getTableIndex(lzKey.getId()) --》 根据id得到tableIndex,其作为Map的key,值为lzKeys组成的列表;
情况4:
List<Integer> indexList = list.stream().map(LzKey::getId).collect(Collectors.toList());
// 理解:
list.stream() --》 基于list集合创建流
map(LzKey::getId) --》 将list集合中的lzKey对象的id元素提取出来
collect(Collectors.toList()) --》将提取出来的id组成新的ListCollections.shuffle(indexList, ThreadLocalRandom.current());
// 理解:
对indexList进行随机重排,参数2 确保多线程环境下速记数生成的安全性;
Thread线程
extends Thread:
public class function extends Thread{}
public function(int a,long b,int c) {super("ConsumerKeyThread");setDaemon(true);this.a = a;this.b = b;this.c = c;
}
// 理解:
super("ConsumerKeyThread") --》 调用父类的构造方法,传入字符串s,作为新线程的名字;
setDaemon(true) --》将创建的线程设置为守护线程;
守护线程是一种特殊的过程,它在后台运行,不会组织程序的退出,当所有的非守护线程都结束时,守护线程也将自动终止;
队列
使用1:
private ArrayBlockingQueue<LzKey> bufferKeys
// 理解:
定义阻塞队列;用于存储和管理LzKey对象;
集合
使用1:
list.forEach(key -> cache.put(key));
// 理解:
遍历list中的每个元素,并对元素执行cache.put操作,将每个元素都存入cache中。
存储
使用1:
long keyMemory = RamUsageEstimator.sizeOf(keysCache)/1024;
// 理解:
RamUsageEstimator.sizeOf(keysCache) --》 评估keysCache对象在内存中所占用的空间;
/1024 --》 将对象占用内存的大小,设置单位为KB;
统计
使用1:Guage
// 学习:
Gauge 是 Prometheus 支持的一种指标类型,它可以记录任意浮点数值,既可以增加也可以减少,适合用来表示像内存使用量、活跃连接数这类可以随时变化的值。Gauge CHANGE_GAUGE = Gauge.build().name("server").help("number of current.").labelNames(NAME).register();
// 理解:
Gauge.build() --》 构建一个新的Gauge对象;
.name() --》 指定名字;
.help() --》 添加描述信息;
.labelNames() --》设置标签,区分相同类型指标的不同实例;
.register() --》 构建好的Gauge注册到Prometheus的客户端库中;
加密
SM3
使用1:
String str = "12345";
String secret = "000000";
String checkSign = SmUtil.sm3WithSalt(secret.getBytes()).digestHex(str);
// secret.getBytes() 将字符串转换成字节数组
// SmUtil.sm3WithSalt() 生成SM3的盐值
// .digestHex() 执行散列运算,将转换为字节流,并将结果转为16进制字符串格式;
String out = SmUtil.sm3(str);
System.out.println(checkSign);
System.out.println(out);
日志以及aspect对接口的时间影响?
描述:某接口中,存在大量的日志处理以及通过aspect在返回结果前进行处理,这样会导致接口返回消耗更多的时间?
解决:日志通过异步处理,不影响主线程正常执行;aspect处理,优化处理逻辑;
war包和jar包的区别?
war包:可以部署到支持java web容器的服务器,比如tomcat、jetty等。可结合容器的优势,实现多实例部署和负载均衡。
jar包:通过命令行或脚本可执行该jar包,适合单机部署;
filter、interceptor、aspect区别?
filter、interceptor、aspect
分别是过滤器、拦截器、切面;
拦截顺序是:filter、interceptor、controllerAdvice、aspect、controller
filter:控制最初请求,和框架无关;作用于servlet
interceptor:可以控制请求的控制器和方法,但控制不了请求方法里的参数;作用于URL
aspect:可以自定义切入点,有方法参数,但是拿不到http请求;作用的对象可以是任何一个方法
探针
描述:创建ServiceTrace类,构建bind方法;案例代码:public static final TransmittableThreadLocal<BusinessTrace> BUSINESS_TRACE = new TransmittableThreadLocal<>();// ThreadLocal 允许将数据绑定到当前线程,对于跨多个方法调用 或 再同一个线程中跟踪业务逻辑特别有用;public static void bind(String serviceId, String serviceName){// 初始化或更新与线程相关的上下文信息,通常用于日志记录和跟踪分布式系统中的事务;MDC.put(SystemConsts.SERVICE_ID, serviceId);MDC.put(SystemConsts.SERVICE_NAME, serviceName);// MDC 来存储键值对,是Logback或Log4j库的一部分,用于附加诊断信息到当前线程的日志事件中;BUSINESS_TRACE.set(BusinessTrace.builder()// 创建BusinessTrace对象,.cover(Boolean.FALSE).threadId(getCurrentThreadId())// 获取当前线程的id.callerId(getCurrentCallerId())// 获取调用者的id.serviceId(serviceId).serviceName(serviceName).build());}
Gson
定义:Gson 是一个流程的java库,用于实现java对象与JSON格式,相互转换;案例:Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();// setDateFormat,表示在执行序列化/反序列化的时候,日期时间按照上述格式转化;gson.fromJson // Json -》 java对象gson.toJson // java对象 -》 Json
JsonObject和JSONObject
两者都用于处理JSON数据,但属于不同的库;
JSONObject:来自于org.json包,提供多种方法操作JSON数据,如添加键值对、获取特定键的值;
JsonObject:来自于com.google.gson包,可以用来将Java对象转化为JSON表示形式,也可以将JSON字符串转换成Java对象。
hutool包的request请求
get请求-方式1:
Map<String,String> param = new HashMap<>();
param.put("appId",appId);
param.put("version", version);
param.put("algorithm", algorithm);
param.put("timestamp",timestamp);HttpResponse response = HttpRequest.get(url).form(param).execute();
// 该方式可行;
post请求-方式1:
JsonObject requestObj = new JsonObject();
JsonObject Head = new JsonObject();
JsonObject Body = new JsonObject();
JsonObject Attache = new JsonObject();requestObj.add("HEAD",Head);
requestObj.add("BODY",Body);
requestObj.add("ATTACHED",Attache);String param = gson.toJson(requestObj);
String httpRes = HttpRequest.post(url).header(Header.ACCEPT_ENCODING, "") .body(param).execute().body();
JSONObject jsonresult = new JSONObject(httpRes);
// 该方法可行
Post请求-方式2:
JsonObject requestJson = new JsonObject();
requestJson.addProperty("aaa",aaa);
Gson gson = new Gson();HttpResponse result = HttpRequest.post(encryptLocalUrl).body(gson.toJson(requestJson)).execute();
System.out.println("请求参数:-》"+requestJson);
// 该方式不可行,参数无法通过请求传递给接口;HttpResponse result = HttpRequest.post(encryptLocalUrl).form(param).execute();
// 通过这样的方式可以实现,且param是map集合;
网络传输 ByteBuffer
Base64安全方式与非安全方式
来自于包package java.util.Base64;这个类Base64 是一种常用的二进制到文本的编码方案,常用于将二进制数据(如图片、音频等)转换成可以在文本环境中安全传输的格式。
不安全方式:
public static Encoder getEncoder() {return Encoder.RFC4648;
}
// 返回一个遵循 RFC 4648 标准的 Base64 编码器。RFC 4648 描述了 Base64 编码的标准形式,其中使用的字符包括大写字母、小写字母、数字、加号 (+) 和斜线 (/)。编码后的字符串还会使用等号 (=) 作为填充字符。
public static Decoder getDecoder() {return Decoder.RFC4648;}安全方式:
public static Encoder getUrlEncoder() {return Encoder.RFC4648_URLSAFE;
}
// 返回一个 URL 和文件名安全的 Base64 编码器。这种编码方式遵循 RFC 4648 中描述的 URL 和文件名安全的 Base64 变体。在这种情况下,加号 (+) 被替换为下划线 (_),斜线 (/) 被替换为减号 (-);
public static Decoder getUrlDecoder() {return Decoder.RFC4648_URLSAFE;}
案例:
public void testxhj(){String data = "127.0.0.1";byte[] encode = getUrlEncoder().encode(data.getBytes());System.out.println("urlencoder:->"+new String(encode));// urlencoder:->MTI3LjAuMC4x// urlencoder:->MTI3LjAuMC4x
// String encode1 = Base64.encode(data.getBytes());String encode1 = getEncoder().encodeToString(data.getBytes());System.out.println("encoder:->"+encode1);// encoder:->MTI3LjAuMC4x// encoder:->MTI3LjAuMC4x// 每次加密后的输出结果一样byte[] decode = getUrlDecoder().decode(encode);System.out.println("url-url decoder:——>"+new String(decode));// url-url decoder:——>127.0.0.1
// byte[] decode1 = getDecoder().decode(encode.toString());
// System.out.println("url-xxx decoder:——>"+new String(decode1)); // 异常byte[] decodex = getUrlDecoder().decode(encode1);System.out.println("xxx-url decoder:——>"+new String(decodex));// xxx-url decoder:——>127.0.0.1byte[] decodex1 = getDecoder().decode(encode1);System.out.println("xxx-xxx decoder:——>"+new String(decodex1));// xxx-xxx decoder:——>127.0.0.1
}