Redis学习笔记

📅 2021-07-04 12:07 👁️ 60 💬 0

1.Redis是什么?

Redis(Remote Dictionary Server),即远程字典服务

是一个开源的使用ANSI C语言编写的、支持网络、可基于内存、持久化的日志型、key-value型数据库,并提供多种语言API

image-20210415175002559

Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并在此基础上实现了主从同步(master-slave)。

Redis是免费的、开源的,是当下最热门的NoSQL技术之一,也被人们称之为结构化数据库!

2.Redis能干嘛?

  1. 内存存储、持久化,因为内存中的数据断电即失,所以持久化很重要(rdb、aof)

  2. 效率高,可用于高速缓存

  3. 发布订阅系统

  4. 地图信息分析

  5. 计时器、计数器、浏览量……

3.Redis基础知识学习

image-20210415184701665

1.String

127.0.0.1:6379[2]> keys *  # 获取所以的科研
1) "name"
127.0.0.1:6379[2]> set k1 v1  #设置key
OK
127.0.0.1:6379[2]> get k1	#获取值
"v1"
127.0.0.1:6379[2]> exists k1	#判断是否存在
(integer) 1
127.0.0.1:6379[2]> append k1 "hello,world" #追加字符串,
(integer) 13
127.0.0.1:6379[2]> get k1
"v1hello,world"
127.0.0.1:6379[2]> append k2 "hello,world,,,," #不存在的key 就新建key 
(integer) 15
127.0.0.1:6379[2]> get k2
"hello,world,,,,"
127.0.0.1:6379[2]> strlen k1  # 获取key对应值的长度
(integer) 13

2.List

###############################################################
## list常用命令
# lpush
# rpush
127.0.0.1:6379[2]> lpush list1  one  #将一个值或多个值插入列表头部,(头插法,左侧插入)
(integer) 1
127.0.0.1:6379[2]> lpush list1  two
(integer) 2
127.0.0.1:6379[2]> lpush list1  three
(integer) 3
127.0.0.1:6379[2]> lrange list1 0 -1 #获取list1 所有的值
1) "three"
2) "two"
3) "one"
127.0.0.1:6379[2]> rpush list1 right #将一个值或多个值插入,尾插法(右侧插入)
(integer) 4
127.0.0.1:6379[2]> lrange list1 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
##################################################################
# lpop
# rpop
127.0.0.1:6379[2]> lpop list1  #从左侧移除数据
"three"
127.0.0.1:6379[2]> rpop list1	#从左侧移除数据
"right"
127.0.0.1:6379[2]> lrange list1 0 -1
1) "two"
2) "one"

3.Set

#Set 集合(无序不重复)
###########################################################
127.0.0.1:6379[2]> sadd k1 "hello" # sadd 添加元素
(integer) 1
127.0.0.1:6379[2]> sadd k1 "world"
(integer) 1
127.0.0.1:6379[2]> smembers k1	# smembers 查看指定set中的所有元素
1) "world"
2) "hello"
127.0.0.1:6379[2]> sismember k1 hahha	# sismember 判断是否存在,没有就为0,有为1
(integer) 0
127.0.0.1:6379[2]> sismember k1 hello
(integer) 1
############################################################
127.0.0.1:6379[2]> scard k1		# 获取set集合中的内容元素个数!
(integer) 2
127.0.0.1:6379[2]> sadd k1 "ssss"
(integer) 1
127.0.0.1:6379[2]> scard k1
(integer) 3
127.0.0.1:6379[2]> srem k1 ssss # 移除set集合中的指定元素
(integer) 1
127.0.0.1:6379[2]> scard k1
(integer) 2
127.0.0.1:6379[2]> smembers k1
1) "world"
2) "hello"
127.0.0.1:6379[2]> smembers k1
1) "world"
2) "hello"

4.Hash

############################################################
127.0.0.1:6379[2]> hset k1 field1 shizhiming # set一个key-value
(integer) 1
127.0.0.1:6379[2]> hget k1 field1 #获取值
"shizhiming"
127.0.0.1:6379[2]> hmset k1 name szm age 18 sex man
OK
127.0.0.1:6379[2]> hmget k1 name sge sex
1) "szm"
2) (nil)
3) "man"
127.0.0.1:6379[2]> hmget k1 name age sex
1) "szm"
2) "18"
3) "man"
127.0.0.1:6379[2]> hgetall k1 	# 获取全部的数据
1) "field1"
2) "shizhiming"
3) "name"
4) "szm"
5) "age"
6) "18"
7) "sex"
8) "man"
127.0.0.1:6379[2]> hdel k1 field1  # 删除hash指定key字段!对应的value值也就消失了!
(integer) 1
############################################################
127.0.0.1:6379[2]> hlen k1 # 获取hash表的字段数量!
(integer) 3
############################################################
127.0.0.1:6379[2]> hexists k1 name  # 判断hash中指定字段是否存在!
(integer) 1
127.0.0.1:6379[2]> hexists k1 sss
(integer) 0

##################################################################
# 只获得所有field 
# 只获得所有value
127.0.0.1:6379[2]> hkeys k1
1) "name"
2) "age"
3) "sex"
127.0.0.1:6379[2]> hvals k1
1) "szm"
2) "18"
3) "man"

5.Zset

#(有序集合)
#zset k1 score1 v1

127.0.0.1:6379[2]> zadd myzset 1 one	# 添加一个值
(integer) 1
127.0.0.1:6379[2]> zadd myzset 2 two
(integer) 1
127.0.0.1:6379[2]> zadd myzset 3 three
(integer) 1
127.0.0.1:6379[2]> zrange myzset 0 -1	#列出所有的值
1) "one"
2) "two"
3) "three"
127.0.0.1:6379[2]> zadd salary 2500 xiaoming
(integer) 1
127.0.0.1:6379[2]> zadd salary 2000 xihong
(integer) 1
127.0.0.1:6379[2]> zadd salary 1500 xiaohua
(integer) 1
################################################################
127.0.0.1:6379[2]> zrangebyscore salary -inf inf # 显示全部的用户 从小到大!
1) "xiaohua"
2) "xihong"
3) "xiaoming"
127.0.0.1:6379[2]> zrangebyscore salary -inf inf withscores # 显示全部的用户并且附带成 绩
1) "xiaohua"
2) "1500"
3) "xihong"
4) "2000"
5) "xiaoming"
6) "2500"
127.0.0.1:6379[2]> zrange salary 0 -1
1) "xiaohua"
2) "xihong"
3) "xiaoming"
127.0.0.1:6379[2]> zrem salary xiaohua # 移除有序集合中的指定元素
(integer) 1
127.0.0.1:6379[2]> zrange salary 0 -1
1) "xihong"
2) "xiaoming"
  1. Geospatial 地理位置
  2. Hyperloglog 统计基数(不重复的元素)
  3. Bitmap 位图

4.Redis事务处理

Redis 事务本质:一组命令的集合! 一个事务中的所有命令都会被序列化

在事务执行过程的中,会按照顺序执行!

一次性、顺序性、排他性!执行一些列的命令!

--------------队列 set1 set2 set3 执行---------------

Redis事务没有没有隔离级别的概念!

所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行!Exec

Redis单条命令式保存原子性的,但是事务不保证原子性!

redis的事务:

  • 开启事务(multi)

  • 命令入队(......)

  • 执行事务(exec)

正常执行事务

127.0.0.1:6379[2]> multi  ##开启事务
OK
127.0.0.1:6379[2]> set k1 v1
QUEUED		## 入队
127.0.0.1:6379[2]> set k2 v2
QUEUED
127.0.0.1:6379[2]> get k2
QUEUED
127.0.0.1:6379[2]> set k3 v3
QUEUED
127.0.0.1:6379[2]> exec ## 执行
1) OK
2) OK
3) "v2"
4) OK

放弃事物

127.0.0.1:6379[2]> multi
OK
127.0.0.1:6379[2]> set k1 v1
QUEUED
127.0.0.1:6379[2]> set k2 v2
QUEUED
127.0.0.1:6379[2]> set k3 v3
QUEUED
127.0.0.1:6379[2]> discard ## 放弃事务,没有执行队列
OK
127.0.0.1:6379[2]> get k3
(nil)

编译型异常(代码有问题命令错误),所有的命令都不会执行

127.0.0.1:6379[2]> multi
OK
127.0.0.1:6379[2]> set k1 v1
QUEUED
127.0.0.1:6379[2]> set k2 v2
QUEUED
127.0.0.1:6379[2]> get k4 ##不存在K4
QUEUED
127.0.0.1:6379[2]> exec
(error) EXECABORT Transaction discarded because of previous errors.

运行时异常(1/0) 如果事务中存在语法性错误,执行命令时,其他命令可以正常执行,错误命令抛出

127.0.0.1:6379[2]> multi
OK
127.0.0.1:6379[2]> set k1 v1
QUEUED
127.0.0.1:6379[2]> incr k1
QUEUED
127.0.0.1:6379[2]> set k2 v2
QUEUED
127.0.0.1:6379[2]> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK

监控! Watch

127.0.0.1:6379[2]> set money 100
OK
127.0.0.1:6379[2]> set out 0
OK
127.0.0.1:6379[2]> watch money ##监控,如果事务期间没有发生变动,就正常想运行

p
OK
127.0.0.1:6379[2]> multi
OK
127.0.0.1:6379[2]> decrby money 10
QUEUED
127.0.0.1:6379[2]> incrby out 10
QUEUED
127.0.0.1:6379[2]> exec
1) (integer) 90
2) (integer) 10

5.Jedis

Jedis是 Redis 官方推荐的 java连接开发工具!类似于jdbc

测试使用

1.导入对应的依赖

<dependency> 
    <groupId>redis.clients</groupId> 
    <artifactId>jedis</artifactId> 
    <version>3.2.0</version> 
</dependency>

 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>fastjson</artifactId>
     <version>1.2.62</version>
</dependency>

2、测试基本使用

package com.zjjg;
import redis.clients.jedis.Jedis;
public class TestPing {

    public static void main(String[] args) {
        // 连接Redis
        Jedis jedis = new Jedis("127.0.0.1", 6379);
       // 切换数据库
        jedis.select(2);
        jedis.set("name","szm");
        String name = jedis.get("name");
        System.out.println(name);
        // 关闭连接
        jedis.close();
    }
}

image-20210425100344401

测试事务

package com.zjjg;

import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

/**
 * @author xiaoming
 * @version 1.0
 * @date 2021/4/25 10:06
 */
public class TestTask {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.select(2);
        jedis.flushDB();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name","szm");
        jsonObject.put("gender","male");
        String user = jsonObject.toJSONString();
        Transaction multi = jedis.multi();
        try {

            multi.set("user1",user);
            multi.set("user2",user);
            int i=1/0;
            multi.exec();
        }catch (Exception e){
            multi.discard(); //放弃事务
            e.printStackTrace();

        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close(); // 关闭连接
        }

    }
}

image-20210425101641496

正常运行时

image-20210425101728718

6.SpringBoot整合

1.导入依赖

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

 <dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-databind</artifactId>
     <version>2.9.6</version>
</dependency>

2、配置连接

# 配置redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=2

3、使用RedisTemplate方式

package com.zjjg.springbootredis;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class SpringbootRedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        // redisTemplate 操作不同的数据类型,api和我们的指令是一样的
        // opsForValue 操作字符串 类似String
        // opsForList 操作List 类似List
        // opsForSet
        // opsForHash
        // opsForZSet
        // opsForGeo
        // opsForHyperLogLog


        // 清空当前数据库
        redisTemplate.getConnectionFactory().getConnection().flushDb();

        redisTemplate.opsForValue().set("k2","hello,world");
        System.out.println(redisTemplate.opsForValue().get("k2"));

    }

}

image-20210425103551895

image-20210425103536957

发现存储的数据都是乱码的,这关系到存储对象的序列化问题

在RedisTemplate类中,发现默认的序列化方式是采用jdk序列化器,

image-20210425104059127

我们可以自定义RedisTemplate模板,自定义序列化的方式

package com.zjjg.springbootredis.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author xiaoming
 * @version 1.0
 * @date 2021/4/25 9:04
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        // json序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String 的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
         // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet(); return template;
    }
    
      @Bean
    public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
        RedisCacheWriter redisCacheWriter =RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
    }

}

再次运行程序

image-20210425104321959

4、使用注解的方式

@EnableCache

开启缓存

用于

@ Cacheable

主要针对方法配置,能够根据方法的请求参数对其结果进行缓存

当调用注解修饰的方法时,先从缓存中查询,如果不存在,则执行实际方法,将结果存入缓存中,如果存在,返回缓存中的对象

参数

  • value 缓存名称
  • key:缓存的key,可以为空,指定需按照SPEL表达式编写(#{})
  • condition:缓存条件
  • cacheManager:用于指定缓存管理器
  • cacheResolver:指定缓存解析器
  • unless:否定缓存,当unless指定的条件为true 就不会缓存
  • sync:是否使用异步模式,默认是false

@CachePut

能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用

参数

  • value 缓存名称

  • key:缓存的key,可以为空,指定需按照SPEL表达式编写(#{})

  • condition:缓存条件

@CacheEvict

能够根据一定的条件对缓存进行清空

参数

  • value 缓存名称
  • key:缓存的key,可以为空,指定需按照SPEL表达式编写(#{})
  • condition:缓存条件
  • allEntries:是否清空所有的缓存,默认是false
  • beforeInvocation:是否在方法执行前就清空,默认为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存

image-20210427101512811

image-20210427144442317

image-20210427144543283

image-20210427102923492

image-20210427102944515

7.Redis持久化

Redis是内存数据库,如果不将内存中的数据保存到磁盘,一旦服务器进程结束,数据也会消失

1、RDB

RDB=(Redis DataBase)

在指定的时间间隔,将内存中的数据集快照写入数据库,恢复时,直接读取快照文件进行数据恢复

在默认情况下,Redis将数据库快照保存在dump.rdb 二进制文件中,文件名可以在配置文件中自定义

工作原理

  1. Redis 调用forks。同时拥有父进程和子进程。
  2. 子进程将数据集写入到一个临时 RDB 文件中。
  3. 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件

image-20210425111636249

触发机制

  1. save的规则满足的情况下,会自动触发rdb原则
  2. 执行flushall命令,也会触发我们的rdb原则
  3. 退出redis,也会自动产生rdb文件

优缺点

优点:

  1. 适合大规模的数据恢复
  2. 对数据的完整性要求不高

缺点:

  1. 需要一定的时间间隔进行操作,如果redis意外宕机了,这个最后一次修改的数据就没有了。
  2. fork进程的时候,会占用一定的内容空间。

2、AOF

AOF=(Append Only File)

将我们的所有命令都记录下来,恢复的时候就把这个文件全部在执行一遍!

image-20210425112210217

以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件

但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件

的内容将写指令从前到后执行一次以完成数据的恢复工作

优缺点

优点:

1、每一次修改都同步,文件的完整会更加好!

2、每秒同步一次,可能会丢失一秒的数据

3、从不同步,效率最高的!

缺点:

1、相对于数据文件来说,aof远远大于 rdb,修复的速度也比 rdb慢!

2、Aof 运行效率也要比 rdb 慢,所以我们redis默认的配置就是rdb持久化

8.Redis主从复制

概念

主从复制,是指将一台Reids服务器的数据,复制到其他的Redis服务器上

前者称之为主节点(Master/Leader)

后者称之为从节点(Slave/Follower)

数据的复制是单向的,只能由主节点复制到从节点,一般主节点以写为主,从节点以读为主

作用

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式
  2. 故障恢复:当主节点服务器发生故障时,从节点可以暂时代替主节点提供服务
  3. 负载均衡:在主从复制的基础上,配合读写分离,主节点进行写操作,从节点进行读操作,分担服务器负载

进行测试

主节点6379 从节点6380

# info replication 查看当前库的信息
127.0.0.1:6379[3]> info replication
role:master  #角色
connected_slaves:0 #从机数量
master_replid:e204c88ff98046164f30edb278139d15c4577afb
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

#使用`SLAVEOF host port`就可以为从机配置主机了 还可以通过配置文件进行配置
##使用SLAVEOF no one 断开关系
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:a38efbc915f817bee7e9365922be53ecc4e5bbb8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14

127.0.0.1:6379[3]> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=490,lag=0
master_replid:a38efbc915f817bee7e9365922be53ecc4e5bbb8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:490
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:490

使用规则

  1. 从机只能读不能写,主机可读可写,多用于写
127.0.0.1:6380> set k123 v123
(error) READONLY You can't write against a read only replica.
#主机读写
127.0.0.1:6379[3]> set k123 v123
OK
127.0.0.1:6379[3]> get k123
"v123"

#从机读
127.0.0.1:6380> select 3
OK
127.0.0.1:6380[3]> keys *
1) "k123"
127.0.0.1:6380[3]> get k123
"v123"

9.Redis使用规范

1、key命名设计

规范性:以业务名(或数据库名)为前缀,用冒号分隔开,如(数据库名:表名:id)

简洁性:在保证语义的前提下,控制key的长度,当key数量较多时,所占的内存同样不可忽视

注意:不要包含特殊字符,如空格、换行、单引号、双引号、转义字符等

2、value设计

拒绝bigkey,防止慢查询,单个string类型的值大小控制在10kb以内,hash、lish、set、zset元素个数不要超过5000

3、控制key的生命周期

建议使用expire设置过期时间,尽量打散过期时间,不要集中过期

4、禁用命令

禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐进式处理。因为redis是单线程执行,容易导致线上不可用.

5、使用批量命令提高效率

原生命令:例如mget、mset

6、不建议过多使用Redis事务功能

阅读更多

fastjson学习笔记

📅 2021-03-27 10:38 👁️ 191 💬 0

FastJson使用说明

1. FastJson 简介

FastJson 是一个java库,可以将java对象转化成JSON格式,同时也可以将JSON字符串解析成java对象,除此之外还支持 Map、list 转JSON等操作

2. 下载

方式一:直接去mavan中央仓库下载jar包,然后导入项目中

​ 地址:https://github.com/alibaba/fastjson/tree/1.2.75

方式二:配置mavan依赖 https://mvnrepository.com/artifact/com.alibaba/fastjson/1.2.75

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.75</version>
</dependency>

3. 序列化

序列化就是将其他类型转化成json格式

主要代码:

String objJson = JSON.toJSONString(Object object);

1. Map 转 JSON

HashMap<String, String> map = new HashMap<>();
map.put("id","340826");
map.put("phone","15279146568");
String str = JSON.toJSONString(map);

image-20210327075618209

2. List 转 JSON

List<Map<String,String>> list=new LinkedList<>();
HashMap<String, String> map = new HashMap<>();
map.put("id","340826");
map.put("phone","15279146568");

HashMap<String, String> map2 = new HashMap<>();
map2.put("name","xiaoming");
map2.put("sex","male");

list.add(map);
list.add(map2);

String str = JSON.toJSONString(list);
System.out.println(str);

image-20210327075842849

3. java bean 转 JSON

student 实体类:

package com.zjjg.domain;

import java.util.List;
import java.util.Map;

/**
 * @author xiaoming
 * @version 1.0
 * @date 2021/3/26 13:44
 */
public class Student {
    private int id;
    private String name;
    private int age;
    private List<String> hobby;
    // Dog 也是一个实体类
    private List<Dog> dogs;
    private Map<String,String> cards;

  // get,set,有参无参构造方法,tostring方法
}

Dog实体类

public class Dog {

    private String name;
    private int age;

  // get,set,有参无参构造方法,tostring方法
}
Dog ww = new Dog("ww", 3);
Dog wc = new Dog("wc", 4);
ArrayList<Dog> dogArrayList = new ArrayList<>();
dogArrayList.add(ww);
dogArrayList.add(wc);

HashMap<String, String> map = new HashMap<>();
map.put("id","340826");
map.put("phone","15279146568");
List<String> hobby=new LinkedList<>();
hobby.add("LOL");
hobby.add("cf");

Student xm = new Student(1, "xm", 16, hobby, dogArrayList, map);

String s = JSON.toJSONString(xm);
System.out.println(s);

image-20210327081111224

通过输出发现JSON格式有点乱,可以通过格式化的方式将输出的字符串转化成标准的JSON格式

String str = JSON.toJSONString(Object object, boolean prettyFormat);

prettyFormat:为true时,则格式化字符串,成标准的JSON格式,我们将上一个代码为例

// 其他都不变
String s = JSON.toJSONString(xm,true);

image-20210327081820983

4. 其他类型转JSON

FastJson 还提供了许多特性的支持,如格式化日期,处理空值等

String str = JSON.toJSONString(Object object, SerializerFeature features) 

SerializerFeature :序列化的特征,是一个枚举类型,具体类型可进SerializerFeature查看

java.util.Data 转 JSON

当不采用任何格式进行转化,FastJson会将 Date 转化成 Long

Date date = new Date();
String str1 = JSON.toJSONString(date);

输出结果:1616805889867

使用SerializerFeature.WriteDateUseDateFormat格式化日期后

Date date = new Date();
String str2 =JSON.toJSONString(date,SerializerFeature.WriteDateUseDateFormat);
System.out.println(str2);

输出结果:"2021-03-27 08:44:49"

也可以指定日期格式进行转化:JSON.toJSONStringWithDateFormat

Date date = new Date();
String str3 = JSON.toJSONStringWithDateFormat(date, "yyyy-MM-dd");
System.out.println(str3);

输出结果:"2021-03-27"

使用单引号进行输出,以上述Javabean 转 JSON为例

默认情况下,是以双引号

String s = JSON.toJSONString(xm,SerializerFeature.UseSingleQuotes);

image-20210327090023560

输出null字段

默认情况下,不会输出

Map<String,Object> map=new HashMap<>();
String v1=null;
String v2="11";
map.put("k1",v1);
map.put("k2",v2);
String str4 = JSON.toJSONString(map);
System.out.println(str4);

输出结果:{"k2":"11"}

使用 SerializerFeature.WriteMapNullValue

String str5 = JSON.toJSONString(map,SerializerFeature.WriteMapNullValue);
System.out.println(str5);

输出结果:{"k1":null,"k2":"11"}

对非字符串的key值转化成字符

注意:key 才可以转化,value转不了

默认情况下:

Date date = new Date();
Map<Date,Object> map=new HashMap<>();
String v1="000";
map.put(date,v1);
String str6 = JSON.toJSONString(map);
System.out.println(str6);

输出结果:{1616807985732:"000"}

格式化后: SerializerFeature.WriteNonStringKeyAsString

String str6 = JSON.toJSONString(map,SerializerFeature.WriteNonStringKeyAsString);
System.out.println(str6);

输出结果:{"1616808045765":"000"}

序列化写入类的信息

Dog ww = new Dog("ww", 2);
String s = JSON.toJSONString(ww, SerializerFeature.WriteClassName);
System.out.println(s);

输出结果:{"@type":"java.util.HashMap",new Date(1616808415125):"000"}

4. 反序列化

反序列化就是将JSON字符串转化成对应的java bean对象

主要代码:JSON.parseObject(string, **.class)

1. JSON 转 java bean

以上面的java bean 转 JSON 为基础,得到转化后的字符串,又将转化成java bean对象

Student student = JSON.parseObject(s, Student.class);
System.out.println(student);

image-20210327093523544

如果我们在java bean转 JSON 时加上类的信息,可以直接进行转化,不需要指定类

Student xm = new Student(1, "xm", 16, list, dogArrayList, map);
String s=JSON.toJSONString(xm,SerializerFeature.WriteClassName);
System.out.println(s);
Student student = (Student) JSON.parse(s);
System.out.println(student);

image-20210327094235954

在自动转化时出现错误,通过从查找资料得到

问题产生的原因:在1.2.25之后的版本,以及所有的.sec01后缀版本中,autotype功能是受限的,和之前的版本不同,如果在升级的过程中遇到问题,可以通过以下方法配置。总而言之:在1.2.25版本过后,禁用了部分autotype功能,

解决办法:打开autotype,

官方解决办法:https://github.com/alibaba/fastjson/wiki/enable_autotype

方式一:加上jvm 启动参数

image-20210327095218455

image-20210327095248402

image-20210327095315729

方式二 直接在代码上加上 ParserConfig.getGlobalInstance().setAutoTypeSupport(true);

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
Student xm = new Student(1, "xm", 16, list, dogArrayList, map);
String s=JSON.toJSONString(xm,SerializerFeature.WriteClassName);
System.out.println(s);
Student student = (Student) JSON.parse(s);
System.out.println(student);

image-20210327094754920

2. JSON 转 Map

String str="{\"phone\":\"15279146568\",\"id\":\"340826\"}";
System.out.println(str);
Map<String, Object> map1 = JSON.parseObject(str, new TypeReference<Map<String, Object>>() {});
System.out.println(map1.get("id"));
System.out.println(map1.get("phone"));

输出结果:
340826
15279146568

3. JSON 转 list

String str = "[{\"phone\":\"15279146568\",\"id\":\"340826\"},{\"sex\":\"male\",\"name\":\"xiaoming\"}]";
System.out.println(str);
List<Map> list1 = JSON.parseArray(str, Map.class);
Object[] objects = list.toArray(); // list 转 数组
String s = Arrays.toString(objects); // 数组 转 string
System.out.println(s);

输出结果:[{phone=15279146568, id=340826}, {sex=male, name=xiaoming}]

5. JSONObject,JSONArray

JSONObject,JSONArray是JSON的两个子类。

JSONObject相当于 Map<String, Object>

JSONArray相当于 List

JSONobject

   HashMap<String, Object> map = new HashMap<>();
        map.put("k1","v1");
        map.put("k2","v2");

        JSONObject jsonObject = new JSONObject(map);
        jsonObject.put("k3","v3");
       
        Object k1 = jsonObject.get("k1");
        Object k2 = jsonObject.get("k2");
        Object k3 = jsonObject.get("k3");
        
        System.out.println(k1);
        System.out.println(k2);
        System.out.println(k3);

输出结果:
v1
v2
v3

JSONAaary

List<Map<String,String>> list=new LinkedList<>();
HashMap<String, String> map = new HashMap<>();
map.put("id","340826");
map.put("phone","15279146568");

HashMap<String, String> map2 = new HashMap<>();
map2.put("name","xiaoming");
map2.put("sex","male");

list.add(map);
list.add(map2);
JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(list));

JSONObject jsonObject = jsonArray.getJSONObject(0);
Object id = jsonObject.get("id");
System.out.println(id);
Object[] objects = jsonArray.toArray();
String s = Arrays.toString(objects);
System.out.println(s);

image-20210327103153910

阅读更多

getRequestDispatcher()与sendRedirect()的区别

📅 2021-03-12 13:00 👁️ 147 💬 0

getRequestDispatcher()与sendRedirect()的区别

  1. request.getRequestDispatcher()是请求转发,前后页面共享一个request ;
    response.sendRedirect()是重新定向,前后页面不是一个request

  2. RequestDispatcher.forward()是在服务器端运行;
    HttpServletResponse.sendRedirect()是通过向客户浏览器发送命令来完成.

  3. ServletContext.getRequestDispatcher(String url)中的url只能使用绝对路径;

    ServletRequest.getRequestDispatcher(String url)中的url可以使用相对路径。因为

    ServletRequest具有相对路径的概念;而ServletContext对象无此概念

  4. response.sendRedirect(url)跳转到指定的URL地址,产生一个新的request,所以要传递参数只有在url后加参,如www.baidu.com?id=1
    request.getRequestDispatcher(url).forward(request,response)是直接将请求转发到指定URL,所以该请求能够直接获得上一个请求的数据,也就是说采用请求转发,request对象始终存在,不会重新创建。而sendRedirect()会新建request对象,所以上一个request中的数据会丢失。
    注意

    • sendRedirect(url):会首先发一个response给浏览器, 然后浏览器收到这个response后再发一个requeset给服务器, 然后服务器发新的response给浏览器. 这时页面收到的request是一个新从浏览器发来的.

    • forward 发生在服务器内部, 在浏览器完全不知情的情况下发给了浏览器另外一个页面的response. 这时页面收到的request不是从浏览器直接发来了,可能己经request.setAttribute在request里放了数据.在转到的页面可直接用request.getAttribute获得数据。

  5. 运用forward方法只能重定向到同一个Web应用程序中的一个资源。而sendRedirect方法可以让你重定向到任何

    如:sendRedirect("/t1") 表示相对于服务器根路径

    网址http://localhost:8080/Test 则提交到 http://localhost:8080/t1

    Forward代码中的"/uu"则代表相对与WEB应用的路径

    如http://localhost:8080/Test 则提交至http://localhost:8080/Test/t1

  6. forward()无法重定向至有frame的jsp文件,可以重定向至有frame的html文件,
    forward()无法在后面带参数传递,比如servlet?name=frank,这样不行,可以程序内通过
    response.setAttribute("name",name)来传至下一个页面.
    重定向后浏览器地址栏URL不变.

阅读更多

计算机网络相关知识

📅 2021-03-11 15:13 👁️ 116 💬 0

前言

计算机网络学习的核心就是网络协议的学习。

网络协议是为了计算机网络进行数据交换而建立的规则、标准或者是约定的集合。

因为不同用户的数据终端可能采取不同的字符集, 两者之间需要进行通信就必须在一定的标准上。

计算机网络协议同我们的语言一样,多种多样。而ARPA公司与1977年到1979年推出了一种名为ARPANET的网络协议受到了广泛的热捧,其中最主要的原因就是它推出了人尽皆知的TCP/IP标准网络协议。目前TCP/IP协议已经成为Internet中的"通用语言",

计算机网络相关知识

1. 网络层次的划分

1.1 为什么要进行网络层次的划分

在计算机领域,任何问题到了某个复杂的阶段,如果当前方法不能解决问题,必定可以通过加多一层来解决,如果加多一层都解决不了问题,那肯定是这个问题模型的层次已经到极限了

  • 各个层次之间相互独立,每一层只实现一种相对独立的功能,可以将一个难题细分成若干部分进行解决,有助于各个部门的开发设计和故障排除,并且能促进标准化工作。
  • 灵活性高,当任何一层发生变化时(例如由于技术的变化),只要层间接口关系保持不变,则在这层以上或以下各层均不受影响。此外,对某一层提供的服务还可进行修改。

2 OSI 七层网络模型

OSI七层网络模型: 应用层 --->表示层---->会话层----->传输层-----> 网络层 -----> 数据链路层 ------->物理层

  1. 物理层

    • 该层为上层协议提供了一个传输数据可靠的物理媒体。确保原始的数据可在各种物理媒体上传输

    • 重要设备名称:中继器(放大器)、集线器

  2. 数据链路层

    最基本的服务是将源自网络层来的数据可靠地传输到相邻节点的目标机网络层

    该层的作用包括:物理地址寻址、数据的成帧、流量控制、数据的检错、重发等。

    • 数据链路层为网络层提供可靠的数据传输
    • 基本数据单位为帧;
    • 主要的协议:以太网协议;
    • 重要的设备名称:网桥和交换机
  3. 网络层

    目的是实现两个端系统之间的数据透明传送,具体功能包括寻址和路由选择、连接的建立、保持和终止等。

    • 网络层负责对子网间的数据包进行路由选择。此外,网络层还可以实现拥塞控制、网际互连等功能;

    • 基本数据单位为IP数据报;

    • 包含的主要协议:

      • IP协议(Internet Protocol,因特网互联协议);
      • ICMP协议(Internet Control Message Protocol,因特网控制报文协议);
      • ARP协议(Address Resolution Protocol,地址解析协议)
      • RARP协议(Reverse Address Resolution Protocol,逆地址解析协议)。
    • 重要的设备:路由器。

  4. 运输层

    第一个端到端,即主机到主机的层次。传输层负责将上层数据分段并提供端到端的、可靠的或不可靠的传输

    传输层的任务是根据通信子网的特性,最佳的利用网络资源,为两个端系统的会话层之间,提供建立、维护和取消传输连接的功能

    • 传输层负责将上层数据分段并提供端到端的、可靠的或不可靠的传输以及端到端的差错控制和流量控制问题;

    • 包含的主要协议:TCP协议(Transmission Control Protocol,传输控制协议)、UDP协议(User Datagram Protocol,用户数据报协议)

    • 重要设备:网关

  5. 会话层

    会话层管理主机之间的会话进程,即负责建立、管理、终止进程之间的会话。会话层还利用在数据中插入校验点来实现数据的同步

  6. 表示层

    表示层对上层数据或信息进行变换以保证一个主机应用层信息可以被另一个主机的应用程序理解。

    表示层的数据转换包括数据的加密、压缩、格式转换等

  7. 应用层

    为操作系统或网络应用程序提供访问网络服务的接口。

    会话层、表示层和应用层重点:

    • 数据传输基本单位为报文;
    • 包含的主要协议:
      • FTP(文件传送协议)
      • Telnet(远程登录协议)
      • DNS(域名解析协议)
      • SMTP(邮件传送协议)
      • POP3协议(邮局协议)
      • HTTP协议(Hyper Text Transfer Protocol)
阅读更多

mavan的安装与配置

📅 2021-03-05 18:10 👁️ 228 💬 0

1、下载mavan

下载路径:http://maven.apache.org/download.cgi

2、安装mavan

将下载好的压缩包解压到指定位置

3、配置系统环境变量

添加一个MAVAN_HOME的变量,指定mavan的安装路径如:

变量名:MAVEN_HOME
变量值:D:\enviornment\apache-maven-3.6.3

path中添加路径

%MAVEN_HOME%\bin

4、测试安装是否成功

win + r --->cmd----->mvn -v

5、配置mavan本地仓库

  • 在mavan安装路径下新建一个文件夹:repository

  • 在mavan的安装路径--->conf--->setting.xml

  • 修改默认的本地仓库路径

    <localRepository>D:/enviornment/apache-maven-3.6.3/repository</localRepository>
    

  • 配置终于仓库镜像

在setting.xml中修改镜像,使用阿里云

<mirror>
      <id>nexus-aliyun</id>
	  <mirrorOf>central</mirrorOf>
	  <name>Nexus aliyun</name>
	  <url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>


配置到此结束!!!

阅读更多

Tomcat的安装与配置

📅 2021-03-05 17:01 👁️ 77 💬 0

1. tomcat的下载地址:https://tomcat.apache.org/


2. 下载好进行解压

3.进行测试,在bin-->startbat 打开,进行测试,安装成功显示tomcat官网

出现的问题:

双击start.bat闪退

解决方法:用文本编辑器打开start.bat,在最后(end之前) 加上 pause 进行调试,若打印的错误为:neither the java_home nor jre_home environment variable is

问题产生原因是:启动tomcat时找不到 javahome 和jrehome的路径

由于start.bat 调用 catalina.batcatalina.bat 调用 setclasspath.bat

我们只需要在setclasspath.bat 上加上路径即可(自己安装java时的路径)

set JAVA_HOME=D:\enviornment\jdk8
set JRE_HOME=D:\enviornment\jdk8\jre1.8.0_181

运行tomcat时,命令行乱码

解决办法:

在tomcat安装目录 找到conf--->logging.properties,加上:

java.util.logging.ConsoleHandler.encoding = GBK


注意:启动tomcat后,如果再次点击start.bat 会出现闪退的情况,需要将tomcat关闭(showdown.bat)关闭后在进行启动,就不会出现闪退的情况

阅读更多

Idea 连接MySQL数据库

📅 2021-03-05 14:49 👁️ 684 💬 0

Idea 连接MySQL数据库

注意:

  • 需要导入jar包,mysql-connector-java-8.0.16.jar
  • mysql8.0及以上 使用的驱动 drive=com.mysql.cj.jdbc.Driver;
  • url="jdbc:mysql://localhost:3306/(设计的数据库名称)?useSSL=false&serverTimezone=Asia/Shanghai"
import java.sql.*;

/**
 * @author xiaoming
 * @create 2021-03-05 12:11
 */

public class MySqlTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {

        // MySQL8.0及以上版本使用
        String driver="com.mysql.cj.jdbc.Driver";
        // 连接上自己新建的数据库,设置useSSL=false,设置时区serverTimezone=Asia/Shanghai
        String url="jdbc:mysql://localhost:3306/MySQLTest?useSSL=false&serverTimezone=Asia/Shanghai";
        String user="root";
        String passWord="123456";
        Connection conn=null;
        Statement stmt =null;

        try {
            // 1、加载驱动
            Class.forName(driver);
            // 2、建立连接
            conn = DriverManager.getConnection(url, user, passWord);
            // 3.创建执行语句的对象
            stmt = conn.createStatement();
            String sql="select ID,Name ,Age,Sex FROM MySqlTest.user";
            // 4.执行数据库语句
            ResultSet resultSet = stmt.executeQuery(sql);

            // 5.输出数据
            while (resultSet.next()){
                System.out.print("id"+resultSet.getInt("id"));
                System.out.print("Name"+resultSet.getString("Name"));
                System.out.print("Age"+resultSet.getInt("Age"));
                System.out.print("Sex"+resultSet.getString("Sex"));
                System.out.println();
            }

        } catch (SQLException SE) {
            SE.printStackTrace();
        }finally {

            // 6. 关闭连接
            stmt.close();
            conn.close();

        }
    }
}

结果图:

阅读更多

Java GUI 实现发送邮件以及附件

📅 2021-03-05 11:27 👁️ 209 💬 0

实现代码:

注意点:

  • 需要的jar包:JavaMail API 和Java Activation Framework (JAF) ,下载可参考菜鸟教程
  • 默认使用QQ邮箱发送,需要设置授权,设置-->账户->POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务
  • 发件人代码中已设置,只需提供收件人邮箱
import com.sun.mail.util.MailSSLSocketFactory;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Properties;

/**
 * @author xiaoming
 * @create 2021-03-04 9:52
 */
public class Email {

    public static void main(String[] args) {
        JFrame jFrame = new JFrame("Send Email");
        jFrame.setBounds(500, 200, 600, 700);
        // 设置窗口不可拉伸
        jFrame.setResizable(false);
        jFrame.add(new SendPanel(jFrame));
        jFrame.setVisible(true);
        // 设置窗口关闭
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}

class SendPanel extends JPanel {
    private String EmailTo;
    private String Subject;
    private String Text;
    private String FileName;
    JFrame jFrame;
    public SendPanel(JFrame jFrame) {
        this.jFrame=jFrame;
        setBounds(0, 0, 600, 700);
        JLabel jLabelTo = new JLabel("收件人");
        jLabelTo.setLocation(100, 70);
        jLabelTo.setSize(50, 50)
        JTextField jTextFieldTo = new JTextField(1);
        jTextFieldTo.setLocation(150, 80);
        jTextFieldTo.setSize(300, 30);
        jTextFieldTo.setToolTipText("请输入QQ邮箱地址");
        jTextFieldTo.setText("请输入QQ邮箱地址");
        jTextFieldTo.setBackground(new Color(204, 204, 204));

        // 设置焦点监听
        jTextFieldTo.addFocusListener(new FocusListener(){
            @Override
            public void focusGained(FocusEvent e) {
                if ("请输入QQ邮箱地址".equals(jTextFieldTo.getText())){
                    jTextFieldTo.setText("");
                    jTextFieldTo.setBackground(Color.white);
                }
            }
            @Override
            public void focusLost(FocusEvent e) {
                if (jTextFieldTo.getText().length()<1){
                    jTextFieldTo.setText("请输入QQ邮箱地址");
                    jTextFieldTo.setBackground(new Color(204, 204, 204));
                }else {
                     EmailTo=jTextFieldTo.getText();
                    String regex="[1-9][0-9]{8,10}\\@[q][q]\\.[c][o][m]";
                    if (!EmailTo.matches(regex)){
                        JOptionPane.showMessageDialog(jTextFieldTo,"输入邮箱错误,请输入QQ邮箱","提示",JOptionPane.ERROR_MESSAGE);
                    }
                    System.out.println(EmailTo);
                }

            }
        });
        JLabel jLabelSubject = new JLabel("主题");
        jLabelSubject.setLocation(110,150);
        jLabelSubject.setSize(50,50);
        JTextField jTextFieldSubject = new JTextField(1);
        jTextFieldSubject.setLocation(150, 160);
        jTextFieldSubject.setSize(300, 30);
        jTextFieldSubject.setToolTipText("请输入邮件主题");
        jTextFieldSubject.setText("请输入邮件主题");
        jTextFieldSubject.setBackground(new Color(204, 204, 204));
        // 设置焦点监听
        jTextFieldSubject.addFocusListener(new FocusListener(){

            @Override
            public void focusGained(FocusEvent e) {
                if ("请输入邮件主题".equals(jTextFieldSubject.getText())){
                    jTextFieldSubject.setText("");
                    jTextFieldSubject.setBackground(Color.white);
                }
            }
            @Override
            public void focusLost(FocusEvent e) {
                if (jTextFieldSubject.getText().length()<1){
                    jTextFieldSubject.setText("请输入邮件主题");
                    jTextFieldSubject.setBackground(new Color(204, 204, 204));
                }else {
                    Subject=jTextFieldSubject.getText();
                    System.out.println(Subject);
               }
            }
        });
        JLabel jLabelText = new JLabel("正文");
        jLabelText.setSize(50,50);
        jLabelText.setLocation(110,250);
        JTextArea jTextAreaText= new JTextArea();
        jTextAreaText.setSize(300,300);
        jTextAreaText.setLocation(150,250);
        jTextAreaText.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {
            }
            @Override
            public void focusLost(FocusEvent e) {
                if (jTextAreaText.getText().length()<1 && jTextFieldTo.getText().length()>1 && jLabelSubject.getText().length()>1){
                    JOptionPane.showMessageDialog(jTextAreaText,"输入内容为空","提示",JOptionPane.INFORMATION_MESSAGE);
                } else {
                    Text=jTextAreaText.getText();
                }
            }
        });
        JButton jButton=new JButton("发送");
        jButton.setSize(200,50);
        jButton.setLocation(390,600);
        jButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {

                    if ("请输入QQ邮箱地址".equals(jTextFieldTo.getText())){
                        JOptionPane.showMessageDialog(jButton,"无收件人","提示",JOptionPane.ERROR_MESSAGE);

                    }
                    boolean state=SendMessageState(EmailTo,Subject,Text,FileName);
                     if(state){
                        JOptionPane.showMessageDialog(jButton,"发送成功","提示",JOptionPane.INFORMATION_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(jButton,"发送失败","提示",JOptionPane.ERROR_MESSAGE);
                    }

                } catch (GeneralSecurityException generalSecurityException) {
                    generalSecurityException.printStackTrace();
                }
            }
        });
        JButton jButtonSelectFile=new JButton("选择");
        jButtonSelectFile.setSize(200,50);
        jButtonSelectFile.setLocation(10,600);
        jButtonSelectFile.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JFileChooser chooser = new JFileChooser();
                //设置选择目录
                chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);

                int reg = chooser.showOpenDialog(null);
                if(reg == JFileChooser.APPROVE_OPTION)
                {
                    //获得选择到的文件
                    File file = chooser.getSelectedFile();
                    try {
                        FileName=file.getCanonicalPath();
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                    }
                    System.out.println(FileName);
                }
            }
        });
        setLayout(null);
        add(jLabelTo);
        add(jTextFieldTo);
        add(jLabelSubject);
        add(jTextFieldSubject);
        add(jLabelText);
        add(jTextAreaText);
        add(jButton);
        add(jButtonSelectFile);
    }
    public static Boolean SendMessageState(String to,String subject,String text,String fileName) throws GeneralSecurityException {
        boolean state=false;
        // 收件人邮箱
        String TO=to;
        // 发件人邮箱 
        String from="*********@qq.com";
        // 发送邮件的主机
        String host="smtp.qq.com";
        // 获取系统的属性
        Properties properties=System.getProperties();

        // 设置邮件服务器
        properties.setProperty("mail.smtp.host",host);
        // 需要验证用户名密码
        properties.put("mail.smtp.auth",true);

        // QQ邮箱使用SSL加密
        MailSSLSocketFactory mailSSLSocketFactory = new MailSSLSocketFactory();
        mailSSLSocketFactory.setTrustAllHosts(true);
        properties.put("mail.smtp.ssl.enable",true);
        properties.put("mail.smtp.ssl.socketFactory",mailSSLSocketFactory);
        Session session = Session.getDefaultInstance(properties, new Authenticator() {
            @Override
            protected javax.mail.PasswordAuthentication getPasswordAuthentication() {

                return new PasswordAuthentication("2649144933@qq.com","vfaeejtwfrapecih") ;
            }
        });
        MimeMessage mimeMessage=new MimeMessage(session);
        try {
            // 发送方
            mimeMessage.setFrom(new InternetAddress(from));
            // 接受方
            mimeMessage.addRecipient(MimeMessage.RecipientType.TO, new InternetAddress(TO));
            // 邮件的标题/主题
            mimeMessage.setSubject(subject);
            //创建消息部分
            MimeBodyPart MessagePart = new MimeBodyPart();
            //添加正文
            MessagePart.setText(text);
            // 创建多重消息
            Multipart multipart = new MimeMultipart();
            multipart.addBodyPart(MessagePart);
            if (fileName!=null){
                // 截取路径后面的文件名称
                String name= fileName.substring(fileName.lastIndexOf("\\")+1);
                System.out.println(name);
                MessagePart=new MimeBodyPart();
                FileDataSource fileDataSource = new FileDataSource(fileName);
                MessagePart.setDataHandler(new DataHandler(fileDataSource));
                MessagePart.setFileName(name);
                multipart.addBodyPart(MessagePart);
            }
            // 发送完整消息
            mimeMessage.setContent(multipart);
            // 发送信息
            Transport.send(mimeMessage);
            state= true;

        } catch (MessagingException e) {
            e.printStackTrace();
        }
        System.out.println(state);
        return state;
    }
}

使用界面:

使用效果:

阅读更多

GET和POST两种基本请求方法的区别

📅 2020-11-11 17:04 👁️ 121 💬 0
  • GET在浏览器回退时是无害的,post会再次提交请求

  • GET产生的URL地址可以被Bookmark,而POST不可以

  • GET请求会被浏览器主动cache,而POST不会,除非手动设置

  • GET请求只能进行url编码,而POST支持多种编码方式

  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留

  • GET请求在URL中传送的参数是有长度限制的,而POST没有

  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制

  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

  • GET参数通过URL传递,POST放在Request body中。

阅读更多
点击右上角即可分享
微信分享提示