本系列文章均采用springboot,采用同样的环境。
A、MAVEN工程
B、2.0.0.BUILD-SNAPSHOT
C 、Group:com.example
D、Artifact:RabbitMQHello
E、Packaging:jar
F、JavaVersion:1.8
G、WEB、勾选ThymeleafA、在dependencies中增加spring-boot-devtools
org.springframework.boot
spring-boot-devtools
true
B、在build的spring-boot-maven-plugin中增加依赖包
org.springframework.boot
spring-boot-maven-plugin
org.springframework
springloaded
1.2.6.RELEASE
%d %p (%file:%line\)- %m%n
GBK
log/base.log
log/base.log.%d.%i
64 MB
%d %p (%file:%line\)- %m%n
UTF-8
A、请求实体RequestMsg
package com.example;
import java.io.Serializable;
public class RequestMsg implements Serializable{
private static final long serialVersionUID = 1L;
private String param;
public RequestMsg() {
super();
}
public RequestMsg(String param) {
super();
this.param = param;
}
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
}
注意空的构造函数,必须有的
B、响应实体
package com.example;
import java.io.Serializable;
public class ResponseMsg implements Serializable{
private static final long serialVersionUID = 1L;
public static final Integer STATUS_SUCCESS = 0;
public static final Integer STATUS_FAILED = -1;
private int status;
private String msg;
private T data;
/**
* 空构造函数
*/
public ResponseMsg() {
super();
}
/**
* 全字段构造函数
* @param status
* @param msg
* @param data
*/
public ResponseMsg(int status, String msg, T data) {
super();
this.status = status;
this.msg = msg;
this.data = data;
}
/**
* 失败
* @param message
*/
public void fail(String message){
this.setStatus(STATUS_FAILED);
this.setMsg(message);
}
/**
* 成功
* @param message
* @param data
*/
public void success(String message,T data){
this.setStatus(STATUS_SUCCESS);
this.setMsg(message);
this.setData(data);
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
@Override
public String toString() {
return "ResponseMsg [status=" + status + ", msg=" + msg + ", data=" + data + "]";
}
}
package com.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class DeferredController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@RequestMapping("/")
public String index(Model model){
logger.debug("进入index");
return "index";
}
}
这个控制器,简单,就是返回index.html页面
package com.example;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
@RestController
@RequestMapping("/api")
public class DeferredRestController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Map>> responseBodyMap=new HashMap>>();
private final Map requestBodyMap=new HashMap();
/**
* 第一个请求
* @param req
* @return
*/
@RequestMapping("/request1")
@ResponseBody
public DeferredResult> request1(RequestMsg req){
logger.debug("request1:请求参数{}",req.getParam());
DeferredResult> result = new DeferredResult>();
requestBodyMap.put(1, req);//把请求放到第一个请求map中
responseBodyMap.put(1, result);//把请求响应的DeferredResult实体放到第一个响应map中
return result;
}
/**
* 第二个请求
* @param req
* @return
*/
@RequestMapping("/request2")
@ResponseBody
public DeferredResult> request2(RequestMsg req){
logger.debug("request2:请求参数{}",req.getParam());
DeferredResult> result = new DeferredResult>();
requestBodyMap.put(2, req);//把请求放到第二个请求map中
responseBodyMap.put(2, result);//把请求响应的DeferredResult实体放到第二个响应map中
return result;
}
/**
* 第三个请求
* @param req
* @return
*/
@RequestMapping("/request3")
@ResponseBody
public DeferredResult> request3(RequestMsg req){
logger.debug("request3:请求参数{}",req.getParam());
DeferredResult> result = new DeferredResult>();
requestBodyMap.put(3, req);//把请求放到第三个请求map中
responseBodyMap.put(3, result);//把请求响应的DeferredResult实体放到第三个响应map中
return result;
}
/**
* 控制第x个请求执行返回操作,同时自己也返回同样的值
* @param x
* @return
*/
@RequestMapping(value="/requestXReturn",method=RequestMethod.POST)
@ResponseBody
public ResponseMsg request1Return(Integer x){
ResponseMsg msg=new ResponseMsg();
logger.debug("requestXReturn--1:请求参数{}",x);
DeferredResult> result =responseBodyMap.get(x);
if (result==null){
msg.fail("錯誤!请求已经释放");
return msg;
}
String resultStr="result"+x.toString()+". Received:"+requestBodyMap.get(x).getParam();
msg.success("成功", resultStr);
result.setResult(msg);//设置DeferredResult的结果值,设置之后,它对应的请求进行返回处理
responseBodyMap.remove(x);//返回map删除
logger.debug("requestXReturn--2:请求参数{}",x);
logger.debug("requestXReturn--3:返回参数{}",msg);
return msg;
}
}
1、定义了两个map,分别用于保存请求对象和返回对象。
2、三个请求,分别把各自的请求、响应对象存放到对应键值的map中
3、控制返回的,到map中取出对象,然后对响应对象进行设值(result.setResult(msg);),使相应的请求发起链接进行返回处理。
1、这个页面需要jQuery,下载jquery放到src/main/resources/static下
2、在src/main/resources/templates/下新建文件index.html
DeferredResult Demo
第一个请求参数:
第一个请求返回:
第二个请求参数:
第二个请求返回:
第三个请求参数:
第三个请求返回:
这个页面完全的普通思路,没有任何技巧,包括六个按钮,三个请求按钮分别调用三个请求;三个请求返回控制,调用控制返回。
整个demo,就是为了体现DeferredResult的思想。DeferredResult执行的分成两段(第一段,发起DeferredResult;第二段,等待别的线程设置DeferredResult的resukt值,DeferredResult开始执行后续事项及返回值),这两段在两个独立的线程中。通过这个模型,我们就可以实现线程的耦合。
本篇仅仅是一个简单的demo,没有考虑超时,以及公共的返回方法,在后续章节中一一呈现。