【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. nyoj 283-对称排序 (sort)

    283-对称排序 内存限制:64MB 时间限制:1000ms 特判: No 通过数:2 提交数:4 难度:1 题目描述: In your job at Albatross Circus Managem ...

  2. CMake 常用函数记录

    1.cmake_minunum_required(VERSION 2.6) #cmake 最低要求版本号 2.PROJECT(projectname [CXX] [C] [Java]) #这个指令隐式 ...

  3. 【前端知识体系-JS相关】JS基础知识总结

    1 变量类型和计算 1.1 值类型和引用类型的区别? 值类型:每个变量都会存储各自的值.不会相互影响 引用类型:不同变量的指针执行了同一个对象(数组,对象,函数) 1.2 typeof可以及检测的数据 ...

  4. Easy 2048 Again(状压dp)

    题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3802 题意: 从数列A中, 删除若干个数(可以0个), 是删除 ...

  5. 关于 “'sqlite3' 不是内部或外部命令.....”问题

    学习django 按书上的  执行 manage.py dbshell 时, 报“'sqlite3' 不是内部或外部命令,也不是可运行的程序 或批处理文件.” 也就是指,环境变量中没有“sqlite3 ...

  6. Java虚拟机详解(十)------类加载过程

    在上一篇文章中,我们详细的介绍了Java类文件结构,那么这些Class文件是如何被加载到内存,由虚拟机来直接使用的呢?这就是本篇博客将要介绍的——类加载过程. 1.类的生命周期 类从被加载到虚拟机内存 ...

  7. Java基础面试题及答案(四)

    反射 57. 什么是反射? 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力 Java反射: 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能 ...

  8. python网络爬虫之解析网页的正则表达式(爬取4k动漫图片)[三]

    前言 hello,大家好 本章可是一个重中之重,因为我们今天是要爬取一个图片而不是一个网页或是一个json 所以我们也就不用用到selenium模块了,当然有兴趣的同学也一样可以使用selenium去 ...

  9. MySQL 格式化时间 成字符串

    创建个表: CREATE TABLE `x02基本信息` ( `ID` varchar(32) NOT NULL COMMENT '系统内记录的唯一标识,供系统内部使用.', `名称` varchar ...

  10. jenkins 如何让job对应一个节点

    1.配置job:如图,在label expression 里面填写[节点标签名]或者是[节点名称]. 2.配置节点: 3.构建:第一个红线,表明使用哪个节点进行构建.  第二个红线,表明工作目录.