【RabbitMQ】显示耗时处理进度

通过网页提交一个耗时的请求,然后启动处理线程,请求返回。处理线程每完成一部分就给前台推送完成的数量,前端显示进度。

依赖jar

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>rabbitmq-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rabbitmq-service</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

配置

server.port=
spring.application.name=rabbitmq-service
spring.rabbitmq.host=192.168.226.128
spring.rabbitmq.port=
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

主入口

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

RabbitMQ配置

package com.example.rabbitmqservice.config;

import lombok.Data;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope; @Data
@Configuration
@ConfigurationProperties(prefix = "spring.rabbitmq")
public class RabbitMQConfig {
private String host;
private int port;
private String username;
private String password; @Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host,port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost("/");
connectionFactory.setPublisherConfirms(true);
return connectionFactory;
} @Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RabbitTemplate rabbitTemplate() {
return new RabbitTemplate(connectionFactory());
}
}

处理RabbitMQ配置

package com.example.rabbitmqservice.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class RabbitMQConfigProcess { public static final String PROCESS_DIRECT_EXCHANGE = "process.direct.exchange";
public static final String PROCESS_QUEUE = "process.queue";
public static final String PROCESS_KEY = "process.key"; @Bean
public DirectExchange processDirectExchange() {
return new DirectExchange(PROCESS_DIRECT_EXCHANGE, true, false);
} @Bean
public Queue processQueue() {
return new Queue(PROCESS_QUEUE, true, false, false);
} @Bean
public Binding processBinding() {
return BindingBuilder.bind(processQueue()).to(processDirectExchange()).with(PROCESS_KEY);
}
}

WebSocket配置

package com.example.rabbitmqservice.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; @Configuration
@EnableWebSocket
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { public static final String END_POINT = "/websocket"; @Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint(END_POINT)
.setAllowedOrigins("*")
.withSockJS()
.setHeartbeatTime(5000)
.setDisconnectDelay(3000)
.setStreamBytesLimit(512);
}
}

消息接收转发

package com.example.rabbitmqservice.receive;

import com.example.rabbitmqservice.config.RabbitMQConfigProcess;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component; @Component
@RabbitListener(queues = RabbitMQConfigProcess.PROCESS_QUEUE)
public class ProcessReceive {
@Autowired
private SimpMessagingTemplate messagingTemplate; @RabbitHandler
public void process(String content) {
System.out.println("收到并转发消息 > " + content);
messagingTemplate.convertAndSend("/direct/process/", content);
}
}

请求处理

package com.example.rabbitmqservice.controller;

import com.example.rabbitmqservice.config.RabbitMQConfigProcess;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.time.LocalTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; @RestController
public class ProcessController {
@Autowired
private RabbitTemplate rabbitTemplate; ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 40, 2, TimeUnit.MINUTES, new LinkedBlockingDeque<>()); @RequestMapping("/process/direct")
public Map<String, Object> direct() { Runnable runnable = () -> process();
executor.execute(runnable); Map<String, Object> result = new HashMap<>();
result.put("status", 200);
result.put("message", "开始处理");
return result;
} private void process() {
// 模拟耗时处理
for (int i = 1; i <= 100; i++) {
String msg = String.valueOf(i);
rabbitTemplate.convertAndSend(RabbitMQConfigProcess.PROCESS_DIRECT_EXCHANGE, RabbitMQConfigProcess.PROCESS_KEY , msg,
// 消息到达broker时调用confirm callback。若是cluster则到达所有的broker时调用confirm callback。
message -> {
// 投递模式2
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
System.out.println("confirm callback");
return message;
}, new CorrelationData("123")); rabbitTemplate.setMandatory(true);//开启强制委托模式
// 没有投递到目标队列时调用return callback
rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
System.out.println("return callback");
System.out.println("没有投递到目标队列");
}); // 模拟耗时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
}

前端html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="js/sockjs.js"></script>
<script type="text/javascript" src="js/stomp.js"></script>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript" src="js/axios.min.js"></script>
</head>
<body>
<div id="app">
<span v-text="message"></span>
<button type="button" @click="startMock">开始模拟</button>
<span v-text="process"></span>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
process: '',
message: '点击开始模拟'
},
methods: {
startMock: function() {
var _this = this;
var query = {};
this.requestProcess(query).then(response => {
console.log('返回');
console.dir(response);
}).then(error => {
console.log('出错');
console.dir(error);
});
},
requestProcess(query) {
return new Promise((resolve, reject) => {
axios({
url: 'http://localhost:8088/process/direct',
method: 'get',
params: query
}).then(response => {
resolve(response);
//_this.message = response.data.message;
}).catch(error => {
reject(error);
});
});
},
displayProcess: function() {
var _this = this;
console.log('displayProcess');
var sock = new SockJS("http://localhost:8088/websocket");
var stompClient = Stomp.over(sock);
stompClient.connect({}, function () {
stompClient.subscribe('/direct/process/', function (data) {
console.dir(data);
_this.process = data.body + '%';
}, {precessId: 123});
});
sock.onclose = function () {
console.dir("websocket已经断开连接");
// 断开五秒后重连
setTimeout(function () {
_this.displayProcess();
}, 5000);
}
}
},
mounted: function() {
this.displayProcess();
}
});
</script>
</body>
</html>

【RabbitMQ】显示耗时处理进度的更多相关文章

  1. 使用afinal下载文件并且在状态栏中显示下载的进度

    2013年10月23日,今天是在“我在找你信息服务有限公司”第一天上班,公司给提出了这样一个要求:下载本公司的app,并且在下载的过程中要在状态栏中显示下载的进度,并且,可以暂停和继续下载. 下面是我 ...

  2. jsp实时显示后台批处理进度 - out分块,简单的长连接方式

    这两天在实现一个批处理操作,但是想让前台实时显示后台批处理进度,本想着用复杂一些的框架可以实现异步信息调用 但是鉴于是内部管理系统,且只有一两个人用到这个功能,所以做了一个简单的长连接方式的实时响应 ...

  3. delphi之完美Splash方案(在TfrmMain.FormCreate里不断调用TfrmSplash显示加载进度文字,并且及时Update显示)

    前言:网上有很多介绍delphi创建闪屏的代码,大多只是在程序开启前显示一个闪屏,但是却没有说如何在闪屏上显示程序加载的进度,于是笔者有意思介绍一下这种闪屏方式. 1.创建一个窗体(TfrmSplas ...

  4. js 利用 ajax 加载 js ,显示加载进度 ,严格按照js的顺序先后加载到页面

    js 利用 ajax 加载 js ,显示加载进度 ,严格按照js的顺序先后加载到页面 , 做手机端开发时,发现一个问题,有些浏览器,在网速比较慢的情况下,js文件没有加载完,后续的调用已经开始调用了, ...

  5. Asp.Net MVC页面显示后台处理进度问题

    这个问题的背景是,用户通过浏览器上传文件或Excel数据到系统中,页面需要时时显示后台处理进度,以增强用户的体验. 在GitHub上找到一个一个项目,基本实现了这个功能,具体效果如下图 代码实现过程大 ...

  6. [Swift通天遁地]四、网络和线程-(9)上传图片并实时显示上传进度

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  7. 2.WP8.1开发_在顶部显示标题和进度

    有时候加载页面的时候,需要在信号那一栏显示进度,或者把信号栏改成标题 1.确保显示状态栏.默认显示.如果不显示,可以在应用程序启动后手动用代码显示,代码如下: //取得状态栏 StatusBar ba ...

  8. LODOP打印URL显示和隐藏进度条

    不建议使用ADD_PRINT_URL:由于Lodop借用IE下载引擎,与非IE浏览器之间目前不能传递Session(Cookies),所以需要安全验证的页面不要用URL方式打印,要用页面已经下载好的内 ...

  9. uploadify实现七牛云存储 显示上传进度+页面显示

    准备: uploadify下载地址: http://www.uploadify.com/download/ 七牛 php-sdk开发指南: http://developer.qiniu.com/doc ...

随机推荐

  1. 【java】关于Cannot refer to the non-final local variable list defined in an enclosing scope解决方法

    今天学习中遇到了一个问题: Cannot refer to the non-final local variable list defined in an enclosing scope 这里的new ...

  2. Java,你告诉我 fail-fast 是什么鬼?

    本篇我们来聊聊 Java 的 fail-fast 机制,文字一如既往的有趣哦. 01.前言 说起来真特么惭愧:十年 IT 老兵,Java 菜鸟一枚.今天我才了解到 Java 还有 fail-fast ...

  3. 基于 cobbler 实现自动安装 linux 系统

    使用 cobbler 实现自动安装 centos 6.7系统 1.yum install cobbler -y 安装 cobbler ,有依赖关系,会自动把 TFTP .HTTP 服务安装上:cobb ...

  4. python:爬虫0

    什么是网页爬虫,也叫网页蜘蛛.把互联网比作一个蜘蛛网,有好多节点,这个蜘蛛在网上爬来爬去,对对网页中的每个关键字进行建立索引,然后建立索引数据库,经过复杂的排序算法后,这些算法的结果将按照相关度的高低 ...

  5. 基于loghub的消息消费延迟监控

    我们可以把loghub当作一个消息中间件来使用.如果能知道当前的消费进度,自然好了,否则消费情况一无所知,总是有点慌! loghub消费分两种情况,一是普通消费,二是消费组消费: 消费组消费,logh ...

  6. 【RocketMQ源码学习】- 5. 消息存储机制

    前言 面试官:你了解RocketMQ是如何存储消息的吗?我:额,,,你等下,我看下这篇文字, (逃 由于这部分内容优点多,所以请哥哥姐姐们自备茶水,欢迎留言! RocketMQ存储设计是高可用和高性能 ...

  7. SpringBoot之DispatcherServlet详解及源码解析

    在使用SpringBoot之后,我们表面上已经无法直接看到DispatcherServlet的使用了.本篇文章,带大家从最初DispatcherServlet的使用开始到SpringBoot源码中Di ...

  8. Dubbo实现登陆

    一.目录展示 二.dubbo_logins_service 2.1 实体类和service层 2.2 logins实体类 package com.login.entity; import java.i ...

  9. Theano 更多示例

    Logistic函数 logistic函数的图,其中x在x轴上,s(x)在y轴上. 如果你想对双精度矩阵上的每个元素计算这个函数,这表示你想将这个函数应用到矩阵的每个元素上. 嗯,你是这样做的: x= ...

  10. win10在python3.6里安装pycrypto-2.6.1

    简单的一步搞定 下载pycrypto-2.6.1-cp36-cp36m-win_amd64.whl文件,然后pip install即可 链接: https://pan.baidu.com/s/1Awl ...