SpringBoot的DeferredResult实例:二、另一个请求控制请求的返回时机
本系列文章均采用springboot,采用同样的环境。
一、创建工程
1、 在http://start.spring.io/中创建RabbitMQHello工程:
A、MAVEN工程
B、2.0.0.BUILD-SNAPSHOT
C 、Group:com.example
D、Artifact:RabbitMQHello
E、Packaging:jar
F、[Java](http://lib.csdn.net/base/java)Version:1.8
G、WEB、勾选Thymeleaf
2、下载工程、解压,然后导入eclipse中
3、修改pom.xml以便于热部署
A、在dependencies中增加spring-boot-devtools
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
B、在build的spring-boot-maven-plugin中增加依赖包
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<!-- spring热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.6.RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
4、增加日志配置文件
在src/main/resources下增加文件logback.xml,内容如下
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %p (%file:%line\)- %m%n</pattern>
<charset>GBK</charset>
</encoder>
</appender>
<appender name="baselog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>log/base.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>log/base.log.%d.%i</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>64 MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>
%d %p (%file:%line\)- %m%n
</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
<logger name="com.example" level="DEBUG">
<appender-ref ref="baselog" />
</logger>
</configuration>
二、編制请求、响应实体
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<T> 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页面
四、编制rest控制器
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<Integer,DeferredResult<ResponseMsg<String>>> responseBodyMap=new HashMap<Integer,DeferredResult<ResponseMsg<String>>>();
private final Map<Integer,RequestMsg> requestBodyMap=new HashMap<Integer,RequestMsg>();
/**
* 第一个请求
* @param req
* @return
*/
@RequestMapping("/request1")
@ResponseBody
public DeferredResult<ResponseMsg<String>> request1(RequestMsg req){
logger.debug("request1:请求参数{}",req.getParam());
DeferredResult<ResponseMsg<String>> result = new DeferredResult<ResponseMsg<String>>();
requestBodyMap.put(1, req);//把请求放到第一个请求map中
responseBodyMap.put(1, result);//把请求响应的DeferredResult实体放到第一个响应map中
return result;
}
/**
* 第二个请求
* @param req
* @return
*/
@RequestMapping("/request2")
@ResponseBody
public DeferredResult<ResponseMsg<String>> request2(RequestMsg req){
logger.debug("request2:请求参数{}",req.getParam());
DeferredResult<ResponseMsg<String>> result = new DeferredResult<ResponseMsg<String>>();
requestBodyMap.put(2, req);//把请求放到第二个请求map中
responseBodyMap.put(2, result);//把请求响应的DeferredResult实体放到第二个响应map中
return result;
}
/**
* 第三个请求
* @param req
* @return
*/
@RequestMapping("/request3")
@ResponseBody
public DeferredResult<ResponseMsg<String>> request3(RequestMsg req){
logger.debug("request3:请求参数{}",req.getParam());
DeferredResult<ResponseMsg<String>> result = new DeferredResult<ResponseMsg<String>>();
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<String> request1Return(Integer x){
ResponseMsg<String> msg=new ResponseMsg<String>();
logger.debug("requestXReturn--1:请求参数{}",x);
DeferredResult<ResponseMsg<String>> 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
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>DeferredResult Demo</title>
</head>
<body>
<div>
第一个请求参数:<input type="text" name="request1Request" id="request1RequestId"/><br/>
第一个请求返回:<input type="text" name="request1Result" id="request1ResultId"/><br/>
<input type="button" value="第一个请求" id="button1Request" οnclick="button1RequestClick()"/>
</div>
<div>
第二个请求参数:<input type="text" name="request2Request" id="request2RequestId"/><br/>
第二个请求返回:<input type="text" name="request2Result" id="request2ResultId"/><br/>
<input type="button" value="第二个请求" id="button2Request" οnclick="button2RequestClick()"/>
</div>
<div>
第三个请求参数:<input type="text" name="request31Request" id="request3RequestId"/><br/>
第三个请求返回:<input type="text" name="request3Result" id="request3ResultId"/><br/>
<input type="button" value="第三个请求" id="button3Request" οnclick="button3RequestClick()"/>
</div>
<div>
<input type="button" value="第二个请求返回" id="button2GetReturn" οnclick="buttonXGetReturnClick(2)"/>
</div>
<div>
<input type="button" value="第三个请求返回" id="button3GetReturn" οnclick="buttonXGetReturnClick(3)"/>
</div>
<div>
<input type="button" value="第一个请求返回" id="button1GetReturn" οnclick="buttonXGetReturnClick(1)"/>
</div>
<script th:src="@{jquery-1.12.4.min.js}" type="text/javascript"></script>
<script th:inline="javascript">
function button1RequestClick(){
//$('#button1Request').attr('disabled',"true");//添加disabled属性
//$('#button2Request').removeAttr("disabled"); //移除disabled属性
var param=$("#request1RequestId").val();
$.ajax({
timeout:30000,
async:true,
type:'post',
url:'/api/request1',
dataType : 'json',
data : {
'param' : param
},
success : function(data) {
console.log(data);
$("#request1ResultId").val(data.data);
},
error : function(data) {
console.log("button1RequestClick---error");
console.log(data);
//alert("错误消息:" + data);
}
});
};
function button2RequestClick(){
var param=$("#request2RequestId").val();
$.ajax({
timeout:30000,
async:true,
type:'post',
url:'/api/request2',
dataType : 'json',
data : {
'param' : param
},
success : function(data) {
console.log(data);
$("#request2ResultId").val(data.data);
},
error : function(data) {
console.log("button2RequestClick---error");
console.log(data);
//alert("错误消息:" + data);
}
});
};
function button3RequestClick(){
var param=$("#request3RequestId").val();
$.ajax({
timeout:30000,
async:true,
type:'post',
url:'/api/request3',
dataType : 'json',
data : {
'param' : param
},
success : function(data) {
console.log(data);
$("#request3ResultId").val(data.data);
},
error : function(data) {
console.log("button3RequestClick---error");
console.log(data);
//alert("错误消息:" + data);
}
});
};
function buttonXGetReturnClick(x){
console.log("buttonXGetReturnClick参数:"+x)
$.ajax({
type:'post',
url:'/api/requestXReturn',
dataType : 'json',
data : {
'x' : x
},
success : function(data) {
console.log("buttonXGetReturnClick:success");
console.log(data);
},
error : function(data) {
console.log("buttonXGetReturnClick---error");
console.log(data);
}
});
};
</script>
</body>
</html>
这个页面完全的普通思路,没有任何技巧,包括六个按钮,三个请求按钮分别调用三个请求;三个请求返回控制,调用控制返回。
六、小结
整个demo,就是为了体现DeferredResult的思想。DeferredResult执行的分成两段(第一段,发起DeferredResult;第二段,等待别的线程设置DeferredResult的resukt值,DeferredResult开始执行后续事项及返回值),这两段在两个独立的线程中。通过这个模型,我们就可以实现线程的耦合。
本篇仅仅是一个简单的demo,没有考虑超时,以及公共的返回方法,在后续章节中一一呈现。
原文:SpringBoot的DeferredResult实例:二、另一个请求控制请求的返回时机_lxhjh的博客-CSDN博客
作者:lxhjh