java操作RabbitMQ

2023-11-19

文章目录


RabbitMQ提供了6种消息模型,但是第6种其实是RPC,并不是MQ,那么也就剩下5种。
但是其实3、4、5这三种都属于订阅模型,只不过进行路由的方式不同。
在这里插入图片描述

一、基本消息模型

在这里插入图片描述

1.导入依赖
<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <!--和springboot2.0.5对应-->
    <version>5.4.1</version>
</dependency>
2.准备连接工具类
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class ConnectionUtil {
    /**
     * 建立与RabbitMQ的连接
     * @return
     * @throws Exception
     */
    public static Connection getConnection() throws Exception {
        //定义连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        //设置服务地址
        factory.setHost("127.0.0.1");
        //端口
        factory.setPort(5672);
        //设置账号信息,用户名、密码、vhost
        //Virtual代表虚拟消息服务器,每个服务器相对独立
        factory.setVirtualHost("/");
        factory.setUsername("guest");
        factory.setPassword("guest");
        // 通过工程获取连接
        Connection connection = factory.newConnection();
        return connection;
    }
}
3.创建消息发送者(生产者)
import com.ty.util.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class SenTest {

    //队列的名字
    private static final String QUEUE_HELLO = "queue_hello";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = null;
        Channel channel = null;
        try{
            //1.创建链接对象
            connection = ConnectionUtil.getConnection();

            //2.创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
            channel = connection.createChannel();

            /**
             *3. 声明队列,如果Rabbit中没有此队列将自动创建
             * param1:队列名称
             * param2:是否持久化
             * param3:队列是否独占此连接
             * param4:队列不再使用时是否自动删除此队列
             * param5:队列参数
             */
            channel.queueDeclare(QUEUE_HELLO, true, false, false, null);
            
            /**
             * 4.消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息包含的属性
             * param4:消息体
             * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显
             示绑定或解除绑定
             * 默认的交换机,routingKey等于队列名称
             */
            channel.basicPublish("", QUEUE_HELLO ,null ,"我是一个hello消息".getBytes());
            System.out.println("已经发送消息:我是一个hello消息");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(channel != null){
                try {
                    channel.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

启动后管理工具查看 http://localhost:15672/
在这里插入图片描述

点击队列名称,进入详情页,可以查看消息
在这里插入图片描述

4.创建消息接受者(消费者)
import com.rabbitmq.client.*;
import com.ty.util.ConnectionUtil;

import java.io.IOException;

public class RevTest {
    //队列的名字
    private static final String QUEUE_HELLO = "queue_hello";

    public static void main(String[] args) {
        try {
            //1.创建链接
            Connection connection = ConnectionUtil.getConnection();

            //2.创建通道
            Channel channel = connection.createChannel();

            //3.声明队列
            channel.queueDeclare(QUEUE_HELLO, true, false, false, null);

            //4.定义消费方法
            Consumer consumer = new DefaultConsumer(channel){
                /**
                 * 消费者接收消息调用此方法
                 * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
                 * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
                (收到消息失败后是否需要重新发送)
                 * @param properties
                 * @param body
                 */
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)throws IOException {
                    //交换机
                    String exchange = envelope.getExchange();
                    System.out.println("exchange:"+exchange);
                    //路由key
                    String routingKey = envelope.getRoutingKey();
                    System.out.println("routingKey:"+routingKey);
                    //消息id
                    long deliveryTag = envelope.getDeliveryTag();
                    System.out.println("deliveryTag:"+deliveryTag);
                    //消息内容
                    String msg = new String(body, "utf8");
                    System.out.println("收到消息:" + msg);
                }
            };
            /**
             * 5.接受消息
             * 监听队列String queue, boolean autoAck,Consumer callback
             * 参数明细
             * 1、队列名称
             * 2、是否自动回复,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置
             为false则需要手动回复
             * 3、消费消息的方法,消费者接收到消息后调用此方法
             */
            channel.basicConsume(QUEUE_HELLO, true,consumer);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

这个时候队列里面的消息没有了
在这里插入图片描述
消费者已经获取了消息,但是程序没有停止,一直在监听队列中是否有新的消息。一旦有新的消息进入队列,就会立即打印

5.消息确认机制(ACK)

通过刚才的案例可以看出,消息一旦被消费者接收,队列中的消息就会被删除。

那么问题来了:RabbitMQ怎么知道消息被接收了呢?

如果消费者领取消息后,还没执行操作就挂掉了呢?或者抛出了异常?消息消费失败,但是RabbitMQ无从得知,这样消息就丢失了!

因此,RabbitMQ有一个ACK机制。当消费者获取消息后,会向RabbitMQ发送回执ACK,告知消息已经被接收,不过这种回执ACK分两种情况:

  • 自动ACK:消息一旦被接收,消费者自动发送ACK。
  • 手动ACK:消息接收后,不会发送ACK,需要手动调用。

这需根据消息的重要性来选:

  • 如果消息不太重要,丢失也没有影响,那么自动ACK会比较方便
  • 如果消息非常重要,不容丢失,那么最好在消费完成后手动ACK,否则接收消息后就自动ACK,RabbitMQ就会把消息从队列中删除。如果此时消费者宕机,那么消息就丢失了。

自动确认存在问题

修改消费者,添加异常,如下:

在这里插入图片描述

生产者不做任何修改,直接运行,消息发送成功
在这里插入图片描述

运行消费者,程序抛出异常,但是消息依然被消费
在这里插入图片描述
在这里插入图片描述
手动确认实现
在这里插入图片描述

二、Work queues

在这里插入图片描述

work queues与入门程序相比,多了一个消费端,两个消费端共同消费同一个队列中的消息。

**应用场景:**对于任务过重或任务较多情况使用工作队列可以提高任务处理的速度。

测试:

  1. 使用入门程序,启动多个消费者。
  2. 生产者发送多个消息。

结果:

  1. 一条消息只会被一个消费者接收。
  2. rabbit采用轮询的方式将消息是平均发送给消费者的,消费者在处理完某条消息后,才会收到下一条消息。

工作队列,又称任务队列,主要思想就是避免执行资源密集型任务时,必须等待它执行完成。相反我们稍后完成任务,我们将任务封装为消息并将其发送到队列。 在后台运行的工作进程将获取任务并最终执行作业。当你运行许多工人时,任务将在他们之间共享,但是一个消息只能被一个消费者获取。

这个概念在Web应用程序中特别有用,因为在短的HTTP请求窗口中无法处理复杂的任务。

接下来我们来模拟这个流程:

  • P:生产者:任务的发布者
  • C1:消费者,领取任务并且完成任务,假设完成速度较快
  • C2:消费者2:领取任务并完成任务,假设完成速度慢
1.创建消息发送者

同helloword一样,不过多发几条消息。
在这里插入图片描述

2.创建多个消息接受者

同 helloword一样,不过消费者一个能力强一个差(RevTest1跟之前一样,RevTest2模拟完成耗时多加一个让线程休眠)
在这里插入图片描述

3.测试

两个消费者同时启动,然后在启动生产者发送50条消息:
在这里插入图片描述可以发现,两个消费者各自消费了25条消息,而且各不相同,这就实现了任务的分发。

4.设置能者多劳

刚刚的模拟中,消费者1比消费者2的效率要高,消费者2一次任务的耗时较长,然而两人最终消费的消息数量是一样的 消费者1大量时间处于空闲状态,消费者2一直忙碌。现在的状态属于是把任务平均分配,正确的做法应该是消费越快的人,消费的越多。

我们可以使用basicQos方法和prefetchCount = 1设置。 这告诉RabbitMQ一次不要向工作人员发送多于一条消息。 或者换句话说,不要向工作人员发送新消息,直到它处理并确认了前一个消息。 相反,它会将其分派给不是仍然忙碌的下一个工作人员。

在这里插入图片描述
请添加图片描述

三、订阅模型分类

在之前的模式中,我们创建了一个工作队列。 工作队列背后的假设是:每个任务只被传递给一个工作人员。 在这一部分,我们将做一些完全不同的事情 - 我们将会传递一个信息给多个消费者。 这种模式被称为“发布/订阅”。

1.订阅模型示意图
  1. 1个生产者,多个消费者
  2. 每一个消费者都有自己的一个队列
  3. 生产者没有将消息直接发送到队列,而是发送到了交换机
  4. 每个队列都要绑定到交换机
  5. 生产者发送的消息,经过交换机到达队列,实现一个消息被多个消费者获取的目的

在这里插入图片描述

2.Exchange分类:

X(Exchanges)交换机一方面接收生产者发送的消息,另一方面知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。

  1. Fanout:广播

将消息交给所有绑定到交换机的队列。

  1. Direct:定向

把消息交给符合指定routing key 的队列 一堆或一个。

  1. Topic:通配符

把消息交给符合routing pattern(路由模式)的队列 一堆或者一个。

四、订阅模型-广播模式FANOUT

Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失。

发送者需要声明交换机 ,不需要声明队列,发送消息的时候需要指定交换机,不需要指定routingkey接受者需要声明队列 ,需要给队列绑定交换机 ,接受者的交换机和消息发送者的交换机要一致。多个消息接受者,声明的队列的名字需要不一样,而交换机的名字需要一样。
在这里插入图片描述
在广播模式下,消息发送流程:

  1. 可以有多个消费者。
  2. 每个消费者有自己的queue(队列)。
  3. 每个队列都要绑定到Exchange(交换机)。
  4. 生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定。
  5. 交换机把消息发送给绑定过的所有队列。
  6. 队列的消费者都能拿到消息,实现一条消息被多个消费者消费。
1.创建消息发送者

两个变化:

  1. 声明Exchange,不再声明Queue
  2. 发送消息到Exchange,不再发送到Queue
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.MessageProperties;
import com.ty.util.ConnectionUtil;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class SenTest {
    //交换机的名字
    private static final String EXCHANGE = "FANOUT_EXCHANGE";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = null;
        Channel channel = null;
        try{
            //1.创建链接对象
            connection = ConnectionUtil.getConnection();

            //2.创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
            channel = connection.createChannel();

            //3.声明交换机,指定类型为fanout
            channel.exchangeDeclare(EXCHANGE, "fanout",true);

            //4.消息发布
            String message = "广播模式FANOUT" ;
            channel.basicPublish(EXCHANGE ,"" , MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
            System.out.println("已经发送消息:" + message);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(channel != null){
                try {
                    channel.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
2.创建消息接受者

消费1与消费者2的区别在于声明的队列的名字需要不一样,但是交换机的名字需要一样。

import com.rabbitmq.client.*;
import com.ty.util.ConnectionUtil;

import java.io.IOException;

public class RevTest1 {
    //队列的名字
    private static final String QUEUE = "FANOUT_QUEUE_1";

    //交换机的名字
    private static final String EXCHANGE = "FANOUT_EXCHANGE";

    public static void main(String[] args) {
        try {
            //1.创建链接
            Connection connection = ConnectionUtil.getConnection();

            //2.创建通道
            Channel channel = connection.createChannel();

            //3.声明队列
            channel.queueDeclare(QUEUE, true, false, false, null);

            //4.绑定队列到交换机
            channel.queueBind(QUEUE, EXCHANGE, "");

            //5.定义消费方法
            Consumer consumer = new DefaultConsumer(channel){
                //获取消息并且处理,这个方法类似事件监听,如果有消息的时候会被自动调用
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)throws IOException {
                    //消息内容
                    String msg = new String(body, "utf8");
                    System.out.println("消费者1:" + msg);
                }
            };

            //6.监听队列,自动返回完成
            channel.basicConsume(QUEUE, true,consumer);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
3.测试

同时运行两个消费者,然后发送1条消息:

在这里插入图片描述

五、订阅模型-定向模式Direct

direct定向模式是交换机根据product指定的routingkey,收到消息后去匹配指定routingkey的队列,将消息发送给队列,消费者进行消费,是有选择性的接收消息。
在这里插入图片描述

  • P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key。

  • X:Exchange(交换机),接收生产者的消息,然后把消息递交给与routing key完全匹配的队列。

  • C1:消费者,其所在队列指定了需要routing key 为 error 的消息。

  • C2:消费者,其所在队列指定了需要routing key 为 info、error、warning 的消息。

1.创建消息发送者

同fanout模式一样,不过要改一下模型、指定routingkey。
在这里插入图片描述

2.创建消息接受者

消费者1和消费者2同fanout模式一样,不过队列名要不一样交换机名字相同,绑定队列到交换机时要指定routingkey。

消费者1:
在这里插入图片描述
消费者2:
在这里插入图片描述

3.测试

我们分别发送update、delete的RoutingKey,发现结果:
在这里插入图片描述

在这里插入图片描述

六、订阅模型-通配符模式Topics

Topic类型的Exchange与Direct相比,都是可以根据RoutingKey把消息路由到不同的队列,只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符。

Routingkey 一般都是由一个或多个单词组成,多个单词之间以”.”分割,例如: ty.insert

通配符规则:

     #:匹配一个或多个词

     *:匹配不多不少恰好1个词

举例:

     audit.#:能够匹配audit.irs.corporate 或者 audit.irs

     audit.*:只能匹配audit.irs

在这里插入图片描述

1.创建消息发送者

同fanout模式一样,不过要改一下模型、指定routingkey。
在这里插入图片描述

2.创建消息接受者

消费者1和消费者2同fanout模式一样,不过队列名要不一样交换机名字相同,绑定队列到交换机时要指定routingkey。

消费者1:
在这里插入图片描述

消费者2:
在这里插入图片描述

3.测试

我们分别发送ty.update、ty.insert的RoutingKey,发现结果:
在这里插入图片描述
在这里插入图片描述

七、Header模式

header模式与routing不同的地方在于,header模式取消routingkey,使用header中的 key/value(键值对)匹配 队列。

举例:

     根据用户的通知设置去通知用户,设置接收Email的用户只接收Email,
     设置接收sms的用户只接收sms,设置两种通知类型都接收的则两种通知都有效。
1.创建消息发送者
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.ty.util.ConnectionUtil;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.TimeoutException;

public class SenTest {
    //交换机的名字
    private static final String EXCHANGE = "HEADERS_EXCHANGE";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = null;
        Channel channel = null;
        try{
            //1.创建链接对象
            connection = ConnectionUtil.getConnection();

            //2.创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
            channel = connection.createChannel();

            //3.声明交换机,指定类型为headers
            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.HEADERS);

            //4.发送消息
            String message = "发送了一个email消息" ;

            Map<String,Object> headers = new Hashtable<String, Object>();
            headers.put("inform_type_email", "email");//匹配email通知消费者绑定的header

            AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder();
            properties.headers(headers);

            //5.消息发布
            channel.basicPublish(EXCHANGE ,"" , properties.build(), message.getBytes());
            System.out.println("已经发送消息:" + message);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(channel != null){
                try {
                    channel.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
2.创建消息接受者

消费者1:

import com.rabbitmq.client.*;
import com.ty.util.ConnectionUtil;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;

public class RevTest1 {
    //队列的名字
    private static final String QUEUE = "HEADERS_QUEUE_1";

    //交换机的名字
    private static final String EXCHANGE = "HEADERS_EXCHANGE";

    public static void main(String[] args) {
        try {
            //1.创建链接
            Connection connection = ConnectionUtil.getConnection();

            //2.创建通道
            Channel channel = connection.createChannel();

            //3.声明队列
            channel.queueDeclare(QUEUE, true, false, false, null);

            Map<String, Object> headersEmail = new Hashtable<String, Object>();
            headersEmail.put("inform_type_email", "email");

            //4.绑定队列到交换机
            channel.queueBind(QUEUE, EXCHANGE, "",headersEmail);

            //5.定义消费方法
            Consumer consumer = new DefaultConsumer(channel){
                //获取消息并且处理,这个方法类似事件监听,如果有消息的时候会被自动调用
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)throws IOException {
                    //消息内容
                    String msg = new String(body, "utf8");
                    System.out.println("消费者1:" + msg);
                }
            };

            //6.监听队列,自动返回完成
            channel.basicConsume(QUEUE, true,consumer);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

消费者2:
改一下队列名称和键值对。
在这里插入图片描述

3.测试

在这里插入图片描述

在这里插入图片描述

八、订阅模型-广播模式FANOUT

在这里插入图片描述

RPC即客户端远程调用服务端的方法 ,使用MQ可以实现RPC的异步调用,基于Direct交换机实现,流程如下:

  1. 客户端即是生产者就是消费者,向RPC请求队列发送RPC调用消息,同时监听RPC响应队列。
  2. 服务端监听RPC请求队列的消息,收到消息后执行服务端的方法,得到方法返回的结果。
  3. 服务端将RPC方法 的结果发送到RPC响应队列。
  4. 客户端(RPC调用方)监听RPC响应队列,接收到RPC调用结果。

九、如何避免消息丢失

1.手动签收

消费者的ACK机制,可以防止消费者丢失消息。但是如果在消费者消费之前,MQ就宕机了消息就没了。

2.持久化

持久化可以防止消费者丢失消息。

1)交换机持久化

在这里插入图片描述

2)队列持久化

在这里插入图片描述

3)消息持久化

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java操作RabbitMQ 的相关文章

  • 如何使用固定数量的工作线程实现简单线程

    我正在寻找最简单 最直接的方法来实现以下内容 主程序实例化worker 执行任务的线程 Only n任务可以同时运行 When n已达到 不再有工人 开始直到计数 正在运行的线程回落到下方n 我觉得Executors newFixedThr
  • 如果列名不同,则一对多休眠连接

    我有三个具有以下结构的表 合同 gt Contract id 主要 customer company id Vendor company id 公司 gt Company id 主要 创建日期 创建者 Company Timeline gt
  • 如何在log4j的配置文件中为文件附加器提供环境变量路径

    我有一个log4j xml配置文件 和一个RollingFileAppender我需要提供用于存储日志的文件路径 问题是我的代码将作为可运行的 jar 部署在 Unix 机器上 所以如果我传递这样的参数 value logs message
  • 如何提取文件 jre-9/lib/modules?

    In JRE 9 lib目录 至少在 Windows 上 有一个名为modules其大小约为107 MB 是否可以提取该文件或在其中列出 java 模块 我可以看到一个名为jmod可以在jdk 9 bin jmod exe 但那是为了阅读
  • GET 请求的 Spring 注解

    这两种spring GET方法有什么区别呢 哪一种是首选方法 Component Scope request Path public class TestComponent GET Path hello public String prin
  • 在 Java 中从 SOAPMessage 获取原始 XML

    我已经在 J AX WS 中设置了 SOAP WebServiceProvider 但我无法弄清楚如何从 SOAPMessage 或任何 Node 对象获取原始 XML 下面是我现在获得的代码示例 以及我试图获取 XML 的位置 WebSe
  • 迁移到Java 9或更高版本时是否需要切换到模块?

    我们目前正在从 Java 8 迁移到 Java 11 但是 升级我们的服务并没有我们预期的那么痛苦 我们基本上只需要更改我们的版本号build gradle文件和服务都顺利启动并运行 我们升级了库以及使用这些库的 微 服务 到目前为止没有问
  • 尝试获取屏幕上绘制的每个随机圆圈的 x、y 坐标

    您好 我正在制作一款游戏 该游戏将在屏幕上创建随机圆圈 随机创建的圆圈的值为红色或绿色 我的问题是 我希望不仅能够确定用户何时单击其中一个圆圈 而且还能够确定他们最终单击的圆圈 红色或绿色 下面是我的代码 我的主要问题是试图找到将要绘制的圆
  • Kafka Java Consumer 已关闭

    我刚刚开始使用卡夫卡 我面临着消费者的一个小问题 我用Java写了一个消费者 我收到此异常 IllegalStateException 此消费者已关闭 我在以下行中遇到异常 ConsumerRecords
  • 使用 JAX-WS 的 WebLogic 中没有模式导入的单个 WSDL

    如何使用 JAX WS 配置由 WebLogic 10 3 6 生成的 Web 服务 以将对象架构包含在单个 WSDL 文件声明 而不是导入声明 中 示例代码 界面 import javax ejb Local Local public i
  • 正则表达式在 Velocity 模板中不起作用

    我在 Test java 中尝试过这个 String regex lt s br s s gt String test1 lt br gt System out println test replaceAll regex 但是当我在速度模板
  • java.lang.Object的hashCode具体使用的算法是什么

    中使用的算法是什么JVM实施java lang Object的隐含的hashCode 方法 OpenJDK or Oracle JDK答案中首选 它依赖于实现 并且在很大程度上 该算法是entirely取决于实施 只要它是一致的 但是 根据
  • 使用 HTTPServletRequestWrapper 包装请求参数

    我有一个可以验证 授权 REST 调用的过滤器 该过滤器需要访问请求参数 因此我为此编写了一个自定义 HTTPServletRequestWrapper import java util Collections import java ut
  • Jetty Plugin 9启动不喜欢icu4j-2.6.1.jar

    我对 mortbay 的 Maven jetty 插件 6 有相同的配置
  • Android项目中使用java获取电脑的IP地址

    我在用ksoap2 android http code google com p ksoap2 android 我需要使用java获取IP地址 这样我就不必每次都手动输入它 我所说的 IP 地址是指 例如 如果我这样做ipconfig使用命
  • JPA 将 BigDecimal 作为整数保存在数据库中

    我在数据库中有这个字段 ITEMCOST NUMERIC 13 DEFAULT 0 NOT NULL 在JAVA中 Entity中的字段定义如下 Column name ITEMCOST private BigDecimal itemCos
  • 如何将库添加到 LIBGDX 项目的依赖项 gradle

    一切都在问题中 我已经尝试了在 SO 和其他网站中找到的所有答案 但没有运气 这就是我迄今为止尝试过的 adding compile fileTree dir lib include jar 到我的 build gradle adding
  • 如何清理 Runtime.exec() 中使用的用户输入?

    我需要通过命令行调用自定义脚本 这些脚本需要很少的参数并在 Linux 机器上调用 当前版本容易出现各种shell注入 如何清理用户给出的参数 参数包括登录名和路径 Unix 或 Windows 路径 用户应该能够输入任何可能的路径 该路径
  • 如何使用注释处理 Hibernate 和 Spring 中的连接查询?

    我正在使用 Spring 和 Hibernate 以及 MySQL 开发应用程序 我是 Hibernate 新手 完成了基本任务 现在我需要在选择查询中应用联接以使用注释从多个表中获取数据 我已经搜索过但仍然没有任何想法 这是我的数据库表和
  • 使用 AmazonSNSClient 发送短信时的授权

    aws 官方文档如何发送短信 http docs aws amazon com sns latest dg sms publish to phone html使用 java 中的 aws SDK 非常简单 但是 当发送如底部示例所示的消息时

随机推荐

  • windows查看功耗

    可以在Windows系统中查看功耗的方法有以下几种 使用任务管理器 在Windows桌面上按下Ctrl Alt Delete键 选择任务管理器 然后在 性能 选项卡中单击 电源使用情况 查看功耗信息 使用系统监视器 打开系统监视器 在Win
  • java 图片Base64转成文件流,直接在浏览器访问图片

    因为业务 需要把图片base64转成文件流 然后直接在浏览器访问就可以看见图片 回显图片 author liuhengliang return ModelAndView RequestMapping value image private
  • 基于51单片机的温度烟雾报警系统设计

    功能 本实例是基于51单片机的温度烟雾报警系统 主要硬件由51单片机最小系统 LCD1602液晶屏电路 烟雾检测电路 温度感应电路 蜂鸣器报警电路 ADC0832转换电路 LED指示灯电路和按键电路构成 1 LCD1602液晶屏 第一行显示
  • Colab .ipynb 从本地/云端/GitHub 导入并使用.py文件

    1 下载 上传目标文件 1 从GitHub下载所需repo 下载Code 下载 Zip 文件保存到本地 2 上传至云端Google Drive 上传成功后就能在My Drive看到文件夹了 尝试过直接Clone repo到Colab 但是后
  • python爬取考研网的信息

    今天我们使用python来爬取考研网站的信息 目标网站 https yz chsi com cn zsml queryAction do 使用的库 requests bs4 pandas 这些库统一可以使用pip进行统一安装 pip ins
  • VSCode 插件安装:中文(简体)语言包(附带:不生效解决方案)

    文章目录 VSCode 安装插件 中文 简体 语言包 中文语言包不生效解决方案 打开 命令面板 配置显示语言 选择中文 重启VSCode 效果 中文界面 VSCode 安装插件 中文 简体 语言包 插件市场搜索 中文 选择如下插件安装 Ch
  • Vue3自定义指令之前端水印功能实现

    一 前置知识 Vue 中的自定义指令 先来说说 vue2和vue3中自定义全局指令的区别 相同点 指令的应用场景 原理是一致的 不同点 生命周期钩子函数名 指令定义的格式不一样 vue2中自定义全局指令 定义 注册一个全局自定义指令 v f
  • 一篇关于如何用深度学习完成自动上色(Automatic Image Colorization)的论文浅析

    论文标题是 Let there be Color Joint End to end Learning of Global and Local Image Priors for Automatic Image Colorization wit
  • 【转载】英语动词过去式ed的发音规则

    规则动词词尾加 ed有三种读音 1 在清辅音后读作 t 如 asked helped watched stopped 2 在浊辅音和元音后读作 d 如 enjoyed studied moved called 3 在t d后读作 id 如
  • 基于vue-cli3模板的axios封装项目

    为了更便捷的使用项目框架 本模板为空白项目 但是已经为大家封装了axios方法和post get请求 内有基础案例 请大家按着自己项目需要进行修改使用 axios interceptors response use response gt
  • 采样位数、采样率、波特率

    实例 16bit 16K 115200 1 采样位数 即采样值或取样值 就是将采样样本幅度量化 它是用来衡量声音波动变化的一个参数 也可以说是声卡的分辨率 它的数值越大 分辨率也就越高 所发出声音的能力越强 在计算机中采样位数一般有8位和1
  • Spring Cloud 微服务

    Spring Cloud 微服务架构介绍 单体架构 单体架构也称之为单体系统或者是单体应用 就是把系统中所有的功能 模块耦合在一个应用中的架构方式 特点 打包成一个独立的单元 导成一个唯一的 jar 包或者是 war 包 会一个进程的方式来
  • 金算盘高手论坛资料中心_3D006期 菜鸟论坛精英PK专栏 速来围观!!

    点上方 菜鸟选号论坛 点右上角 选 星标 每日上午更新 星标置顶与大神不走散 苹果是置顶 安卓是星标 点击 菜鸟选号论坛 关注我们 论坛明星版块 集全网各路高手之大乘 打造草根明星 展示舞台 同时主要是为广大关注彩友 在每一期 推出个人擅长
  • swift编程入门(非常详细)从零基础入门到精通,看完这一篇就够了

    文章目录 1 读后概述 2 语法笔记 2 1 说明 2 2 基础类型 2 3 运算符 2 4 字符与字符串 2 4 控制流 2 5 函数 2 6 闭包 2 7 枚举 结构体 类 2 8 类的构造与析构 2 9 属性监听器 2 10 类的继承
  • python 图像处理(7):对比度与亮度调整

    图像亮度与对比度的调整 是放在skimage包的exposure模块里面 1 gamma调整 原理 I Ig 对原图像的像素 进行幂运算 得到新的像素值 公式中的g就是gamma值 如果gamma gt 1 新图像比原图像暗 如果gamma
  • 毕业设计-基于微信小程序的电影推荐系统

    目录 前言 课题背景与简介 实现设计思路 一 电影推荐算法的设计与实现 二 电影推荐系统分析与设计 实现效果样例 更多帮助 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业升学做准备 一边要为毕业设计耗费大量精力
  • 基于情感词典的情感分析

    思路以及代码都来源于下面两篇文章 一个不知死活的胖子 Python做文本情感分析之情感极性分析 Ran Fengzheng 的博客 基于情感词典的文本情感极性分析相关代码 基于情感词典的情感分析应该是最简单的情感分析方法了 大致说一下使用情
  • http服务器_本地简易http服务器

    本地简易http服务器 下面实现一个简单的http服务器 听起来高大上的样子 其实就是网络通信加上http协议 运用上篇的网络编程的基础模型 上篇的网络通信是开两个vs程序 一个做服务器 一个做客户端 互相发送数据 http服务器其实也是同
  • 【Unity-学习-021】异步实现HTTP请求

    对Http访问操作 Unity中一般使用协程操作 但是协程有一个比较要命的要求就是所在Mono必须在场景中是激活的 所以一些操作就会被限制 所以我们就找办法替代掉协程做一些异步的操作 那就用异步方法 首先扩展一下AsyncOperation
  • java操作RabbitMQ

    文章目录 一 基本消息模型 1 导入依赖 2 准备连接工具类 3 创建消息发送者 生产者 4 创建消息接受者 消费者 5 消息确认机制 ACK 二 Work queues 1 创建消息发送者 2 创建多个消息接受者 3 测试 4 设置能者多