springboot数据访问

springboot整合JDBC

JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分。JdbcTemplate处理了资源的建立和释放。他帮助我们避免一些常见的错误,比如忘了总要关闭连接。他运行核心的JDBC工作流,如Statement的建立和执行,而我们只需要提供SQL语句和提取结果。

  • execute:可以执行所有SQL语句,一般用于执行DDL语句。
  • update:用于执行INSERTUPDATEDELETE等DML语句。
  • queryXxx:用于DQL数据查询语句。

pom引入依赖

pom.xml 配置maven依赖,mysql-connector驱动和jdbc-starter,数据库版本要和驱动版本对应。导入JDBC场景,不导入驱动因为官方不知道我们接下要操作什么数据库。

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

yaml配置数据库账号密码驱动等信息

spring:
datasource:
url: jdbc:mysql://localhost:3306/springdata?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver

创建一个简单的数据库表

create table `student` (
`age` int (11),
`name` varchar (255),
`num` int (11)
);
insert into `student` (`age`, `name`, `num`) values('12','小明','1');
insert into `student` (`age`, `name`, `num`) values('13','小红','2');

@Test测试jdbc连接

@Slf4j
@SpringBootTest
class SpringbootReviewApplicationTests { @Test
public void testImport(){
} @Autowired
JdbcTemplate jdbcTemplate; @Test
void contextLoads() {
List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from student");
for (Map<String, Object> map : maps) {
for (String s : map.keySet()) {
log.info(s + map.get(s));
}
}
Long aLong = jdbcTemplate.queryForObject("select count(*) from student", Long.class);
log.info("记录总数:{}",aLong);
} }

使用Druid数据源

数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正式针对这个问题提出来的.数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中, 这些数据库连接的数量是由最小数据库连接数来设定的.无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量.连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

引入starter:

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>

官方文档:

https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

参数配置:

监控页访问地址:http://localhost:8080/druid/index.html

spring:
mvc:
hiddenmethod:
filter:
enabled: true
servlet:
multipart:
enabled: true
file-size-threshold: 2KB
max-request-size: 215MB
datasource:
url: jdbc:mysql://localhost:3306/springdata?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource druid:
aop-patterns: com.top.springbootweb.* #监控SpringBean
filters: stat,wall # 底层开启功能,stat(sql监控),wall(防火墙) stat-view-servlet: # 配置监控页功能
enabled: true
login-username: admin
login-password: admin
resetEnable: false web-stat-filter: # 监控web
enabled: true
urlPattern: /*
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' filter:
stat: # 对上面filters里面的stat的详细配置
slow-sql-millis: 1000
logSlowSql: true
enabled: true
wall:
enabled: true
config:
drop-table-allow: false

参数意义:

注入bean:

将druidDataSource,监控servlet和过滤器filter注入

@Configuration
public class DruidConfig { // 默认的自动配置是判断容器中没有才会配@ConditionalOnMissingBean(DataSource.class)
@ConfigurationProperties("spring.datasource")
@Bean
public DataSource dataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
} /**
* 配置 druid的监控页功能
*
* @return
*/
@Bean
public ServletRegistrationBean statViewServlet() {
StatViewServlet statViewServlet = new StatViewServlet();
ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*");
// registrationBean.addInitParameter("loginUsername", "admin");
// registrationBean.addInitParameter("loginPassword", "admin");
//白名单:
servletRegistrationBean.addInitParameter("allow","127.0.0.1");
//IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
servletRegistrationBean.addInitParameter("deny","192.168.1.73");
return registrationBean;
} /**
* WebStatFilter 用于采集web-jdbc关联监控的数据。
*/
@Bean
public FilterRegistrationBean webStatFilter() {
WebStatFilter webStatFilter = new WebStatFilter();
FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>(webStatFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); return filterRegistrationBean;
} }

controller:

访问/student之后,进入监控页可以查看对sql语句执行的监控

@RestController
@Slf4j
public class DruidTestController {
@Autowired
JdbcTemplate jdbcTemplate;
@GetMapping("/student")
public List<Map<String, Object>> contextLoads() {
DataSource dataSource = jdbcTemplate.getDataSource();
log.info(dataSource.toString());
List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from student");
for (Map<String, Object> map : maps) {
for (String s : map.keySet()) {
log.info(s+map.get(s));
}
}
return maps; }
}
//INFO 22000 --- [nio-9999-exec-1] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited

使用redis

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings)散列(hashes)列表(lists)集合(sets)有序集合(sorted sets) 与范围查询, bitmapshyperloglogs地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication)LUA脚本(Lua scripting)LRU驱动事件(LRU eviction)事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

Lettuce与Jedis区别

Jedis在实现上是直接连接Redis Server,如果在多线程环境下是非线程安全的。每个线程都去拿自己的Jedis 实例,当连接数量增多时,资源消耗阶梯式增大,连接成本就较高(使用JedisPool会有一定的改善)。

Lettuce的连接是基于Netty的,异步、多线程、事件驱动,连接实例可以在多个线程间共享,当多线程使用同一连接实例时,是线程安全的。

切换Jedis

默认添加了Lettuce,添加jedis依赖,并在配置文件中配置spring.redis.client-type: jedis

    <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 导入jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

引入redis依赖:

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

测试连接是否成功

@Autowired
RedisTemplate redisTemplate;
@Autowired
StringRedisTemplate stringRedisTemplate; @Test
void testRedis(){
ValueOperations<String, String> operations = redisTemplate.opsForValue();
operations.set("hello","world");
String hello = operations.get("hello");
System.out.println(hello);
}

更改默认模板的序列化方式

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer; /**
* 编写配置类,构造RedisTemplate
* 这个springboot已经帮我们配了,但是默认object,这里改成string
*/
@Configuration
public class RedisConfig { @Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 设置key的序列化方式
template.setKeySerializer(RedisSerializer.string());
// 设置value的序列化方式
template.setValueSerializer(RedisSerializer.json());
// 设置hash的key的序列化方式
template.setHashKeySerializer(RedisSerializer.string());
// 设置hash的value的序列化方式
template.setHashValueSerializer(RedisSerializer.json());
template.afterPropertiesSet();
return template;
} }

写RedisUtil类,更方便地使用redis

package com.top.springbootweb.Utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit; @Component
public class RedisUtil { @Autowired
private RedisTemplate<String, Object> redisTemplate; /**
* 指定缓存失效时间
* @param key 键
* @param time 时间(秒)
* @return true / false
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 根据 key 获取过期时间
* @param key 键
* @return
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
} /**
* 判断 key 是否存在
* @param key 键
* @return true / false
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 删除缓存
* @SuppressWarnings("unchecked") 忽略类型转换警告
* @param key 键(一个或者多个)
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
// 传入一个 Collection<String> 集合
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
} // ============================== String ============================== /**
* 普通缓存获取
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
} /**
* 普通缓存放入
* @param key 键
* @param value 值
* @return true / false
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 普通缓存放入并设置时间
* @param key 键
* @param value 值
* @param time 时间(秒),如果 time < 0 则设置无限时间
* @return true / false
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 递增
* @param key 键
* @param delta 递增大小
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于 0");
}
return redisTemplate.opsForValue().increment(key, delta);
} /**
* 递减
* @param key 键
* @param delta 递减大小
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于 0");
}
return redisTemplate.opsForValue().increment(key, delta);
} // ============================== Map ============================== /**
* HashGet
* @param key 键(no null)
* @param item 项(no null)
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
} /**
* 获取 key 对应的 map
* @param key 键(no null)
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
} /**
* HashSet
* @param key 键
* @param map 值
* @return true / false
*/
public boolean hmset(String key, Map<Object, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* HashSet 并设置时间
* @param key 键
* @param map 值
* @param time 时间
* @return true / false
*/
public boolean hmset(String key, Map<Object, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 向一张 Hash表 中放入数据,如不存在则创建
* @param key 键
* @param item 项
* @param value 值
* @return true / false
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 向一张 Hash表 中放入数据,并设置时间,如不存在则创建
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(如果原来的 Hash表 设置了时间,这里会覆盖)
* @return true / false
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 删除 Hash表 中的值
* @param key 键
* @param item 项(可以多个,no null)
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
} /**
* 判断 Hash表 中是否有该键的值
* @param key 键(no null)
* @param item 值(no null)
* @return true / false
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
} /**
* Hash递增,如果不存在则创建一个,并把新增的值返回
* @param key 键
* @param item 项
* @param by 递增大小 > 0
* @return
*/
public Double hincr(String key, String item, Double by) {
return redisTemplate.opsForHash().increment(key, item, by);
} /**
* Hash递减
* @param key 键
* @param item 项
* @param by 递减大小
* @return
*/
public Double hdecr(String key, String item, Double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
} // ============================== Set ============================== /**
* 根据 key 获取 set 中的所有值
* @param key 键
* @return 值
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 从键为 key 的 set 中,根据 value 查询是否存在
* @param key 键
* @param value 值
* @return true / false
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将数据放入 set缓存
* @param key 键值
* @param values 值(可以多个)
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 将数据放入 set缓存,并设置时间
* @param key 键
* @param time 时间
* @param values 值(可以多个)
* @return 成功放入个数
*/
public long sSet(String key, long time, Object... values) {
try {
long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 获取 set缓存的长度
* @param key 键
* @return 长度
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 移除 set缓存中,值为 value 的
* @param key 键
* @param values 值
* @return 成功移除个数
*/
public long setRemove(String key, Object... values) {
try {
return redisTemplate.opsForSet().remove(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} // ============================== List ============================== /**
* 获取 list缓存的内容
* @param key 键
* @param start 开始
* @param end 结束(0 到 -1 代表所有值)
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 获取 list缓存的长度
* @param key 键
* @return 长度
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 根据索引 index 获取键为 key 的 list 中的元素
* @param key 键
* @param index 索引
* 当 index >= 0 时 {0:表头, 1:第二个元素}
* 当 index < 0 时 {-1:表尾, -2:倒数第二个元素}
* @return 值
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 将值 value 插入键为 key 的 list 中,如果 list 不存在则创建空 list
* @param key 键
* @param value 值
* @return true / false
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将值 value 插入键为 key 的 list 中,并设置时间
* @param key 键
* @param value 值
* @param time 时间
* @return true / false
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将 values 插入键为 key 的 list 中
* @param key 键
* @param values 值
* @return true / false
*/
public boolean lSetList(String key, List<Object> values) {
try {
redisTemplate.opsForList().rightPushAll(key, values);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将 values 插入键为 key 的 list 中,并设置时间
* @param key 键
* @param values 值
* @param time 时间
* @return true / false
*/
public boolean lSetList(String key, List<Object> values, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, values);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 根据索引 index 修改键为 key 的值
* @param key 键
* @param index 索引
* @param value 值
* @return true / false
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 在键为 key 的 list 中删除值为 value 的元素
* @param key 键
* @param count 如果 count == 0 则删除 list 中所有值为 value 的元素
* 如果 count > 0 则删除 list 中最左边那个值为 value 的元素
* 如果 count < 0 则删除 list 中最右边那个值为 value 的元素
* @param value
* @return
*/
public long lRemove(String key, long count, Object value) {
try {
return redisTemplate.opsForList().remove(key, count, value);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} }

测试RedisUtil

@SpringBootTest
@Slf4j
public class RedisTest {
@Autowired
RedisUtil redisUtil; @Test
public void testExpire() throws InterruptedException {
redisUtil.set("expire",3);
redisUtil.expire("expire", 4);
log.info("expire time = "+redisUtil.getExpire("expire"));
log.info(String.valueOf("hasKey? " + redisUtil.hasKey("expire")));
Thread.currentThread().sleep(5000);
redisUtil.get("expire");
log.info(String.valueOf("hasKey? " + redisUtil.hasKey("expire")));
}
@Test
public void testDelete(){
redisUtil.set("1",1);
redisUtil.set("2",2);
log.info(String.valueOf(redisUtil.hasKey("1")));
log.info(String.valueOf(redisUtil.hasKey("2")));
redisUtil.del("1","2");
log.info(String.valueOf(redisUtil.hasKey("1")));
log.info(String.valueOf(redisUtil.hasKey("2")));
}
@Test
public void testMap(){
redisUtil.hset("xiaoming","age",17);
redisUtil.hset("xiaoming","name","xiaoming");
} }

Springboot笔记<12>数据访问的更多相关文章

  1. SpringBoot+MyBatis简单数据访问应用

    因为实习用的是MyBatis框架,所以写一篇关于SpringBoot整合MyBatis框架的总结. 一,Pom文件 <?xml version="1.0" encoding= ...

  2. spring boot 尚桂谷学习笔记10 数据访问02 mybatis

    数据访问 mybatis 创建一个 springboot 工程,模块选择 sql 中 mysql(数据驱动), jdbc(自动配置数据源), mybatis Web模块中选择 web pom 引入: ...

  3. 【SpringBoot实战】数据访问

    前言 在开发中我们通常会对数据库的数据进行操作,SpringBoot对关系性和非关系型数据库的访问操作都提供了非常好的整合支持.SpringData是spring提供的一个用于简化数据库访问.支持云服 ...

  4. Spring揭秘读书笔记 八 数据访问异常体系

    这篇博客 来自spring揭秘一书的第十三章 为什么要有访问异常都有一个体系,这个我们得从DAO模式说起. DAO模式 任何一个系统,不管是一个最简单的小系统,还是大规模的系统,都得跟数据打交道,说白 ...

  5. Spring.Net学习笔记(二)-数据访问器

    Spring对ADO.NET也提供了支持,依赖与程序集Spring.Data.dll IDbProvider IDbProvider定义了数据访问提供器的基础,配置如下 <?xml versio ...

  6. SpringBoot起飞系列-数据访问(九)

    一.前言 前边我们已经学些了开发的基本流程,最重要的一步来了,怎么样和数据库交互才是最重要的,毕竟没有数据那就相当于什么也没做,本文我们来学习使用springboot整合jdbc.mybatis.jp ...

  7. spring boot 尚桂谷学习笔记09 数据访问

    springboot 与数据库访问 jdbc, mybatis, spring data jpa,  1.jdbc原生访问 新建项目 使用 springboot 快速构建工具 选中 web 组件 sq ...

  8. spring boot 尚桂谷学习笔记11 数据访问03 JPA

    整合JPA SpringData 程序数据交互结构图 (springdata jpa 默认使用 hibernate 进行封装) 使用之后就关注于 SpringData 不用再花多经历关注具体各个交互框 ...

  9. SpringBoot之旅第五篇-数据访问

    一.引言 大部分系统都离不开数据访问,数据库包括SQL和NOSQL,SQL是指关系型数据库,常见的有SQL Server,Oracle,MySQL(开源),NOSQL是泛指非关系型数据库,常见的有Mo ...

  10. springboot 数据访问【转】【补】

    六.SpringBoot与数据访问 1.JDBC pom.xml配置 <dependencies> <dependency> <groupId>org.spring ...

随机推荐

  1. vim中文乱码 vim字符集设置

    vim中文乱码 vim字符集设置 vim的设置一般放在/etc/vimrc文件中,不过,建议不要修改它.可以修改~/.vimrc文件(默认不存在,可以自己新建一个),写入所希望的设置. set fil ...

  2. HTTP/1.1 优化

    避免发送 HTTP 请求 对于一些具有重复性的 HTTP 请求,比如每次请求得到的数据都一样的,我们可以把这对「请求-响应」的数据都缓存在本地,通过缓存技术减少请求次数. 客户端会把第一次请求以及响应 ...

  3. BUUCTF---Morse

    1.题目 -..../.----/-..../-..../-..../...--/--.../....-/-..../-..../--.../-.../...--/.----/--.../...--/ ...

  4. 基于RK3568 + FPGA国产平台的多通道AD实时采集显示方案分享

    在工业控制与数据采集领域,高精度的AD采集和实时显示至关重要.今天,我们就来基于瑞芯微RK3568J + FPGA国产平台深入探讨以下,它是如何实现该功能的.适用开发环境如下: Windows开发环境 ...

  5. 【JVM之内存与垃圾回收篇】本地方法接口

    本地方法接口 什么是本地方法 简单地讲,一个 Native Method 是一个 Java 调用非 Java 代码的接囗.一个 Native Method 是这样一个 Java 方法:该方法的实现由非 ...

  6. Windows Terminal

    ... Windows Terminal 安装 命令行接口 Windows Terminal 的命令行接口是 wt 因此我们可以在运行输入 wt 打开 Windows Terminal 也可以在资源管 ...

  7. 详细介绍MessageQueueSelector

    一.MessageQueueSelector 详解 MessageQueueSelector 是 RocketMQ 提供的一个接口,用于自定义消息发送时的队列选择策略. 通过实现该接口, 开发者可以控 ...

  8. javaweb基础之HTTP、Request、Response、ServletContext

    一.http协议是一个重要的协议,他是贯穿整合B/S架构的核心协议.因此学习http协议的时候一定要从请求和响应两个角度思考.注意方向性(请求:浏览器->服务器:响应:服务器->浏览器) ...

  9. nohup启动jar包

    1. 后台启动jar包,并追加日志到日志文件run.log nohup java -jar wash-1.0-SNAPSHOT.jar >> run.log 2>&1 &am ...

  10. 一天 Star 破万的开源项目「GitHub 热点速览」

    虽然现在市面上的 AI 编程助手已经"琳琅满目",但顶流就是顶流!OpenAI 新开源的轻量级编程助手 Codex,发布不到 24 小时 Star 数就轻松破万!姗姗来迟的 Ope ...