docker

一、docker的安装

在centos7.5的虚拟机中安装命令

 yum install docker      

docker的启动和关闭,重启,及状态查询

systemctl status/start/stop/restart docker

查看版本

 docker -v

查看信息

docker -info

设置开机自启动docker

   systemctl enable docker

查看docker的开机自启动的状态

  systemctl list-unit-files | grep docker
二、 镜像
      展示所有的镜像
 docker images
   **从网上拉镜像**
   docker pull hello-world
**删除镜像**
docker rmi (端口号imageid)

镜像加速

$ docker pull registry.docker-cn.com/library/centos:7(版本这个自选)

为了永久性保留更改,您可以修改 /etc/docker/daemon.json 文件并添加上 registry-mirrors 键值。

{
  "registry-mirrors": ["https://registry.docker-cn.com"]
}

这个不好用可以访问这个地址

https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
比这个快多啦
修改保存后重启 Docker 以使配置生效。

查找镜像

docker  search 镜像名称

当出现一台机器能上网,一台机器不能上网,导入导出镜像

cd /home

在那个目录就会导入那个目录,导出到啦home文件夹下

docker save -o tomcat.tar docker.io/tomcat:7-jre7

拷贝到另一台机器上,取另一台机器的ip

scp ./tomcat.tar root@192.168.64.131:/home

在没有镜像的机器上可以使用tomcat.tar 镜像的压缩包执行如下命令安装镜像

docker load -i tomcat.tar 
三、容器

查看docker所运行的容器

   docker ps -a

通过镜像安装交互容器

   docker run -i -t --name mycentos centos:7 /bin/bash

退出 exit
通过镜像安装守护式容器

 docker run -i -d --name mycentos1 centos:7

进入容器

docker exec -i -t mycentos1 /bin/bash

使用退出exit 但是容器并没有退出,真正的关闭要写

  docker stop mycentos1

开启容器
docker start 容器名称/container id

docker exec -i -t mycentos1 /bin/bash

删除容器

 docker rm  mycentos

删除所有的容器(注意不是rmi,加i就是删除镜像)

 docker rm `docker ps -a`

这个也行

docker rm `docker ps -a -q`

拷贝
将宿主机中的文件传到容器为mycentos1的home文件夹下

   docker cp 1.txt mycentos1:/home

将mycentos容器中的Hi.txt拷贝到宿主机的home文件夹下

   docker cp mycentos:/home/Hi.txt /home

共享

   docker run -di -v /home/a:/home/ --name =mycentos2 --privileged=true centos:7

一台机器能上网,一台机器不能上网如何在不能联网的机器怎么使用镜像?
在有镜像的机器上做如下操作

   cd  /home

把镜像导出到home文件夹下

   docker save -o tomcat.tar docker.io/tomcat:7-jre7

操作之后在,home文件夹下就会出现 tomcat.tar文件做如下操作
不能联网机器的ip

   scp ./tomcat.tar root@192.168.15.39:/home

在新机器上做如下操作

cd /home

导入镜像

docker load -i tomcat.tar

创建tomcat容器

docker run -i -d --name mytomcat1  -p 8081:8080 镜像的imageid
四、MySQL

安装mysql镜像

   docker pull mysql

安装mysql的容器

   docker run -di --name mysql_easybuy -p 3307:3306 -e MYSQL_ROOT_PASSWORD=root mysql

注意这样写window下的mysql访问的端口号是3307
进入到mysql的容器中

docker exec -i -t mysql_easybuy /bin/bash

如果进入到mysql中发现出现中文?则使用下列命令进入

docker exec -it mysql_test env LANG=C.UTF-8 bash

进入到mysql里

mysql -u root -p

默认没有放开root的远程登录权限权限 要放开,执行下列代码,否则链接报错

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';

链接window下的数据库

在这里插入图片描述

察看ip(要退出mysql再察看)
内容较多

   docker inspect mysql_easybuy;

只察看ip地址

docker inspect --format='{{.NetworkSettings.IPAddress}}' mysql_easybuy;
五、Tomcat

一、安装tomcat
第一种

 docker install tomcat

第二种:详情看容器版本末尾

二、创建tomcat容器
window下访问8080

docker run -i -d --name mytomcat1  -p 8081:8080 镜像的imageid

三、问题解决如果出现404
使用docker exec -it b6a955c3cbea /bin/bash命令进入tomcat目录,查看目录信息:
发现webapps为空,tomcat的默认项目资源都在webapps.dist文件夹下
将webapps删除,将webapps.dist重命名为webapps

docker exec -it b6a955c3cbea /bin/bash
rm -rf webaps
mv webapps.dist/ webapps

四、一个镜像产生多个容器问题

1)首先产生三个tomcat容器

docker run -i -d --name mytomcat1 -p 8081:8080 f43f44c16fb0
docker run -i -d --name mytomcat2 -p 8082:8080 f43f44c16fb0
docker run -i -d --name mytomcat3 -p 8083:8080 f43f44c16fb0

(2)察看tomcat的容器的ip地址

   docker inspect mytomcat1 |grep IPAddress

发现ip地址按启动顺序自动递增分配
如果想自定义分配需要创建定义网络
****(1)这个老师视频有问题得问

六、如何利用docker在linux上部署项目

修改database.配置文件的ip地址

1.首先进入到mysql的容器当中查看mysql的对应的id地址

docker exec -i -t mysql_easybuy /bin/bash
docker inspect --format='{{.NetworkSettings.IPAddress}}' mysql_easybuy;

2.在war包中修改WEB-INF下的classes文件下的database.properties文件夹下的url 地址使用的是mysql的ip地址,端口号使用的是创建mysql的容器时指定的端口号

在这里插入图片描述
3.将war包导入到linux中的home文件夹下面,再移动到tomcat容器中的webapps文件夹下面

  rz
docker cp /home/EasyBuy.war  mytomcat1:/usr/local/tomcat/webapps

4.将对应项目的sql文件,上传到home文件夹下面,再将文件通过命令转入到mysql的容器中的home文件夹下面

rz
docker cp /home/easybuy.sql mysql_easybuy:/home

5.在mysql的容器中首先,创建一个同名数据库,再通过命令将容器中的home文件夹使用

   create database easybuy

注意在mysql的文件夹下使用

mysql> source /home/easybuy.sql;

6.在浏览器中访问改linux的ip地址tomcat的端口号+项目名称即可
在这里插入图片描述

七、 docker 下面的redis的使用

拉取redis的镜像

 docker pull redis

创建redis的容器

docker run -i -d --name redis -p 6379:6379 redis

进入到redis容器中

docker exec -i -t redis /bin/bash

在redis容器中查看redis的默认IP地址和端口号以及进入到redis的客户端上

redis-cli

在redis的客户端上测试redis是否启动

   127.0.0.1:6379> ping

在客户端中使用set,get等基础语法

  set name  jss
  get name

在idea中使用redis Nosql技术创建项目步骤

1.创建Spring Initializr 选择Web下面的SpirngWebNoSQL下面的 Spring Data Redis(Access+Driver)

2.在application.propertites的配置文件中进行如下的配置

spring.redis.host= 192.168.64.132
spring.redis.port = 6379

**3.在测试类中进行操作使java代码链接redis缓存 **

package com.hdax.redis02;

import com.hdax.redis02.entity.User;
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;

import java.util.*;

@SpringBootTest
class Redis02ApplicationTests {




    //redisTemplate可以操作所有的数据类型 list/set/ String
    @Autowired
    private RedisTemplate redisTemplate;


    @Test
    public void setFunction(){
        redisTemplate.opsForValue().set("sex","女");

    }

    @Test
    public void getFunction(){
        String sex = (String)redisTemplate.opsForValue().get("sex");
        System.out.println(sex);
    }
    @Test
    public void setObject(){
      User user =new User();
      user.setId(12);
      user.setName("jss");
        //想redis服务器存放对象的时,默认使用的jdk的序列化器
      redisTemplate.opsForValue().set("u",user);
    }

    @Test
    public void getObject(){

        User u = (User)redisTemplate.opsForValue().get("u");
        System.out.println(u.getId()+"--"+u.getName());
      /*  Object user = redisTemplate.opsForValue().get("u");
        User t = (User) JSON.toJavaObject((JSON) user, User.class);
        System.out.println(t.getId() + " -- " + t.getName());*/
    }

     @Test
     public void testHasKey(){
         Boolean flag = redisTemplate.hasKey("u");
         System.err.println(flag);
     }

     @Test
     public void testOBjectList(){
        User user =new User();
        user.setName("zs");
        user.setId(1);

         User user1 =new User();
         user1.setName("zs");
         user1.setId(1);

         List<User> list =new ArrayList<>();
         list.add(user);
         list.add(user1);

         redisTemplate.opsForValue().set("ulist",list);
     }

     @Test
     public void testGetObjectList(){
         List<User> list = (List<User>)redisTemplate.opsForValue().get("ulist");
         for(User u:list){
             System.out.println(u.getId()+"---"+u.getName());
         }


     }


    @Test
    //如果出现不能转换为user对象的时候要使用这中形式
    public void testGetObject1(){

        LinkedHashMap t = (LinkedHashMap) redisTemplate.opsForValue().get("user") ;

        Set<Map.Entry<String,Object>> set = t.entrySet() ;

        for(Map.Entry entry :set){
            System.out.println(entry.getKey() + " -- " + entry.getValue());
        }

    }

    @Test
    void contextLoads() {
    }

}

(4)也有专用的处理字符串的对象stringRedisTemplated

/**
 * Copyright (C), 2020, Y2 T205
 * FileName: StringRedisTemplateTest
 * Author: Lenovo
 * Date: 2020-04-22 17:50
 * Description:
 * History:
 * <author> <time> <version> <desc>
 * 作者姓名 修改时间 版本号 描述
 */


package com.hdax.redis02;



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.StringRedisTemplate;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author Lenovo
 * @create 2020-04-22
 * @since 1.0.0
 */
@SpringBootTest
public class StringRedisTemplateTest {

    //这个对象可防止在存入string类型的值时,在redis desktop manager 中乱码的情况,但不能对对象进行操作
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Test
    public void testSetString(){
        stringRedisTemplate.opsForValue().set("lastname","姬少帅");
    }

    @Test
    public void testGetString(){
        String lastname = stringRedisTemplate.opsForValue().get("lastname");
        System.err.println("我的名字时"+lastname);
    }

}

(5)重写redistemplate对象,好处是<Object,Object>转化为<Stirng,Object>减少类型转换的操作,Object ->json,两种手段使用fastjson和自带的springboot自带的jackson,这回使用jackson在项目中引入RedisConfig类

package com.hdax.redis02.config;

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

/**
 * redis配置类
 */
@Configuration
@EnableCaching //开启注解
public class RedisConfig extends CachingConfigurerSupport {
    /**
     * retemplate相关配置
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(factory);

        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
       // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        jacksonSeial.setObjectMapper(om);

        // 值采用json序列化
        template.setValueSerializer(jacksonSeial);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());

        // 设置hash key 和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSeial);
        template.afterPropertiesSet();

        return template;
    }

    /**
     * 对hash类型的数据操作
     *
     * @param redisTemplate
     * @return
     */
    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }

    /**
     * 对redis字符串类型数据操作
     *
     * @param redisTemplate
     * @return
     */
    @Bean
    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForValue();
    }

    /**
     * 对链表类型的数据操作
     *
     * @param redisTemplate
     * @return
     */
    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }

    /**
     * 对无序集合类型的数据操作
     *
     * @param redisTemplate
     * @return
     */
    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }

    /**
     * 对有序集合类型的数据操作
     *
     * @param redisTemplate
     * @return
     */
    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }

}

(6)封装redistemplate的操作

创建一个util包下面的

package com.hdax.redis02.util;
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.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * redisTemplate封装
 *
 *  @author david
 */
@Component
public class RedisUtil {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 指定缓存失效时间
     * @param key 键
     * @param time 时间(秒)
     * @return
     */
    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 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    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;
        }
    }

    /**
     * 删除缓存
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String ... key){
        if(key!=null&&key.length>0){
            if(key.length==1){
                redisTemplate.delete(key[0]);
            }else{
                redisTemplate.delete(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 如果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 要增加几(大于0)
     * @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 要减少几(小于0)
     * @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 键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key,String item){
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取hashKey对应的所有键值
     * @param key 键
     * @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<String,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<String,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 键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item){
        redisTemplate.opsForHash().delete(key,item);
    }

    /**
     * 判断hash表中是否有该项的值
     * @param key 键 不能为null
     * @param item 项 不能为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 要减少记(小于0)
     * @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;
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     * @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 sSetAndTime(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;
        }
    }

    /**
     * 移除值为value的
     * @param key 键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object ...values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } 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;
        }
    }

    /**
     * 通过索引 获取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;
        }
    }

    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @param time 时间(秒)
     * @return
     */
    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;
        }
    }

    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @param time 时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     * @param key 键
     * @param index 索引
     * @param value 值
     * @return
     */
    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;
        }
    }

    /**
     * 移除N个值为value
     * @param key 键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key,long count,Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

}

测试类

/**
 * Copyright (C), 2020, Y2 T205
 * FileName: RedisUtilTest
 * Author: Lenovo
 * Date: 2020-04-22 20:16
 * Description:
 * History:
 * <author> <time> <version> <desc>
 * 作者姓名 修改时间 版本号 描述
 */


package com.hdax.redis02;


import com.hdax.redis02.util.RedisUtil;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author Lenovo
 * @create 2020-04-22
 * @since 1.0.0
 */
@SpringBootTest
public class RedisUtilTest {

    @Autowired
    private RedisUtil redisUtil;
@Test
    public void testhaskey(){
        boolean flag = redisUtil.hasKey("sex");
        System.out.println(flag);
    }

}
八、 redis gui 可视化界面 partainer

(1)安装docker中的protainer镜像


docker pull docker.io/portainer/portainer

(2)配置加速器

vi /etc/docker/daemon.json 

“hosts”: [“tcp://127.0.0.1:2375”, “unix:///var/run/docker.sock”]
在这里插入图片描述
(3)重启docker服务

systemctl restart docker

(4)创建容器

docker volume create partiner_db

(5)进入容器
docker run -d -p 9000:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --name portainer --privileged=true docker.io/portainer/portainer

(6)浏览器访问
192.168.64.132:9000/

账号:admin
密码:12345678
在这里插入图片描述

九、 elasticsearch的安装与使用

1.搜索镜像

  docker search elasticsearch

2.拉取镜像
这个版本要依据创建springboot项目中的依赖所决定的版本要一致
在这里插入图片描述

docker pull elasticsearch:6.8.7

3.因为需要的内存和资源多,所以要重新设置虚拟机的cpu核心和内存
在这里插入图片描述
在这里插入图片描述
分配内存太小,需要将vm.max_map_count的值调大,网上查资料,得知用命令的方式来设置vm.max_map_count,命令如下:

sysctl -w vm.max_map_count=262144

查看vm.max_map_count命令:

sysctl -a|grep vm.max_map_count

但是以上方法在重启虚拟机之后就不生效,如果想要一直生效的话,到 /etc目录下编辑sysctl.conf文件,添加vm.max_map_count=262144就可以了

vi /etc/sysctl.conf 

在这里插入图片描述
保存文件之后用sysctl -a|grep vm.max_map_count命令查看,显示的还是修改之前的值,此时需要重启虚拟机才能生效

4 安装elasticsearch容器

  docker run -d --name=elasticsearch -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -p 9200:9200 -p 9300:9300 9cdc9986c313

5 访问地址

http://192.168.64.132:9200/

6 文档
/{index}/{type}/{id}
每个属性相当于
index: mysql
type:mysql中的表
id: 相当于表的主键

7.放入一个文档
使用postman软件 (红色字体的text可以换成json)
(1)使用id号,使用put请求

在这里插入图片描述
(2)不使用id号添加,用post请求
在这里插入图片描述

8.取出一个文档
(1)加上一个pretty参数使出来的数据更方便可读

在这里插入图片描述
(2)source参数使的打印出源码
在这里插入图片描述
(3)检查文档是否存在
如果只想检查一个文档是否存在–根本不想关心内容—​那么用 HEAD 方法来代替 GET 方法。 HEAD 请求没有返回体,只返回一个 HTTP 请求报头:

curl -i -XHEAD http://localhost:9200/website/blog/123

(4)更新文档
在这里插入图片描述

(5)创建新文档
第二种方法是在 URL 末端使用 /_create :

PUT /website/blog/123/_create
{ … }
如果创建新文档的请求成功执行,Elasticsearch 会返回元数据和一个 201 Created 的 HTTP 响应码。
在这里插入图片描述
(6)删除文档
在这里插入图片描述
(7)java代码与elasticsearch项目的整合
1.创建一个springboot的web项目,首先在pom.xml中加入elasticsearch的依赖

  <!--加入elasticsearch的依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
  

2.application.yml的配置

server.port=8082
#spring.elasticsearch.jest.uris=http://192.168.15.15:9200
#spring.data.elasticsearch.cluster-name=elasticsearch
#spring.data.elasticsearch.cluster-nodes=192.168.15.15:9300
#spring.elasticsearch.rest.uris=http://192.168.15.15:9200
spring.data.elasticsearch.cluster-name=docker-cluster
spring.data.elasticsearch.cluster-nodes=192.168.64.132:9300

3.创建一个bean下面的Book实体类 **注意使用注解@Document
**

/**
 * Copyright (C), 2020, Y2 T205
 * FileName: Book
 * Author: Lenovo
 * Date: 2020-04-27 16:53
 * Description:
 * History:
 * <author> <time> <version> <desc>
 * 作者姓名 修改时间 版本号 描述
 */


package com.hdax.springbootandelasticsearch.bean;


import org.springframework.data.elasticsearch.annotations.Document;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author Lenovo
 * @create 2020-04-27
 * @since 1.0.0
 */
@Document(indexName ="hdax",type ="book")
public class Book {

    private Integer id;
    private String bookName;
    private String author;

    public Book() {
    }

    public Book(Integer id, String bookName, String author) {
        this.id = id;
        this.bookName = bookName;
        this.author = author;
    }


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}
  1. 创建repository包,在下面创建BookRepository的接口
/**
 * Copyright (C), 2020, Y2 T205
 * FileName: BookRespository
 * Author: Lenovo
 * Date: 2020-04-27 16:57
 * Description:
 * History:
 * <author> <time> <version> <desc>
 * 作者姓名 修改时间 版本号 描述
 */


package com.hdax.springbootandelasticsearch.Repository;


import com.hdax.springbootandelasticsearch.bean.Book;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author Lenovo
 * @create 2020-04-27
 * @since 1.0.0
 */

public interface BookRespository extends ElasticsearchRepository<Book,Integer> {

       //public List<Book> findByBookNameLike(String bookName);

}

5、测试类

package com.hdax.springbootandelasticsearch;

import com.hdax.springbootandelasticsearch.Repository.BookRespository;
import com.hdax.springbootandelasticsearch.bean.Book;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
class SpringbootandelasticsearchApplicationTests {

    @Test
    void contextLoads() {
    }

    @Resource
    private BookRespository bookRespository;

    @Test
    public void test1(){
        Book b=new Book();
        b.setId(1);
        b.setAuthor("jss");
        b.setBookName("dsafd");

        bookRespository.save(b);
    }

}

6.在postman中访问,得到数据 如果访问第二个加入的数据,把1改为2
在这里插入图片描述

十 、 kibana的安装与使用
  1. 安装(注意版本要和elasticsearch的版本保持一致)
   docker pull kibana:6.8.7

2 创建容器

docker run --link elasticsearch:elasticsearch -d --name kibana -p 5601:5601  kibana:6.8.7

3 浏览器访问 http://192.168.64.132:5601/
4.在Dev Tools 模块中写
GET /hdax/book/1/_source
GET /hdax/book/2/_source

就可以得到相应的数据

获取所有数据:

GET /_search

创建数据

PUT /ecommerce/product/1
{
    "name" : "gaolujie yagao",
    "desc" :  "gaoxiao meibai",
    "price" :  30,
    "producer" :      "gaolujie producer",
    "tags": [ "meibai", "fangzhu" ]
}
PUT /ecommerce/product/2
{
    "name" : "jiajieshi yagao",
    "desc" :  "youxiao fangzhu",
    "price" :  25,
    "producer" :      "jiajieshi producer",
    "tags": [ "fangzhu" ]
}
PUT /ecommerce/product/3
{
    "name" : "zhonghua yagao",
    "desc" :  "caoben zhiwu",
    "price" :  40,
    "producer" :      "zhonghua producer",
    "tags": [ "qingxin" ]
}

进行crud
#2.查询

GET /ecommerce/product/2

#3.覆盖,替换文档(全量替换)

PUT /ecommerce/product/1
{
  "name" : "jiaqiangban gaolujie yagao",
  "desc" : "gaoxiao meibai",
  "price" : 30,
  "producer" : "gaolujie producer",
  "tags" : [ "meibai" , "fangzhu" ]
}

注意:1.document是不可变的,如果要修改document的内容,可以通过全量替换,直接对document
  重新建立索引,替换里面所有的内容。
   2.es会将老的document标记为deleted(逻辑删除),然后新增我们给定的一个document,当我们
  创建越来越多的document的时候,es会在适当的时机在后台自动删除(物理删除)标记为deleted
  的document。
   3.替换必须带上所有的field,否则其他数据会丢失。
#4.修改(更新文档)

POST /ecommerce/product/1/_update
{
  "doc" : {
    "name" : "jiaqianban gaolujie yagao1"
  }
}

#5.删除文档

DELETE /ecommerce/product/2

注意:在删除一个document之后,我们可以从侧面证明,它不是立即物理删除的,因为它的一些版本号信息还是保留的
#6.使用query DSL 请求查询

GET /ecommerce/product/_search
{
  "query" : {
    "match_all" : {}
  }
}

#6.1查询名称包含yaogao的商品,同时按照价格降序排列
这里刚开始可能报错说需要把fileddata设置为true,解决方案如下 注意这个price是要进行分组的字段

PUT /ecommerce/_mapping/product
{
 "properties": {
     "price":{
        "type": "text",
        "fielddata": true
      }
  }
}
GET /ecommerce/product/_search
{
  "query" : {
    "match" : {
      "name" : "yagao"
    }
  },
  "sort" : [
    { "price" : "desc"}
    ]
}

#6.2分页查询
#总共3条商品,假设每页就显示1条商品,现在显示第2页,所以就查出来第2个商品

GET /ecommerce/product/_search
{
  "query" : { "match_all" : {}},
  "from" : 1,
  "size" : 1
}

#6.3指定查询项

GET /ecommerce/product/_search
{
  "query" : {"match_all" : {}},
  "_source" : ["name", "price"]
}

#6.4过滤查询
#搜索商品名称包含yaogao,而且售价大于25元的商品

GET /ecommerce/product/_search
{
  "query" : {
    "bool" : {
      "must" : {
        "match" : {
          "name" : "yagao"
      }
  },
  "filter" : {
    "range" : {
      "price": {"gt" : 25}
        }
      }
    }
  }
}

#7.ull-text search(全文检索)

GET /ecommerce/product/_search
{
  "query" : {
    "match" : {
      "producer": "yagao producer"
    }
  }
}

#8.phrase search(短语搜索)

GET /ecommerce/product/_search
{
  "query" : {
    "match_phrase" : {
      "producer" : "yagao producer"
    }
  }
}

#9.多条件查询
#名字中有"yagao",描述上可以有fangzhu也可以没有,价格不能是25元

GET /ecommerce/_search
{
  "query" : {
    "bool" : {
      "must" : [
        {
          "match" : {
            "name" : "yagao"
          }
        }
        ],
        "should" : [
          {
            "match" : {
              "desc" : "fangzhu"
            }
          },
          {
            "match" : {
              "desc" : "caoben"
            }
          }
          ],
          "must_not" : [
            {
              "match" : {
                "price" :25
              }
            }
          ],
          "minimum_should_match" : 1
    }
  }
}

在以上的实例中:

从第六条开始需要做出的补充:

两种请求分类:query string search / query DSL

第一种:类似搜索全部商品: GET /ecommerce/product/_search (参数直接拼接在请求上,不带json参数的)

query string search的由来,因为search参数都是以http请求的query string来附带的。

搜索商品名称中包含yagao的商品,而且按照售价降序排列:

GET /ecommerce/product/_search?q=name:yagao&sort=price:desc

适用于临时的在命令行使用一些工具,比如curl,快速的发出请求,来检索想要的信息;但是

如果查询请求很复杂,是很难去构建的,所以在生产环境中,几乎很少使用query string search。

第二种:DSL:Domain Specified Language,特定领域的语言

http request body:请求体,可以用json的格式来构建查询语法,比较方便,可以构建各种复杂的语法,

比query string search肯定强大太多了。

full-text search 全文检索)和 phrase search(短语搜索)的区别:

全文检索:会将输入的搜索串拆解开来,去索引里面去一一匹配,只要能匹配任意一个拆解后的单词,就可以作为结果返回。

phrase search: 要求输入的搜索串,必须在指定的字段文本中,完全包含一模一样的,才可以算匹配成功,才能作为结果返回。

多条件查询中的字段描述:

must:  表示一定要满足;

should:  表示可以满足也可以不满足;

must_not:  表示不能满足该条件;

minimum_should_match:1 :表示最小匹配度,可以设置为百分之百,设置了这个值的时候就必须满足should里面的设置了,

另外注意这边should里面同一字段设置的多个值,意思是当这个值等于X或者等于Y都成立,务必注意格式。

十一、Rabbitmq的安装与使用
1.安装镜像
 docker pull rabbitmq:3.6-management
2.创建容器
docker run -i -d -p 5672:5672 -p 15672:15672 --name myr1 9df8e9792ce6

服务器是5672 管理页面时15672

3.在浏览器中访问

http://192.168.64.132:15672/
账号 guest 密码 guest

4.新建队列

在这里插入图片描述

5.创建交换机
创建交换机的四种方式以及区别
第一种,以direct的方式创建,规则是“先匹配,在投送”,即在绑定的时候设置一个routing key,消息的routing_key 匹配是,才会被交换器投送到绑定的队列中,在绑定队列的时候需要在routingkey中写值 就是点对点,发送到对应的一个队列一次,相应的队列接受一次

在这里插入图片描述
绑定队列
在这里插入图片描述
通过转换器发送消息
在这里插入图片描述

第二种,Fanout 转发消息到所有绑定的队列中去,这个就是在绑定队列的时候不用填写routingkey的值,发送一次,绑定的所有的队列都会接受,不用重复发送

在这里插入图片描述

第三种,topic创建 按照规则转发消息也就是routingkey中可以写*或者.来表示相应的字段

绑定队列
在这里插入图片描述
在这里插入图片描述

  • *代表任意一个词
  • #代表任意多个词

发送消息
在这里插入图片描述

在这里插入图片描述

第四种,Headers的创建,设置header attribute 参数类型的交换机
6.使用java代码控制mq
第一种,使用的交换器的类型是direct

(1)创建springboot的空项目 (rabbitmq)这个是发消息的项目
(2)引入依赖

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

(3)创建配置文件application.properties

spring.rabbitmq.host = 192.168.64.132
spring.rabbitmq.username = guest
spring.rabbitmq.password= guest

(4)测试类中写

package com.hdaccp.rabbitmq;

import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;
import java.util.Map;

@SpringBootTest
class RabbitmqApplicationTests {
@Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    void contextLoads() {
    }

    @Test
    public void send(){
        Map<String,Object> map =new HashMap<>();
        map.put("msg","第一个消息");
        rabbitTemplate.convertAndSend("c1","q3",map);
    }

}

(5)重复123步骤再创建一个springboot项目(rabbitmq2) 接受消息 ,注意接受消息后队列中的消息信息会被消耗
(6)测试类中的写法

       package com.hdaccp.rabbitmq2;

import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Map;

@SpringBootTest
class Rabbitmq2ApplicationTests {
    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Test
    void contextLoads() {
    }

    @Test
    public void receive(){
        Object q3 = rabbitTemplate.receiveAndConvert("q3");
        Map<String,Object> map =(Map<String,Object>) q3;
        System.out.println(map.get("msg"));
    }

}
7.如果需要让发送的信息在,rabbitmq客户端上显示的是中文,需要进行以下配置

(1)在项目的依赖中添加web依赖,因为其中包含jackson的依赖

   <!--如果想要在rabbitmq的控制器中队列显示的消息不是java序列化的乱码,而是json的形式,需要使用jkson的,而json在web的依赖里面-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

(2) 创建一个配置文件类,将转换模式转化为jackson的转化模式

/**
 * Copyright (C), 2020, Y2 T205
 * FileName: JsonConfig
 * Author: Lenovo
 * Date: 2020-04-30 9:46
 * Description:
 * History:
 * <author> <time> <version> <desc>
 * 作者姓名 修改时间 版本号 描述
 */


package com.hdaccp.rabbitmq.config;



import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author Lenovo
 * @create 2020-04-30
 * @since 1.0.0
 */
@Configuration
public class JsonConfig {

    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }

}

(3)执行相应的发送代码,会在客户端中显示成json的格式

在这里插入图片描述

8 信息监听器 让信息发过来就能被监听或者接受到

(1)在发送的项目(rabbitmq)中把,config的那个文件注释掉 @configuration @bean,不注释,就会因为转换问题报错
(2) 在接受的项目中(rabbitmq2)依赖中添加web依赖,引入jackson

 <!--如果想要在rabbitmq的控制器中队列显示的消息不是java序列化的乱码,而是json的形式,需要使用jkson的,而json在web的依赖里面-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

(3)在项目中启动类中添加注解

package com.hdaccp.rabbitmq2;

import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableRabbit
@SpringBootApplication
public class Rabbitmq2Application {

    public static void main(String[] args) {
        SpringApplication.run(Rabbitmq2Application.class, args);
    }

}

(4)建立一个service包下的myservice类

/**
 * Copyright (C), 2020, Y2 T205
 * FileName: MyService
 * Author: Lenovo
 * Date: 2020-04-30 10:04
 * Description:
 * History:
 * <author> <time> <version> <desc>
 * 作者姓名 修改时间 版本号 描述
 */


package com.hdaccp.rabbitmq2.service;


import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

import java.util.HashMap;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author Lenovo
 * @create 2020-04-30
 * @since 1.0.0
 */
@Service
public class MyService {

    @RabbitListener(queues = "q3")
    public void receive(HashMap<String,Object> map){
        System.out.println(map.get("msg")+"---");
    }

}

     

(5)运行接受项目可以监听传递过来的数据信息

第二种,使用的交换器的类型是Fanout

(1)在发送的测试类中写

  @Test
public void sendFanout(){
    Map<String,Object> map =new HashMap<>();
    map.put("msg","第一个消息");
    rabbitTemplate.convertAndSend("c2",null,map);
}

(2) 在接受的myservice这个类中添加监听

@RabbitListener(queues = "q2")
public void receiveQ2(HashMap<String,Object> map){
    System.out.println(map.get("msg")+"---");
}
@RabbitListener(queues = "q1")
public void receiveQ1(HashMap<String,Object> map){
    System.out.println(map.get("msg")+"---");
}    

(3)启动接受的信息的项目启动监听

第三种,使用的交换器的类型是topic的

(1)在发送的测试类中写

@Test
public void sendTopic(){
    Map<String,Object> map =new HashMap<>();
    map.put("msg","发送topic的消息");
    rabbitTemplate.convertAndSend("c3","q1.adsfa.adsfa",map);
    rabbitTemplate.convertAndSend("c3","x.q2",map);
}
9. 发送对象
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐