如何搭建fastdfs服务及单机redis服务

fastdfs服务搭建

先要安装gcc编译器&
#xff1a;

yum -y install gcc-c++

安装lib依赖包tar -zxvf V1.0.43.tar.gz
cd libfastcommon-1.0.43
./make.sh
./make.sh install

ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so
ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so 安装fastdfs服务tar -zxvf V6.06.tar.gz
cd fastdfs-6.06
./make.sh
./make.sh install 配置Tracker服务mkdir -p /data/fastdfs/tracker
cd /etc/fdfs
cp tracker.conf.sample tracker.conf
vim tracker.conf

要修改的内容为

#启用配置文件&
#xff08;
默认启用&
#xff09;

disabled=false
#设置tracker的端口号&
#xff0c;
通常采用22122这个默认端口
port=22122
#设置tracker的数据文件和日志目录
base_path=/data/fastdfs/tracker
#设置http端口号&
#xff0c;
默认为8080
http.server_port=80

启动服务

#启动
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf start

查看是否启动

#查看启动端口
ss -ant | grep 22122

查看启动日志

#查看启动日志
tail -f /data/fastdfs/tracker/logs/trackerd.log

加入开机启动

vim /etc/rc.d/rc.local

在加入启动命令

如果重启后发现未能自动启动则通过命令

ll /etc/rc.d/rc.local

检查一下rc.local是否具备可执行权限&
#xff0c;
若是无可执行权限则通过命令进行授权

chmod +x /etc/rc.d/rc.local 配置Storage服务mkdir -p /data/fastdfs/storage
mkdir -p /data/fastdfs/storage/file
cd /etc/fdfs
cp storage.conf.sample storage.conf
vim storage.conf

要修改的内容为

#启用配置文件&
#xff08;
默认启用&
#xff09;

disabled=false
#组名&
#xff0c;
根据实际情况修改
group_name=group1
#设置storage的端口号&
#xff0c;
默认是23000&
#xff0c;
同一个组的storage端口号必须一致
port=23000
#设置storage数据文件和日志目录
base_path=/data/fastdfs/storage
#存储路径个数&
#xff0c;
需要和store_path个数匹配
store_path_count=1
#实际文件存储路径
store_path0=/data/fastdfs/storage/file
#tracker 服务器的 IP地址和端口号&
#xff0c;
如果是单机搭建&
#xff0c;
IP不要写127.0.0.1&
#xff0c;
否则启动不成功&
#xff08;
此处的ip是我的CentOS虚拟机ip&
#xff09;

tracker_server=172.16.6.50:22122
#设置 http 端口号
http.server_port=8888

启动服务

#启动
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf start

查看启动端口

#查看启动端口
ss -ant | grep 23000

查看启动日志

#查看启动日志
tail -f /data/fastdfs/storage/logs/storaged.log

通过monitor查看storage是否绑定成功

[root@localhost /]# /usr/bin/fdfs_monitor /etc/fdfs/storage.conf
[2021-09-23 12:59:26] DEBUG - base_path=/opt/fastdfs_storage, connect_timeout=30, network_timeout=60, tracker_server_count=1, anti_steal_token=0, anti_steal_secret_key length=0, use_connection_pool=0, g_connection_pool_max_idle_time=3600s, use_storage_id=0, storage server id count: 0

server_count=1, server_index=0

tracker server is 172.16.8.11:22122

group count: 1

Group 1:
group name = group1
disk total space = 6818 MB
disk free space = 2169 MB
trunk free space = 0 MB
……

加入开机启动

vim /etc/rc.d/rc.local

在该文件中&
#xff0c;
加入启动命令

/usr/bin/fdfs_storaged /etc/fdfs/storage.conf start 测试验证[root@localhost ~]# ps -ef|grep fdfs
root 10335 17685 0 23:50 pts/3 00:00:00 grep --color=auto fdfs
root 13335 1 0 13:17 ? 00:00:07 /usr/bin/fdfs_storaged /etc/fdfs/storage.conf start
root 15779 1 0 12:59 ? 00:00:04 /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf

用fdfs客户端进行测试

cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf

测试时需要设置客户端的配置文件

vim /etc/fdfs/client.conf

打开文件后依次做以下修改&
#xff1a;

#tracker服务器文件路径
base_path=/data/fastdfs/tracker
#tracker服务器IP地址和端口号
tracker_server=172.16.7.50:22122
# tracker 服务器的 http 端口号&
#xff0c;
必须和tracker的设置对应起来
http.tracker_server_port=80

配置完成后就可以模拟文件上传了&
#xff0c;
先给/data目录下放一文件test.txt&
#xff0c;
然后通过执行客户端上传命令尝试上传&
#xff1a;

/usr/bin/fdfs_upload_file /etc/fdfs/client.conf /data/test.txt 单机redis服务搭建1.获取redis资源&
#xff0c;
并解压tar xzvf redis-4.0.8.tar.gz 2.安装cd redis-4.0.8
make
cd src
make install PREFIX=/usr/local/redis 3.移动配置文件到安装目录下cd ../
mkdir /usr/local/redis/etc
mv redis.conf /usr/local/redis/etc 4.配置redis为后台启动vim /usr/local/redis/etc/redis.conf

注意&
#xff0c;
将daemonize no 改成daemonize yes&
#xff0c;
及注释掉bind 127.0.0.1&
#xff0c;
可以远程访问

5.将redis加入到开机启动 vim /etc/rc.d/rc.local

在里面添加内容&
#xff1a;

/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf

意思就是开机调用这段开启redis的命令.

6.启动redis/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf 7.将redis-cli,redis-server拷贝到bin下&
#xff0c;
让redis-cli指令可以在任意目录下直接使用cp /usr/local/redis/bin/redis-server /usr/local/bin/
cp /usr/local/redis/bin/redis-cli /usr/local/bin/ 8.设置redis密码a.运行命令&
#xff1a;
redis-cli b.查看现有的redis密码(可选操作&
#xff0c;
可以没有)

运行命令&
#xff1a;

config get requirepass

如果没有设置过密码的话运行结果会如下图所示

c.设置redis密码

运行命令&
#xff1a;

config set requirepass *******

(******为你要设置的密码)&
#xff0c;
设置成功的话会返回‘OK’字样

d.测试连接

重启redis服务

//****为你设置的密码
redis-cli -h 127.0.0.1 -p 6379 -a ****

也可以&
#xff0c;
输入 redis-cli 进入命令模式&
#xff0c;
使用 auth '
*****'
&
#xff08;
****为你设置的密码&
#xff09;
登陆     

9.让外网能够访问redisa.配置防火墙:#开放6379端口
firewall-cmd --zone=public --add-port=6379/tcp --permanent
#重启防火墙以使配置即时生效
systemctl restart firewalld
#查看系统所有开放的端口
firewall-cmd --zone=public --list-ports b.若是仍不可远程访问&
#xff1a;

此时 虽然防火墙开放了6379端口&
#xff0c;
但是外网还是无法访问的&
#xff0c;
因为redis监听的是127.0.0.1:6379&
#xff0c;
并不监听外网的请求。

  • 把文件夹目录里的redis.conf配置文件里的bind 127.0.0.1前面加#注释掉

  • 命令&
    #xff1a;
    redis-cli连接到redis后&
    #xff0c;
    通过 config get daemonize和config get protected-mode 是不是都为no&
    #xff0c;
    如果不是&
    #xff0c;
    就用config set 配置名 属性 改为no。

  • 其他redis相关常用命令  卸载redis&
    #xff1a;
    #停止redis
    pkill redis   
    #删除安装目录
    rm -rf /usr/local/redis
    #删除所有redis相关命令脚本
    rm -rf /usr/bin/redis-*
    #删除redis解压文件夹
    rm -rf /root/download/redis-4.0.4 报异常&
    #xff0c;
    尝试重启

    原因: Redis已经启动

    解决: 关掉Redis,重启即可

    redis-cli shutdown
    redis-server &

    然后你就能看到Redis愉快的运行了.

    客户端检测连接是否正常

    使用redis-cli客户端检测连接是否正常

    $redis-cli
    127.0.0.1:6379>
    keys *
    (empty list or set)
    127.0.0.1:6379>
    set key "
    hello world"

    OK
    127.0.0.1:6379>
    get key
    "
    hello world"
    Redis客户端常见操作

    Redis是key-value数据库&
    #xff0c;
    支持五种数据类型&
    #xff1a;
    string&
    #xff08;
    字符串&
    #xff09;
    &
    #xff0c;
    hash&
    #xff08;
    哈希&
    #xff09;
    &
    #xff0c;
    list&
    #xff08;
    列表&
    #xff09;
    &
    #xff0c;
    set&
    #xff08;
    集合&
    #xff09;
    及zset(sorted set&
    #xff1a;
    有序集合)。

    当value是string类型&
    #xff0c;
    命令包括set get setnx incr del 等。>
    set server:name "
    fido"
    // 设置键值
    OK
    >
    get server:name // 获取键值
    "
    fido"

    >
    setnx connections 10 // set if not exists
    OK
    >
    incr connections // 原子性增加values值
    (integer) 11
    >
    incr connections
    (integer) 12
    >
    del connections // 删除key
    (integer) 1
    >
    incr connections
    (integer) 1 当value是list类型&
    #xff0c;
    命令包括rpush lpush llen lrange lpop rpop del 等。>
    rpush friends "
    Alice"
    // 在末尾追加
    (integer) 1
    >
    rpush friends "
    Bob"

    (integer) 2
    >
    lpush friends "
    Sam"
    // 插入到开头
    (integer) 3
    >
    lrange friends 0 -1 // 返回列表的子集&
    #xff0c;
    类似切片操作
    1) "
    Sam"

    2) "
    Alice"

    3) "
    Bob"

    >
    lrange friends 0 1
    1) "
    Sam"

    2) "
    Alice"

    >
    lrange friends 1 2
    1) "
    Alice"

    2) "
    Bob"

    >
    llen friends // 返回列表长度
    (integer) 3
    >
    lpop friends // 删除并返回列表第一个元素
    "
    Sam"

    >
    rpop friends // 删除并返回列表最后一个元素
    "
    Bob"

    >
    lrange friends 0 -1
    1) "
    Alice"

    >
    del friends // 删除key
    (integer) 1 // 1表示成功&
    #xff0c;
    0表示失败 当value是set类型&
    #xff0c;
    命令包括sadd srem sismember smembers sunion del等。>
    sadd superpowers "
    flight"
    // 添加元素
    (integer) 1
    >
    sadd superpowers "
    x-ray vision"

    (integer) 1
    >
    sadd superpowers "
    reflexes"

    (integer) 1
    >
    srem superpowers "
    reflexes"
    // 删除元素1

    >
    sismember superpowers "
    flight"
    // 测试元素是否在集合中
    (integer) 1
    >
    sismember superpowers "
    reflexes"

    (integer) 0
    >
    smembers superpowers // 返回集合中所有元素
    1) "
    x-ray vision"

    2) "
    flight"

    >
    sadd birdpowers "
    pecking"

    (integer) 1
    >
    sadd birdpowers "
    flight"

    (integer) 1
    >
    sunion superpowers birdpowers // 合并多个set&
    #xff0c;
    返回合并后的元素列表
    1) "
    x-ray vision"

    2) "
    flight"

    3) "
    pecking"

    >
    del superpowers // 删除key
    (integer) 1 当value是zset类型&
    #xff0c;
    命令包括 zadd zrange del等&
    #xff0c;
    注意给value一个编号用于排序。>
    zadd hacker 1940 "
    Alan Kay"
    // 给value指定一个编号&
    #xff0c;
    比如以年份1940作为编号
    (integer) 1
    >
    zadd hacker 1906 "
    Grace Hopper"

    (integer) 1
    >
    zadd hacker 1953 "
    Richard Stallman"

    (integer) 1
    >
    zadd hacker 1965 "
    Yukihiro Matsumoto"

    (integer) 1
    >
    zadd hacker 1916 "
    Claude Shannon"

    (integer) 1
    >
    zadd hacker 1969 "
    Linux Torvalds"

    (integer) 1
    >
    zadd hacker 1957 "
    Sophie Wilson"

    (integer) 1
    >
    zadd hacker 1912 "
    Alan Turing"

    (integer) 1

    >
    zrange hacker 2 4 // 切片返回有序集合中元素
    1) "
    Claude Shannon"

    2) "
    Alan Kay"

    3) "
    Richard Stallman"


    >
    del hacker // 删除key
    (integer) 1 当value是hash类型&
    #xff0c;
    hash类型可以理解为字典&
    #xff0c;
    需要给value指定一个field用于映射&
    #xff0c;
    命令包括hset hmset hget hgetall hdel hincrby del 等。>
    hset user:1000 name "
    John Smith"
    // 给value指定一个field&
    #xff0c;
    比如name
    (integer) 1
    >
    hset user:1000 email "
    john.smith@example.com"

    (integer) 1
    >
    hset user:1000 password "
    s3cret"

    (integer) 1
    >
    hgetall user:1000 // 获得hash表中所有成员&
    #xff0c;
    包括field和value
    1) "
    name"

    2) "
    John Smith"

    3) "
    email"

    4) "
    john.smith@example.com"

    5) "
    password"

    6) "
    s3cret"


    >
    hmset user:1001 name "
    Mary Jones"
    password "
    hidden"
    email
    "
    mjones@example.com"
    // 设置多个field和value
    OK
    >
    hget user:1001 name // 根据field获取value
    "
    Mary Jones"


    >
    hset user:1000 visits 10 // field可以映射到数字值
    (integer) 1
    >
    hincrby user:1000 visits 1 // 原子性增加value的值&
    #xff0c;
    增加1
    (integer) 11
    >
    hincrby user:1000 visits 10 // 增加10
    (integer) 21
    >
    hdel user:1000 visits // 删除field及其value
    (integer) 1
    >
    hincrby user:1000 visits 1
    (integer) 1

    >
    del user:1000 // 删除key
    (integer) 1 设置和查看key的生命周期&
    #xff0c;
    key过期会被自动删除&
    #xff0c;
    命令包括expire ttl 等。>
    set resource:lock "
    Redis Demo"

    OK
    >
    expire resource:lock 120 // 设置生命周期为120s
    (integer) 1
    >
    ttl resource:lock // 查看当前生命周期还剩多少时间
    (integer) 109
    >
    ttl resource:lock // 120s后查看&
    #xff0c;
    返回-2表示已过期或不存在
    (integer) -2

    >
    set resource:lock "
    Redis Demo 2"

    OK
    >
    ttl resource:lock // 返回-1表示永不过期
    (integer) -1 springboot实现h5与fastdfs之间的断点续传,大文件上传,秒传文件和批量上传 对比&
    #xff0c;
    只是单纯返回一个String类型&
    #xff1f;

    改为upload_list8888&
    #xff0c;
    页面调用是失败的

    改回upload_list

    ThreadLocal与redis秒配&
    #xff0c;
    解决了redis线程池在被共享访问时带来的线程安全问题

    打个比方&
    #xff0c;
    现在公司所有人都要填写一个表格&
    #xff0c;
    但是只有一支笔&
    #xff0c;
    这个时候就只能上个人用完了之后&
    #xff0c;
    下个人才可以使用&
    #xff0c;
    为了保证"
    笔"
    这个资源的可用性&
    #xff0c;
    只需要保证在接下来每个人的获取顺序就可以了&
    #xff0c;
    这就是 lock 的作用&
    #xff0c;
    当这支笔被别人用的时候&
    #xff0c;
    我就加 lock &
    #xff0c;
    你来了那就进入队列排队等待获取资源(非公平方式那就另外说了)&
    #xff0c;
    这支笔用完之后就释放 lock &
    #xff0c;
    然后按照顺序给下个人使用。

    搭建fastdfs与redis服务,实现高效数据存储与缓存

    但是完全可以一个人一支笔对不对&
    #xff0c;
    这样的话&
    #xff0c;
    你填写你的表格&
    #xff0c;
    我填写我的表格&
    #xff0c;
    咱俩谁都不耽搁谁。这就是 ThreadLocal 在做的事情&
    #xff0c;
    因为每个 Thread 都有一个副本&
    #xff0c;
    就不存在资源竞争&
    #xff0c;
    所以也就不需要加锁&
    #xff0c;
    这不就是拿空间去换了时间嘛&
    #xff01;

    了解决redis线程池对象&
    #xff08;
    笔&
    #xff09;
    &
    #xff0c;
    不能被多线程&
    #xff08;
    多个人&
    #xff09;
    共享访问的问题&
    #xff0c;
    通过 threadLocal.set() 方法&
    #xff0c;
    将redis线程池对象实例保存在每个线程&
    #xff0c;
    自己所拥有的 threadLocalMap中&
    #xff08;
    生成多个副本&
    #xff09;

    这样的话&
    #xff0c;
    每个线程都使用自己的redis线程池对象实例&
    #xff0c;
    彼此不会影响&
    #xff0c;
    从而达到了隔离的作用&
    #xff0c;
    这样就解决了redis线程池对象在被共享访问时带来的线程安全问题。

    import cn.hutool.core.util.StrUtil;

    import org.slf4j.Logger;

    import org.slf4j.LoggerFactory;

    import redis.clients.jedis.Jedis;

    import redis.clients.jedis.JedisPool;

    import redis.clients.jedis.JedisPoolConfig;


    import java.util.List;



    public class RedisUtil {

    private RedisUtil() {
    }
    private static Logger _logger = LoggerFactory.getLogger(RedisUtil.class);

    ;


    protected static final ThreadLocal<
    Jedis>
    threadLocalJedis = new ThreadLocal<
    Jedis>
    ();


    //Redis服务器IP
    private static String ADDR_ARRAY = ReadProper.getResourceValue("
    spring.redis.host"
    );


    //Redis的端口号
    private static int PORT = Integer.parseInt(ReadProper.getResourceValue("
    spring.redis.port"
    ));


    //访问密码
    private static String AUTH = ReadProper.getResourceValue("
    spring.redis.password"
    );


    //可用连接实例的最大数目&
    #xff0c;
    默认值为8&
    #xff1b;

    //如果赋值为-1&
    #xff0c;
    则表示不限制&
    #xff1b;
    如果pool已经分配了maxActive个jedis实例&
    #xff0c;
    则此时pool的状态为exhausted(耗尽)。
    private static int MAX_ACTIVE = -1;


    //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例&
    #xff0c;
    默认值也是8。
    private static int MAX_IDLE = 16;


    //等待可用连接的最大时间&
    #xff0c;
    单位毫秒&
    #xff0c;
    默认值为-1&
    #xff0c;
    表示永不超时。如果超过等待时间&
    #xff0c;
    则直接抛出JedisConnectionException&
    #xff1b;

    private static int MAX_WAIT = 1000 * 5;


    //超时时间
    private static int TIMEOUT = 1000 * 5;


    //在borrow一个jedis实例时&
    #xff0c;
    是否提前进行validate操作&
    #xff1b;
    如果为true&
    #xff0c;
    则得到的jedis实例均是可用的&
    #xff1b;

    private static boolean TEST_ON_BORROW = true;


    private static JedisPool jedisPool ;


    //默认的数据库为0



    /**
    * redis过期时间,以秒为单位
    */
    public final static int EXRP_HOUR = 60 * 60;
    //一小时
    public final static int EXRP_DAY = 60 * 60 * 24;
    //一天
    public final static int EXRP_MONTH = 60 * 60 * 24 * 30;
    //一个月





    /**
    * 初始化Redis连接池,注意一定要在使用前初始化一次,一般在项目启动时初始化就行了
    */
    public static JedisPool initialPool() {
    JedisPool jp=null;

    try {
    JedisPoolConfig config = new JedisPoolConfig();

    config.setMaxTotal(MAX_ACTIVE);

    config.setMaxIdle(MAX_IDLE);

    config.setMaxWaitMillis(MAX_WAIT);

    config.setTestOnBorrow(TEST_ON_BORROW);

    config.setTestOnCreate(true);

    config.setTestWhileIdle(true);

    config.setTestOnReturn(true);

    config.setNumTestsPerEvictionRun(-1);

    jp = new JedisPool(config, ADDR_ARRAY, PORT, TIMEOUT, AUTH);

    jedisPool=jp;

    threadLocalJedis.set(getJedis());

    } catch (Exception e) {
    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);


    }

    return jp;

    }



    public static void close(Jedis jedis) {
    if (threadLocalJedis.get() == null &
    &
    jedis != null){
    jedis.close();

    }
    }






    // /**
    // * 在多线程环境同步初始化
    // */
    // private static synchronized void poolInit() {
    // if (jedisPool == null) {
    // initialPool();

    // }
    // }


    /**
    * 获取Jedis实例,一定先初始化
    *
    * @return Jedis
    */
    public static Jedis getJedis() {
    boolean success = false;

    Jedis jedis = null;

    // if (jedisPool == null) {
    // poolInit();

    // }
    int i=0;

    while (!success) {
    i++;

    try {
    if (jedisPool != null) {
    jedis=threadLocalJedis.get();

    if (jedis==null){
    jedis = jedisPool.getResource();

    }else {
    if(! jedis.isConnected()&
    &
    !jedis.getClient().isBroken()){
    threadLocalJedis.set(null);

    jedis = jedisPool.getResource();

    }
    //System.out.println(Thread.currentThread().getName()+"
    :第"
    +i+"
    次获取成功#@利用了本地缓存redis"
    );

    return jedis;

    }

    }else {
    throw new RuntimeException("
    redis连接池初始化失败"
    );

    }
    } catch (Exception e) {

    System.out.println(Thread.currentThread().getName()+"
    :第"
    +i+"
    次获取失败!!!"
    );

    success = false;

    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);

    }
    if (jedis!=null){
    success=true;

    }

    if (i>
    =10&
    &
    i<
    20){
    try {
    Thread.sleep(1000);

    } catch (InterruptedException e) {
    e.printStackTrace();

    }

    }

    if (i>
    =20&
    &
    i<
    30){
    try {
    Thread.sleep(2000);

    } catch (InterruptedException e) {
    e.printStackTrace();

    }

    }

    if (i>
    =30&
    &
    i<
    40){
    try {
    Thread.sleep(3000);

    } catch (InterruptedException e) {
    e.printStackTrace();

    }

    }

    if (i>
    =40){
    System.out.println("
    redis彻底连不上了~~~~(>
    _<
    )~~~~"
    );

    return null;

    }

    }
    if (threadLocalJedis.get()==null){threadLocalJedis.set(jedis);
    }
    //System.out.println(Thread.currentThread().getName()+"
    :第"
    +i+"
    次获取成功@"
    );

    return jedis;

    }




    /**
    * 设置 String
    *
    * @param key
    * @param value
    */
    public static void setString(String key, String value) {
    Jedis jo = null;

    try {

    value = StrUtil.isBlank(value) ? "
    "
    : value;

    jo = getJedis();

    jo.set(key, value);

    } catch (Exception e) {
    threadLocalJedis.set(null);

    _logger.error("
    redis服务器异常"
    ,e);

    throw new RuntimeException("
    redis服务器异常"
    );

    } finally {
    if (jo != null) {
    close(jo);

    }

    }
    }

    /**
    * 设置 过期时间
    *
    * @param key
    * @param seconds 以秒为单位
    * @param value
    */
    public static void setString(String key, int seconds, String value) {
    Jedis jo = null;

    try {
    value = StrUtil.isBlank(value) ? "
    "
    : value;

    jo = getJedis();

    jo.setex(key, seconds, value);

    } catch (Exception e) {
    threadLocalJedis.set(null);

    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);

    throw new RuntimeException("
    redis服务器异常"
    );

    } finally {
    if (jo != null) {
    close(jo);


    }
    }


    }

    /**
    * 获取String值
    *
    * @param key
    * @return value
    */
    public static String getString(String key) {
    Jedis jo = null;


    try {
    jo = getJedis();


    if (jo == null || !jo.exists(key)) {
    return null;

    }
    return jo.get(key);

    } catch (Exception e) {
    threadLocalJedis.set(null);

    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);

    throw new RuntimeException("
    redis操作错误"
    );

    } finally {
    if (jo != null) {
    close(jo);

    }
    }


    }

    public static long incrBy(String key, long integer) {
    Jedis jo = null;

    try {
    jo = getJedis();


    return jo.incrBy(key, integer);

    } catch (Exception e) {
    threadLocalJedis.set(null);

    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);

    throw new RuntimeException("
    redis操作错误"
    );

    } finally {
    if (jo != null) {
    close(jo);

    }
    }

    }

    public static long decrBy(String key, long integer) {
    Jedis jo = null;

    try {
    jo = getJedis();

    return jo.decrBy(key, integer);

    } catch (Exception e) {
    threadLocalJedis.set(null);

    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);

    throw new RuntimeException("
    redis操作错误"
    );

    } finally {
    if (jo != null) {
    close(jo);

    }
    }

    }

    //删除多个key
    public static long delKeys(String [] keys){
    Jedis jo = null;

    try {
    jo = getJedis();

    return jo.del(keys);

    } catch (Exception e) {
    threadLocalJedis.set(null);

    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);

    throw new RuntimeException("
    redis操作错误"
    );

    } finally {
    if (jo != null) {
    close(jo);

    }
    }

    }

    //删除单个key
    public static long delKey(String key){
    Jedis jo = null;

    try {
    jo = getJedis();

    return jo.del(key);

    } catch (Exception e) {
    threadLocalJedis.set(null);

    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);

    throw new RuntimeException("
    redis操作错误"
    );

    } finally {
    if (jo != null) {
    close(jo);

    }
    }

    }

    //添加到队列尾
    public static long rpush(String key,String node){
    Jedis jo = null;

    try {
    jo = getJedis();

    return jo.rpush(key,node);

    } catch (Exception e) {
    threadLocalJedis.set(null);

    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);

    throw new RuntimeException("
    redis操作错误"
    );

    } finally {
    if (jo != null) {
    close(jo);

    }
    }

    }


    //删除list元素
    public static long delListNode(String key,int count,String value){
    Jedis jo = null;

    try {
    jo = getJedis();

    return jo.lrem(key,count,value);

    } catch (Exception e) {
    threadLocalJedis.set(null);

    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);

    throw new RuntimeException("
    redis操作错误"
    );

    } finally {
    if (jo != null) {
    close(jo);

    }
    }

    }




    //获取所有list

    public static List getListAll(String key){
    Jedis jo = null;

    List list=null;

    try {
    jo = getJedis();

    list= jo.lrange(key,0,-1);

    } catch (Exception e) {
    threadLocalJedis.set(null);

    e.printStackTrace();

    _logger.error("
    redis服务器异常"
    ,e);

    throw new RuntimeException("
    redis操作错误"
    );

    } finally {
    if (jo != null) {
    close(jo);

    }
    }
    return list;

    }

    //清理缓存redis
    public static void cleanLoacl(Jedis jo){
    threadLocalJedis.set(null);

    close(jo);

    }

    static {
    initialPool();

    }

    } 使用webuploader组件实现大文件分片上传&
    #xff0c;
    断点续传

    webuploader&
    #xff1a;
    是一个以HTML5为主&
    #xff0c;
    Flash为辅的文件上传组件&
    #xff0c;
    采用大文件分片/并发上传的方式&
    #xff0c;
    极大地提高了文件上传的效率&
    #xff0c;
    同时兼容多种浏览器版本&
    #xff1b;

    前端

    引入百度Webuploader组件&
    #xff0c;
    需要注意标签的id/nama属性&
    #xff0c;
    这些将在后面的JavaScript中使用到进行文件切分、验证。

    以上js组件&
    #xff0c;
    将完成文件上传、MD5验证、删除、切片、上传进度条显示、暂停、继续上传及上传成功/失败时候的回调。

    后端

    前端&
    #xff0c;
    给后端提供封装的chunk,及request

    后端&
    #xff0c;
    主要是判断文件是否有分片&
    #xff0c;
    如果没有&
    #xff0c;
    则直接存放到目的目录&
    #xff1b;

    如果存在分片&
    #xff0c;
    则创建临时目录&
    #xff0c;
    存放分片信息&
    #xff1b;

    之后判断当前分片所属的文件的所有分片是否已经传输完毕&
    #xff0c;
    如果当前分片数==所属文件总分片数&
    #xff0c;
    则开始合并文件并转移完整文件到目的目录&
    #xff0c;
    并且删除临时目录

    检测完文件&
    #xff0c;
    以后&
    #xff0c;
    开始上传操作

    //上传操作
    path = appendFileStorageClient.uploadAppenderFile(UpLoadConstant.DEFAULT_GROUP, file.getInputStream(),file.getSize(), FileUtil.extName((String) paramMap.get("
    name"
    )));

    //更新操作
    appendFileStorageClient.modifyFile(UpLoadConstant.DEFAULT_GROUP, noGroupPath, file.getInputStream(),file.getSize(),historyUpload);
    hutool工具的巧妙运用

    可参考hutool资料http://www.mianshigee.com/tutorial/hutool/26e24c7a37d93249.md

    <
    dependency>

    <
    groupId>
    cn.hutool<
    /groupId>

    <
    artifactId>
    hutool-all<
    /artifactId>

    <
    version>
    5.0.6<
    /version>

    <
    /dependency>
    cn.hutool.core.collection.CollUtil判断非空

    cn.hutool.json.JSONObject与JSONUtilif (CollUtil.isNotEmpty(fileList)){
    for (String e:fileList){
    JSONObject jsonObject= JSONUtil.parseObj(e);

    jsonObjects.add(jsonObject);


    }
    } cn.hutool.core.convert.Convert类型转换

    cn.hutool.core.util.RandomUtil生成随机字符串及StrUtil判断字符为空

    解析文件的扩展名&
    #xff0c;
    来获该文件的类型import cn.hutool.core.io.FileUtil;

    FileUtil.extName((String) paramMap.get("
    name"
    )));


    快速搭建FastDFS服务
    FastDFS是一个开源的轻量级分布式文件系统,适用于海量的图片、音视频等数据存储。可利用其快捷的文件分发机制,搭建高效且弹性的文件存储服务。
    首先,在服务器上安装FastDFS服务,并配置tracker和storage节点。通过配置nginx反向代理,可方便地将文件下载到客户端。最后,使用FastDFS提供的客户端工具即可上传和下载文件。
    单机Redis服务搭建
    Redis是一款高性能的key-value存储系统,主要用于缓存、队列、排行榜等应用场景!搭建单机Redis服务,可为业务系统提供高速的数据读取与缓存服务。
    通过向指定路径下载Redis安装包,解压后即可进行配置和启动服务。为提高Redis的并发处理能力,可在服务端启用多个线程。对于性能要求较高的业务场景,还需对Redis进行性能优化,如开启数据压缩等。
    综上所述,通过搭建FastDFS与Redis服务,可轻松实现高效数据存储和管理。当然,在实际应用中还需结合具体业务需求和系统架构来不断地优化和调整。希望这些方法对您的技术建设和业务创新提供帮助。