Compare commits
10 Commits
v1.0.0
...
sprintboot
| Author | SHA1 | Date | |
|---|---|---|---|
| 885b6bc7fb | |||
| 69a6a73663 | |||
| be5ac402cc | |||
| 26e4227ace | |||
| f8e958fa71 | |||
| 66c4d7ae39 | |||
| 4b56e79eac | |||
| 03cb51fd4a | |||
| 2890b40b4f | |||
| 30e057eb76 |
@ -3,7 +3,7 @@
|
||||
[](https://github.com/yidao620c/SpringBootBucket/issues)
|
||||
[![License][licensesvg]][license]
|
||||
[](https://github.com/yidao620c/SpringBootBucket/releases/latest)
|
||||
[](https://github.com/yidao620c/SpringBootBucket/release)
|
||||
[](https://github.com/yidao620c/SpringBootBucket/releases)
|
||||
|
||||
Spring Boot 现在已经成为Java 开发领域的一颗璀璨明珠,它本身是包容万象的,可以跟各种技术集成。
|
||||
|
||||
@ -11,6 +11,8 @@ Spring Boot 现在已经成为Java 开发领域的一颗璀璨明珠,它本身
|
||||
|
||||
每个子项目都会使用最小依赖,大家拿来即可使用,自己可以根据业务需求自由组合搭配不同的技术构建项目。
|
||||
|
||||
该分支基于springboot1.5构建。
|
||||
|
||||
## 项目简介
|
||||
|
||||

|
||||
@ -33,6 +35,7 @@ springboot-swagger2 | [集成Swagger2自动生成API文档](https://www.
|
||||
springboot-jwt | [集成JWT实现接口权限认证](https://www.xncoding.com/2017/07/09/spring/sb-jwt.html)
|
||||
springboot-multisource | [多数据源配置](https://www.xncoding.com/2017/07/10/spring/sb-multisource.html)
|
||||
springboot-schedule | [定时任务](https://www.xncoding.com/2017/07/12/spring/sb-schedule.html)
|
||||
springboot-cxf | [cxf实现WebService](https://www.xncoding.com/2017/07/13/spring/sb-cxf.html)
|
||||
springboot-websocket | [使用WebScoket实时通信](https://www.xncoding.com/2017/07/15/spring/sb-websocket.html)
|
||||
springboot-socketio | [集成SocketIO实时通信](https://www.xncoding.com/2017/07/16/spring/sb-socketio.html)
|
||||
springboot-async | [异步线程池](https://www.xncoding.com/2017/07/20/spring/sb-async.html)
|
||||
@ -76,7 +79,7 @@ springboot-echarts | [集成Echarts导出图片](https://www.xncoding.c
|
||||
## 后续计划
|
||||
|
||||
1. 集成OAuth2认证
|
||||
1. 集成QQ、微信、新浪微博第三方登录,配合shiro使用
|
||||
1. 集成QQ、微信、新浪微博第三方登录
|
||||
1. 集成网络爬虫框架
|
||||
1. 等SpringBoot 2稳定后全部升级至2
|
||||
|
||||
|
||||
14
springboot-cxf/.gitignore
vendored
Normal file
14
springboot-cxf/.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# 此为注释– 将被Git 忽略
|
||||
# /结尾表示是目录,忽略目录和目录下的所有件
|
||||
# /开头表示根目录,否则是.gitignore的相对目录
|
||||
# !开头表示反选
|
||||
.idea/
|
||||
target/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
*.log
|
||||
.svn/
|
||||
.project
|
||||
rebel.xml
|
||||
.rebel-remote.xml.*
|
||||
20
springboot-cxf/LICENSE
Normal file
20
springboot-cxf/LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Xiong Neng
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
53
springboot-cxf/README.md
Normal file
53
springboot-cxf/README.md
Normal file
@ -0,0 +1,53 @@
|
||||
## 实现WebService
|
||||
|
||||
利用Apache CXF实现WebService
|
||||
|
||||
启动之后,wsdl访问链接:<http://localhost:8092/services/CommonService?wsdl>
|
||||
|
||||
## 客户端动态代理调用
|
||||
|
||||
这个在单元测试类ApplicationTests中有演示,这里要注意的是model类的包名一定要放到指定的路径下。
|
||||
也就是targetNamespace的倒叙包名中。
|
||||
|
||||
## 客户端代码生成
|
||||
|
||||
有两种方式生成客户端调用代码
|
||||
|
||||
**Apache的wsdl2java工具**
|
||||
|
||||
```
|
||||
wsdl2java -autoNameResolution http://xxx?wsdl
|
||||
```
|
||||
|
||||
**JDK自带的工具(推荐)**
|
||||
|
||||
```
|
||||
wsimport -encoding utf-8 -p com.xncoding.webservice.client -keep http://xxx?wsdl -s d:/ws -B-XautoNameResolution
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
```
|
||||
-encoding :指定编码格式(此处是utf-8的指定格式)
|
||||
-keep:是否生成Java源文件
|
||||
-s:指定.java文件的输出目录
|
||||
-d:指定.class文件的输出目录
|
||||
-p:定义生成类的包名,不定义的话有默认包名
|
||||
-verbose:在控制台显示输出信息
|
||||
-b:指定jaxws/jaxb绑定文件或额外的schemas
|
||||
-extension:使用扩展来支持SOAP1.2
|
||||
```
|
||||
|
||||
生成的客户端代码不能改包名
|
||||
|
||||
``` java
|
||||
CommonService_Service c = new CommonService_Service();
|
||||
com.xncoding.webservice.client.User user = c.getCommonServiceImplPort().getUser("Tom");
|
||||
assertThat(user.getName(), is("Tom"));
|
||||
```
|
||||
|
||||
## 许可证
|
||||
|
||||
Copyright (c) 2018 Xiong Neng
|
||||
|
||||
基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>
|
||||
106
springboot-cxf/pom.xml
Normal file
106
springboot-cxf/pom.xml
Normal file
@ -0,0 +1,106 @@
|
||||
<?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>
|
||||
|
||||
<groupId>com.xncoding</groupId>
|
||||
<artifactId>springboot-cxf</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>springboot-restful</name>
|
||||
<description>CXF实现WebService</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.10.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jetty</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- CXF webservice -->
|
||||
<dependency>
|
||||
<groupId>org.apache.cxf</groupId>
|
||||
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
|
||||
<version>3.2.4</version>
|
||||
</dependency>
|
||||
<!-- CXF webservice -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-all</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<configuration>
|
||||
<!--<proc>none</proc>-->
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.20</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
72
springboot-cxf/run.sh
Normal file
72
springboot-cxf/run.sh
Normal file
@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
# 项目自动更新脚本
|
||||
# 先clone相应的分支下来:
|
||||
# git clone ssh://git@120.24.173.142:7999/xxx.git
|
||||
# 远程调试启动:
|
||||
# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &
|
||||
|
||||
function start {
|
||||
profile="$1"
|
||||
echo "启动环境profile=${profile}"
|
||||
jarfile=$(ls target/*.jar)
|
||||
if [[ "$?" == "0" ]]; then
|
||||
stop $profile $jarfile
|
||||
fi
|
||||
branch=$(git branch |awk '{print $2}')
|
||||
git pull origin ${branch}
|
||||
echo "更新完代码开始重新打包"
|
||||
mvn clean && mvn clean && mvn package -DskipTests=true
|
||||
if [[ "$?" != "0" ]]; then
|
||||
echo "编译出错,退出!"
|
||||
exit 1
|
||||
fi
|
||||
echo "nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &"
|
||||
nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &
|
||||
echo "启动应用中,请查看日志文件..."
|
||||
}
|
||||
|
||||
function stop {
|
||||
profile="$1"
|
||||
jarfile="$2"
|
||||
ps aux | grep "${jarfile}" | grep "spring.profiles.active=${profile}" | grep -v grep > /dev/null
|
||||
if [[ "$?" == "0" ]]; then
|
||||
echo "该应用还在跑,我先停了它"
|
||||
pid=$(ps aux | grep "${jarfile}" | grep "spring.profiles.active=${profile}" | grep -v grep |awk '{print $2}')
|
||||
if [[ "$pid" != "" ]]; then
|
||||
kill -9 $pid
|
||||
fi
|
||||
echo "停止应用成功..."
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "$1" == "start" ]]; then
|
||||
if [[ "$#" < 2 ]]; then
|
||||
echo "请输入正确参数:./epay.sh start {profile}"
|
||||
exit 1
|
||||
fi
|
||||
profile="$2"
|
||||
if [[ "$profile" != "dev" && "$profile" != "test" && "$profile" != "show" && "$profile" != "production" ]]; then
|
||||
echo "参数错误,请输入正确的profile参数,使用方法:"
|
||||
echo "./epay.sh start {profile} ==> 启动应用,{profile}取值:dev|test|show|production"
|
||||
exit 1
|
||||
fi
|
||||
start "${profile}"
|
||||
elif [[ "$1" == "stop" ]]; then
|
||||
if [[ "$#" < 2 ]]; then
|
||||
echo "请输入正确参数:./epay.sh stop {profile}"
|
||||
exit 1
|
||||
fi
|
||||
profile="$2"
|
||||
if [[ "$profile" != "dev" && "$profile" != "test" && "$profile" != "show" && "$profile" != "production" ]]; then
|
||||
echo "参数错误,请输入正确的profile参数,使用方法:"
|
||||
echo "./epay.sh stop {profile} ==> 停止应用,{profile}取值:dev|test|show|production"
|
||||
exit 1
|
||||
fi
|
||||
jarfile=$(ls target/*.jar)
|
||||
stop $profile $jarfile
|
||||
else
|
||||
echo "参数错误,使用方法:{}参数是必填的,[]参数可选"
|
||||
echo "./epay.sh start {profile} ==> 启动应用,{profile}取值:dev|test|show|production"
|
||||
echo "./epay.sh stop {profile} ==> 停止应用,{profile}取值:dev|test|show|production"
|
||||
exit 1
|
||||
fi
|
||||
@ -0,0 +1,12 @@
|
||||
package com.xncoding.webservice;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
|
||||
package com.xncoding.webservice.client;
|
||||
|
||||
import javax.jws.WebMethod;
|
||||
import javax.jws.WebParam;
|
||||
import javax.jws.WebResult;
|
||||
import javax.jws.WebService;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
import javax.xml.ws.RequestWrapper;
|
||||
import javax.xml.ws.ResponseWrapper;
|
||||
|
||||
|
||||
/**
|
||||
* This class was generated by the JAX-WS RI.
|
||||
* JAX-WS RI 2.2.9-b130926.1035
|
||||
* Generated source version: 2.2
|
||||
*
|
||||
*/
|
||||
@WebService(name = "CommonService", targetNamespace = "http://model.webservice.xncoding.com/")
|
||||
@XmlSeeAlso({
|
||||
ObjectFactory.class
|
||||
})
|
||||
public interface CommonService {
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userName
|
||||
* @return
|
||||
* returns com.xncoding.webservice.client.User
|
||||
*/
|
||||
@WebMethod
|
||||
@WebResult(targetNamespace = "")
|
||||
@RequestWrapper(localName = "getUser", targetNamespace = "http://model.webservice.xncoding.com/", className = "com.xncoding.webservice.client.GetUser")
|
||||
@ResponseWrapper(localName = "getUserResponse", targetNamespace = "http://model.webservice.xncoding.com/", className = "com.xncoding.webservice.client.GetUserResponse")
|
||||
public User getUser(
|
||||
@WebParam(name = "userName", targetNamespace = "")
|
||||
String userName);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userName
|
||||
* @return
|
||||
* returns java.lang.String
|
||||
*/
|
||||
@WebMethod
|
||||
@WebResult(targetNamespace = "")
|
||||
@RequestWrapper(localName = "sayHello", targetNamespace = "http://model.webservice.xncoding.com/", className = "com.xncoding.webservice.client.SayHello")
|
||||
@ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://model.webservice.xncoding.com/", className = "com.xncoding.webservice.client.SayHelloResponse")
|
||||
public String sayHello(
|
||||
@WebParam(name = "userName", targetNamespace = "")
|
||||
String userName);
|
||||
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
|
||||
package com.xncoding.webservice.client;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.ws.Service;
|
||||
import javax.xml.ws.WebEndpoint;
|
||||
import javax.xml.ws.WebServiceClient;
|
||||
import javax.xml.ws.WebServiceException;
|
||||
import javax.xml.ws.WebServiceFeature;
|
||||
|
||||
|
||||
/**
|
||||
* This class was generated by the JAX-WS RI.
|
||||
* JAX-WS RI 2.2.9-b130926.1035
|
||||
* Generated source version: 2.2
|
||||
*
|
||||
*/
|
||||
@WebServiceClient(name = "CommonService", targetNamespace = "http://model.webservice.xncoding.com/", wsdlLocation = "http://localhost:8092/services/CommonService?wsdl")
|
||||
public class CommonService_Service
|
||||
extends Service
|
||||
{
|
||||
|
||||
private final static URL COMMONSERVICE_WSDL_LOCATION;
|
||||
private final static WebServiceException COMMONSERVICE_EXCEPTION;
|
||||
private final static QName COMMONSERVICE_QNAME = new QName("http://model.webservice.xncoding.com/", "CommonService");
|
||||
|
||||
static {
|
||||
URL url = null;
|
||||
WebServiceException e = null;
|
||||
try {
|
||||
url = new URL("http://localhost:8092/services/CommonService?wsdl");
|
||||
} catch (MalformedURLException ex) {
|
||||
e = new WebServiceException(ex);
|
||||
}
|
||||
COMMONSERVICE_WSDL_LOCATION = url;
|
||||
COMMONSERVICE_EXCEPTION = e;
|
||||
}
|
||||
|
||||
public CommonService_Service() {
|
||||
super(__getWsdlLocation(), COMMONSERVICE_QNAME);
|
||||
}
|
||||
|
||||
public CommonService_Service(WebServiceFeature... features) {
|
||||
super(__getWsdlLocation(), COMMONSERVICE_QNAME, features);
|
||||
}
|
||||
|
||||
public CommonService_Service(URL wsdlLocation) {
|
||||
super(wsdlLocation, COMMONSERVICE_QNAME);
|
||||
}
|
||||
|
||||
public CommonService_Service(URL wsdlLocation, WebServiceFeature... features) {
|
||||
super(wsdlLocation, COMMONSERVICE_QNAME, features);
|
||||
}
|
||||
|
||||
public CommonService_Service(URL wsdlLocation, QName serviceName) {
|
||||
super(wsdlLocation, serviceName);
|
||||
}
|
||||
|
||||
public CommonService_Service(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
|
||||
super(wsdlLocation, serviceName, features);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* returns CommonService
|
||||
*/
|
||||
@WebEndpoint(name = "CommonServiceImplPort")
|
||||
public CommonService getCommonServiceImplPort() {
|
||||
return super.getPort(new QName("http://model.webservice.xncoding.com/", "CommonServiceImplPort"), CommonService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param features
|
||||
* A list of {@link WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
|
||||
* @return
|
||||
* returns CommonService
|
||||
*/
|
||||
@WebEndpoint(name = "CommonServiceImplPort")
|
||||
public CommonService getCommonServiceImplPort(WebServiceFeature... features) {
|
||||
return super.getPort(new QName("http://model.webservice.xncoding.com/", "CommonServiceImplPort"), CommonService.class, features);
|
||||
}
|
||||
|
||||
private static URL __getWsdlLocation() {
|
||||
if (COMMONSERVICE_EXCEPTION!= null) {
|
||||
throw COMMONSERVICE_EXCEPTION;
|
||||
}
|
||||
return COMMONSERVICE_WSDL_LOCATION;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
|
||||
package com.xncoding.webservice.client;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>getUser complex type的 Java 类。
|
||||
*
|
||||
* <p>以下模式片段指定包含在此类中的预期内容。
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="getUser">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="userName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "getUser", propOrder = {
|
||||
"userName"
|
||||
})
|
||||
public class GetUser {
|
||||
|
||||
protected String userName;
|
||||
|
||||
/**
|
||||
* 获取userName属性的值。
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置userName属性的值。
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setUserName(String value) {
|
||||
this.userName = value;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
|
||||
package com.xncoding.webservice.client;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>getUserResponse complex type的 Java 类。
|
||||
*
|
||||
* <p>以下模式片段指定包含在此类中的预期内容。
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="getUserResponse">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="return" type="{http://model.webservice.xncoding.com/}user" minOccurs="0"/>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "getUserResponse", propOrder = {
|
||||
"_return"
|
||||
})
|
||||
public class GetUserResponse {
|
||||
|
||||
@XmlElement(name = "return")
|
||||
protected User _return;
|
||||
|
||||
/**
|
||||
* 获取return属性的值。
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link User }
|
||||
*
|
||||
*/
|
||||
public User getReturn() {
|
||||
return _return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置return属性的值。
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link User }
|
||||
*
|
||||
*/
|
||||
public void setReturn(User value) {
|
||||
this._return = value;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
|
||||
package com.xncoding.webservice.client;
|
||||
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.annotation.XmlElementDecl;
|
||||
import javax.xml.bind.annotation.XmlRegistry;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
|
||||
/**
|
||||
* This object contains factory methods for each
|
||||
* Java content interface and Java element interface
|
||||
* generated in the com.xncoding.webservice.client package.
|
||||
* <p>An ObjectFactory allows you to programatically
|
||||
* construct new instances of the Java representation
|
||||
* for XML content. The Java representation of XML
|
||||
* content can consist of schema derived interfaces
|
||||
* and classes representing the binding of schema
|
||||
* type definitions, element declarations and model
|
||||
* groups. Factory methods for each of these are
|
||||
* provided in this class.
|
||||
*
|
||||
*/
|
||||
@XmlRegistry
|
||||
public class ObjectFactory {
|
||||
|
||||
private final static QName _GetUser_QNAME = new QName("http://model.webservice.xncoding.com/", "getUser");
|
||||
private final static QName _GetUserResponse_QNAME = new QName("http://model.webservice.xncoding.com/", "getUserResponse");
|
||||
private final static QName _SayHello_QNAME = new QName("http://model.webservice.xncoding.com/", "sayHello");
|
||||
private final static QName _SayHelloResponse_QNAME = new QName("http://model.webservice.xncoding.com/", "sayHelloResponse");
|
||||
|
||||
/**
|
||||
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.xncoding.webservice.client
|
||||
*
|
||||
*/
|
||||
public ObjectFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link GetUserResponse }
|
||||
*
|
||||
*/
|
||||
public GetUserResponse createGetUserResponse() {
|
||||
return new GetUserResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link SayHello }
|
||||
*
|
||||
*/
|
||||
public SayHello createSayHello() {
|
||||
return new SayHello();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link GetUser }
|
||||
*
|
||||
*/
|
||||
public GetUser createGetUser() {
|
||||
return new GetUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link SayHelloResponse }
|
||||
*
|
||||
*/
|
||||
public SayHelloResponse createSayHelloResponse() {
|
||||
return new SayHelloResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link User }
|
||||
*
|
||||
*/
|
||||
public User createUser() {
|
||||
return new User();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link JAXBElement }{@code <}{@link GetUser }{@code >}}
|
||||
*
|
||||
*/
|
||||
@XmlElementDecl(namespace = "http://model.webservice.xncoding.com/", name = "getUser")
|
||||
public JAXBElement<GetUser> createGetUser(GetUser value) {
|
||||
return new JAXBElement<GetUser>(_GetUser_QNAME, GetUser.class, null, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link JAXBElement }{@code <}{@link GetUserResponse }{@code >}}
|
||||
*
|
||||
*/
|
||||
@XmlElementDecl(namespace = "http://model.webservice.xncoding.com/", name = "getUserResponse")
|
||||
public JAXBElement<GetUserResponse> createGetUserResponse(GetUserResponse value) {
|
||||
return new JAXBElement<GetUserResponse>(_GetUserResponse_QNAME, GetUserResponse.class, null, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link JAXBElement }{@code <}{@link SayHello }{@code >}}
|
||||
*
|
||||
*/
|
||||
@XmlElementDecl(namespace = "http://model.webservice.xncoding.com/", name = "sayHello")
|
||||
public JAXBElement<SayHello> createSayHello(SayHello value) {
|
||||
return new JAXBElement<SayHello>(_SayHello_QNAME, SayHello.class, null, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link JAXBElement }{@code <}{@link SayHelloResponse }{@code >}}
|
||||
*
|
||||
*/
|
||||
@XmlElementDecl(namespace = "http://model.webservice.xncoding.com/", name = "sayHelloResponse")
|
||||
public JAXBElement<SayHelloResponse> createSayHelloResponse(SayHelloResponse value) {
|
||||
return new JAXBElement<SayHelloResponse>(_SayHelloResponse_QNAME, SayHelloResponse.class, null, value);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
|
||||
package com.xncoding.webservice.client;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>sayHello complex type的 Java 类。
|
||||
*
|
||||
* <p>以下模式片段指定包含在此类中的预期内容。
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="sayHello">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="userName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "sayHello", propOrder = {
|
||||
"userName"
|
||||
})
|
||||
public class SayHello {
|
||||
|
||||
protected String userName;
|
||||
|
||||
/**
|
||||
* 获取userName属性的值。
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置userName属性的值。
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setUserName(String value) {
|
||||
this.userName = value;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
|
||||
package com.xncoding.webservice.client;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>sayHelloResponse complex type的 Java 类。
|
||||
*
|
||||
* <p>以下模式片段指定包含在此类中的预期内容。
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="sayHelloResponse">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="return" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "sayHelloResponse", propOrder = {
|
||||
"_return"
|
||||
})
|
||||
public class SayHelloResponse {
|
||||
|
||||
@XmlElement(name = "return")
|
||||
protected String _return;
|
||||
|
||||
/**
|
||||
* 获取return属性的值。
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getReturn() {
|
||||
return _return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置return属性的值。
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setReturn(String value) {
|
||||
this._return = value;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
|
||||
package com.xncoding.webservice.client;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>user complex type的 Java 类。
|
||||
*
|
||||
* <p>以下模式片段指定包含在此类中的预期内容。
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="user">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="age" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
|
||||
* <element name="id" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
|
||||
* <element name="name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "user", propOrder = {
|
||||
"age",
|
||||
"id",
|
||||
"name"
|
||||
})
|
||||
public class User {
|
||||
|
||||
protected Integer age;
|
||||
protected Long id;
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* 获取age属性的值。
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link Integer }
|
||||
*
|
||||
*/
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置age属性的值。
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link Integer }
|
||||
*
|
||||
*/
|
||||
public void setAge(Integer value) {
|
||||
this.age = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取id属性的值。
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link Long }
|
||||
*
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置id属性的值。
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link Long }
|
||||
*
|
||||
*/
|
||||
public void setId(Long value) {
|
||||
this.id = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取name属性的值。
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置name属性的值。
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setName(String value) {
|
||||
this.name = value;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
@javax.xml.bind.annotation.XmlSchema(namespace = "http://model.webservice.xncoding.com/")
|
||||
package com.xncoding.webservice.client;
|
||||
@ -0,0 +1,38 @@
|
||||
package com.xncoding.webservice.config;
|
||||
|
||||
import javax.xml.ws.Endpoint;
|
||||
|
||||
import org.apache.cxf.Bus;
|
||||
import org.apache.cxf.jaxws.EndpointImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import com.xncoding.webservice.service.ICommonService;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 默认服务在 Host:port/services/*** 路径下
|
||||
* 这里相当于把Commonservice接口发布在了路径/services/CommonService下
|
||||
* wsdl文档路径为http://localhost:8080/services/CommonService?wsdl
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/6/15
|
||||
*/
|
||||
@Configuration
|
||||
public class CxfConfig {
|
||||
@Autowired
|
||||
private Bus bus;
|
||||
|
||||
@Autowired
|
||||
ICommonService commonService;
|
||||
|
||||
/**
|
||||
* JAX-WS
|
||||
**/
|
||||
@Bean
|
||||
public Endpoint endpoint() {
|
||||
EndpointImpl endpoint = new EndpointImpl(bus, commonService);
|
||||
endpoint.publish("/CommonService");
|
||||
return endpoint;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.xncoding.webservice.model;
|
||||
|
||||
/**
|
||||
* 用户
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/3/4
|
||||
*/
|
||||
public class User {
|
||||
private Long id;
|
||||
private String name;
|
||||
private Integer age;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(Long id, String name, Integer age) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.xncoding.webservice.service;
|
||||
|
||||
import com.xncoding.webservice.model.User;
|
||||
|
||||
import javax.jws.WebMethod;
|
||||
import javax.jws.WebParam;
|
||||
import javax.jws.WebService;
|
||||
|
||||
/**
|
||||
* ICommonService
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/6/15
|
||||
*/
|
||||
@WebService(name = "CommonService", // 暴露服务名称
|
||||
targetNamespace = "http://model.webservice.xncoding.com/"// 命名空间,一般是接口的包名倒序
|
||||
)
|
||||
public interface ICommonService {
|
||||
@WebMethod
|
||||
// @WebResult(name = "String", targetNamespace = "")
|
||||
public String sayHello(@WebParam(name = "userName") String name);
|
||||
|
||||
@WebMethod
|
||||
// @WebResult(name = "String", targetNamespace = "")
|
||||
public User getUser(@WebParam(name = "userName") String name);
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.xncoding.webservice.service.impl;
|
||||
|
||||
import com.xncoding.webservice.model.User;
|
||||
import com.xncoding.webservice.service.ICommonService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.jws.WebService;
|
||||
|
||||
/**
|
||||
* CommonServiceImpl
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/6/15
|
||||
*/
|
||||
@WebService(serviceName = "CommonService", // 与接口中指定的name一致
|
||||
targetNamespace = "http://model.webservice.xncoding.com/", // 与接口中的命名空间一致,一般是接口的包名倒
|
||||
endpointInterface = "com.xncoding.webservice.service.ICommonService"// 接口地址
|
||||
)
|
||||
@Component
|
||||
public class CommonServiceImpl implements ICommonService {
|
||||
|
||||
@Override
|
||||
public String sayHello(String name) {
|
||||
return "Hello ," + name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUser(String name) {
|
||||
return new User(1000L, name, 23);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.xncoding.webservice.util;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* JacksonUtil
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/3/4
|
||||
*/
|
||||
public class JacksonUtil {
|
||||
private static ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public static String bean2Json(Object obj) {
|
||||
try {
|
||||
return mapper.writeValueAsString(obj);
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// public static <T> T json2Bean(String jsonStr, Class<T> objClass) {
|
||||
// try {
|
||||
// return mapper.readValue(jsonStr, objClass);
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
public static <T> T json2Bean(String jsonStr, TypeReference<T> typeReference) {
|
||||
try {
|
||||
return mapper.readValue(jsonStr, typeReference);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
springboot-cxf/src/main/resources/application.yml
Normal file
33
springboot-cxf/src/main/resources/application.yml
Normal file
@ -0,0 +1,33 @@
|
||||
##########################################################
|
||||
################## 所有profile共有的配置 #################
|
||||
##########################################################
|
||||
|
||||
################### 项目启动端口 ###################
|
||||
server.port: 8092
|
||||
|
||||
################### spring配置 ###################
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
|
||||
cxf:
|
||||
path: /services # 替换默认的/services路径
|
||||
|
||||
logging:
|
||||
level:
|
||||
org.springframework.web.servlet: ERROR
|
||||
|
||||
---
|
||||
|
||||
#####################################################################
|
||||
######################## 开发环境profile ##########################
|
||||
#####################################################################
|
||||
spring:
|
||||
profiles: dev
|
||||
|
||||
logging:
|
||||
level:
|
||||
ROOT: INFO
|
||||
com:
|
||||
xncoding: DEBUG
|
||||
file: E:/logs/app.log
|
||||
23
springboot-cxf/src/main/resources/banner.txt
Normal file
23
springboot-cxf/src/main/resources/banner.txt
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
_____ _______ _____ _____
|
||||
/\ \ /::\ \ /\ \ /\ \
|
||||
/::\____\ /::::\ \ /::\____\ /::\ \
|
||||
/:::/ / /::::::\ \ /:::/ / /::::\ \
|
||||
/:::/ / /::::::::\ \ /:::/ / /::::::\ \
|
||||
/:::/ / /:::/~~\:::\ \ /:::/ / /:::/\:::\ \
|
||||
/:::/ / /:::/ \:::\ \ /:::/____/ /:::/__\:::\ \
|
||||
/:::/ / /:::/ / \:::\ \ |::| | /::::\ \:::\ \
|
||||
/:::/ / /:::/____/ \:::\____\ |::| | _____ /::::::\ \:::\ \
|
||||
/:::/ / |:::| | |:::| | |::| | /\ \ /:::/\:::\ \:::\ \
|
||||
/:::/____/ |:::|____| |:::| | |::| | /::\____\/:::/__\:::\ \:::\____\
|
||||
\:::\ \ \:::\ \ /:::/ / |::| | /:::/ /\:::\ \:::\ \::/ /
|
||||
\:::\ \ \:::\ \ /:::/ / |::| | /:::/ / \:::\ \:::\ \/____/
|
||||
\:::\ \ \:::\ /:::/ / |::|____|/:::/ / \:::\ \:::\ \
|
||||
\:::\ \ \:::\__/:::/ / |:::::::::::/ / \:::\ \:::\____\
|
||||
\:::\ \ \::::::::/ / \::::::::::/____/ \:::\ \::/ /
|
||||
\:::\ \ \::::::/ / ~~~~~~~~~~ \:::\ \/____/
|
||||
\:::\ \ \::::/ / \:::\ \
|
||||
\:::\____\ \::/____/ \:::\____\
|
||||
\::/ / ~~ \::/ /
|
||||
\/____/ \/____/
|
||||
|
||||
@ -0,0 +1,112 @@
|
||||
package com.xncoding.webservice;
|
||||
|
||||
import com.xncoding.webservice.client.CommonService_Service;
|
||||
import com.xncoding.webservice.model.User;
|
||||
import com.xncoding.webservice.service.ICommonService;
|
||||
import org.apache.cxf.endpoint.Client;
|
||||
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
|
||||
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.context.embedded.LocalServerPort;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
public class ApplicationTests {
|
||||
@LocalServerPort
|
||||
private Integer port;
|
||||
/**
|
||||
* 接口地址
|
||||
*/
|
||||
private String wsdlAddress;
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
wsdlAddress = "http://localhost:" + port + "/services/CommonService?wsdl";
|
||||
}
|
||||
|
||||
/**
|
||||
* 方式1.代理类工厂的方式,需要拿到对方的接口
|
||||
*/
|
||||
@Test
|
||||
public void cl1() {
|
||||
try {
|
||||
// 接口地址
|
||||
// 代理工厂
|
||||
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
|
||||
// 设置代理地址
|
||||
jaxWsProxyFactoryBean.setAddress(wsdlAddress);
|
||||
// 设置接口类型
|
||||
jaxWsProxyFactoryBean.setServiceClass(ICommonService.class);
|
||||
// 创建一个代理接口实现
|
||||
ICommonService cs = (ICommonService) jaxWsProxyFactoryBean.create();
|
||||
// 数据准备
|
||||
String userName = "Leftso";
|
||||
// 调用代理接口的方法调用并返回结果
|
||||
String result = cs.sayHello(userName);
|
||||
System.out.println("返回结果:" + result);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 方式2. 动态调用方式
|
||||
*/
|
||||
@Test
|
||||
public void cl2() {
|
||||
// 创建动态客户端
|
||||
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
|
||||
Client client = dcf.createClient(wsdlAddress);
|
||||
// 需要密码的情况需要加上用户名和密码
|
||||
// client.getOutInterceptors().add(new ClientLoginInterceptor(USER_NAME, PASS_WORD));
|
||||
Object[] objects;
|
||||
try {
|
||||
// invoke("方法名",参数1,参数2,参数3....);
|
||||
objects = client.invoke("sayHello", "Leftso");
|
||||
System.out.println("返回类型:" + objects[0].getClass());
|
||||
System.out.println("返回数据:" + objects[0]);
|
||||
} catch (java.lang.Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 方式3. 动态调用方式,返回对象User
|
||||
*/
|
||||
@Test
|
||||
public void cl3() {
|
||||
// 创建动态客户端
|
||||
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
|
||||
Client client = dcf.createClient(wsdlAddress);
|
||||
Object[] objects;
|
||||
try {
|
||||
// invoke("方法名",参数1,参数2,参数3....);
|
||||
objects = client.invoke("getUser", "张三");
|
||||
System.out.println("返回类型:" + objects[0].getClass());
|
||||
System.out.println("返回数据:" + objects[0]);
|
||||
User user = (User) objects[0];
|
||||
System.out.println("返回对象User.name=" + user.getName());
|
||||
} catch (java.lang.Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 方式4. 客户端代码生成方式
|
||||
*/
|
||||
@Test
|
||||
public void cl4() {
|
||||
CommonService_Service c = new CommonService_Service();
|
||||
com.xncoding.webservice.client.User user = c.getCommonServiceImplPort().getUser("Tom");
|
||||
assertThat(user.getName(), is("Tom"));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Xiong Neng
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@ -0,0 +1,9 @@
|
||||
## RabbitMQ实现RPC调用客户端
|
||||
|
||||
消息队列RabbitMQ的使用例子,演示了RPC调用的客户端例子。
|
||||
|
||||
## 许可证
|
||||
|
||||
Copyright (c) 2018 Xiong Neng
|
||||
|
||||
基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>
|
||||
@ -0,0 +1,87 @@
|
||||
<?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>
|
||||
|
||||
<groupId>com.xncoding</groupId>
|
||||
<artifactId>springboot-rabbitmq-rpc-client</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>springboot-rabbitmq-rpc-client</name>
|
||||
<description>集成消息队列RabbitMQ RPC调用 - 客户端</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.10.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.vaadin.external.google</groupId>
|
||||
<artifactId>android-json</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<configuration>
|
||||
<!--<proc>none</proc>-->
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.20</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,12 @@
|
||||
package com.xncoding.pos;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
package com.xncoding.pos.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.amqp.core.AmqpTemplate;
|
||||
import org.springframework.amqp.core.AnonymousQueue;
|
||||
import org.springframework.amqp.core.Queue;
|
||||
import org.springframework.amqp.rabbit.AsyncRabbitTemplate;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
||||
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* RabbitConfig
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/3/1
|
||||
*/
|
||||
@Configuration
|
||||
public class RabbitConfig {
|
||||
/**
|
||||
* 同步RPC队列
|
||||
*/
|
||||
public static final String QUEUE_SYNC_RPC = "rpc.sync";
|
||||
|
||||
/**
|
||||
* 异步RPC队列,使用临时回复队列,或者使用“Direct reply-to”特性
|
||||
*/
|
||||
public static final String QUEUE_ASYNC_RPC = "rpc.async";
|
||||
|
||||
/**
|
||||
* 异步RPC队列,每个客户端使用不同的固定回复队列,需要额外提供correlationId以关联请求和响应
|
||||
*/
|
||||
public static final String QUEUE_ASYNC_RPC_WITH_FIXED_REPLY = "rpc.with.fixed.reply";
|
||||
|
||||
@Bean
|
||||
public Queue syncRPCQueue() {
|
||||
return new Queue(QUEUE_SYNC_RPC);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue asyncRPCQueue() {
|
||||
return new Queue(QUEUE_ASYNC_RPC);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue fixedReplyRPCQueue() {
|
||||
return new Queue(QUEUE_ASYNC_RPC_WITH_FIXED_REPLY);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue repliesQueue() {
|
||||
return new AnonymousQueue();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageConverter jsonMessageConverter(){
|
||||
return new Jackson2JsonMessageConverter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public SimpleMessageListenerContainer replyContainer(ConnectionFactory connectionFactory) {
|
||||
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
|
||||
container.setQueueNames(repliesQueue().getName());
|
||||
return container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
|
||||
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
|
||||
rabbitTemplate.setMessageConverter(jsonMessageConverter());
|
||||
return rabbitTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AsyncRabbitTemplate asyncRabbitTemplate(RabbitTemplate template, SimpleMessageListenerContainer container) {
|
||||
return new AsyncRabbitTemplate(template, container);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.xncoding.pos.model;
|
||||
|
||||
/**
|
||||
* User
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/5/17
|
||||
*/
|
||||
public class User {
|
||||
private String name;
|
||||
private Integer age;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.xncoding.pos.service;
|
||||
|
||||
import com.xncoding.pos.model.User;
|
||||
import com.xncoding.pos.util.StringUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.amqp.core.AmqpTemplate;
|
||||
import org.springframework.amqp.core.MessagePostProcessor;
|
||||
import org.springframework.amqp.rabbit.AsyncRabbitTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.AsyncResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static com.xncoding.pos.config.RabbitConfig.QUEUE_ASYNC_RPC;
|
||||
import static com.xncoding.pos.config.RabbitConfig.QUEUE_ASYNC_RPC_WITH_FIXED_REPLY;
|
||||
|
||||
/**
|
||||
* 消息发送服务
|
||||
*/
|
||||
@Service
|
||||
public class SenderService {
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
@Autowired
|
||||
AsyncRabbitTemplate asyncRabbitTemplate;
|
||||
|
||||
@Autowired
|
||||
AmqpTemplate amqpTemplate;
|
||||
|
||||
@Async
|
||||
public Future<String> sendAsync(User message) {
|
||||
// String result = (String) amqpTemplate.convertSendAndReceive(QUEUE_ASYNC_RPC, message, m -> {
|
||||
// m.getMessageProperties().setCorrelationIdString(StringUtil.generateUUId());
|
||||
// return m;
|
||||
// });
|
||||
String result = (String) amqpTemplate.convertSendAndReceive(QUEUE_ASYNC_RPC, message);
|
||||
return new AsyncResult<>(result);
|
||||
}
|
||||
|
||||
public Future<String> sendWithFixedReplay(User message) {
|
||||
// ListenableFuture<String> future = asyncRabbitTemplate.convertSendAndReceive(QUEUE_ASYNC_RPC_WITH_FIXED_REPLY, message, m -> {
|
||||
// m.getMessageProperties().setCorrelationIdString(StringUtil.generateUUId());
|
||||
// return m;
|
||||
// });
|
||||
return asyncRabbitTemplate.convertSendAndReceive(QUEUE_ASYNC_RPC_WITH_FIXED_REPLY, message);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.xncoding.pos.util;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* StringUtil
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/5/17
|
||||
*/
|
||||
public class StringUtil {
|
||||
public static String generateUUId() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
##########################################################
|
||||
################## 所有profile共有的配置 #################
|
||||
##########################################################
|
||||
|
||||
################### spring配置 ###################
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
|
||||
---
|
||||
|
||||
#####################################################################
|
||||
######################## 开发环境profile ##########################
|
||||
#####################################################################
|
||||
spring:
|
||||
profiles: dev
|
||||
rabbitmq:
|
||||
host: 119.29.12.177
|
||||
port: 5672
|
||||
username: guest
|
||||
password: guest
|
||||
|
||||
logging:
|
||||
level:
|
||||
ROOT: INFO
|
||||
com:
|
||||
xncoding: DEBUG
|
||||
file: D:/logs/rabbitmq-rpc-client.log
|
||||
|
||||
@ -0,0 +1,90 @@
|
||||
package com.xncoding.service;
|
||||
|
||||
import com.xncoding.pos.Application;
|
||||
import com.xncoding.pos.model.User;
|
||||
import com.xncoding.pos.service.SenderService;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
|
||||
/**
|
||||
* SenderServiceTest
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/2/2
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Application.class)
|
||||
public class SenderServiceTest {
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(getClass());
|
||||
@Autowired
|
||||
private SenderService senderService;
|
||||
|
||||
private List<User> users;
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
users = new ArrayList<>();
|
||||
User user1 = new User();
|
||||
user1.setName("用户1");
|
||||
user1.setAge(19);
|
||||
users.add(user1);
|
||||
|
||||
User user2 = new User();
|
||||
user2.setName("用户2");
|
||||
user2.setAge(20);
|
||||
users.add(user2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendAsync() throws InterruptedException, ExecutionException {
|
||||
|
||||
List<Future<String>> results = new ArrayList<>();
|
||||
for (User user : users) {
|
||||
Future<String> result = senderService.sendAsync(user);
|
||||
results.add(result);
|
||||
}
|
||||
for (Future<String> future : results) {
|
||||
String result = future.get();
|
||||
if (result == null) {
|
||||
Assert.fail("message will not timeout");
|
||||
} else {
|
||||
logger.info("tttttttttttt=" + result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendWithFixedReplay() throws InterruptedException, ExecutionException{
|
||||
List<Future<String>> results = new ArrayList<>();
|
||||
for (User user : users) {
|
||||
Future<String> result = senderService.sendWithFixedReplay(user);
|
||||
results.add(result);
|
||||
}
|
||||
for (Future<String> future : results) {
|
||||
String result = future.get();
|
||||
if (result == null) {
|
||||
Assert.fail("message will not timeout");
|
||||
} else {
|
||||
logger.info("tttttttttttt=" + result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Xiong Neng
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@ -0,0 +1,9 @@
|
||||
## RabbitMQ实现RPC调用服务端
|
||||
|
||||
消息队列RabbitMQ的使用例子,演示了RPC调用的服务端例子。
|
||||
|
||||
## 许可证
|
||||
|
||||
Copyright (c) 2018 Xiong Neng
|
||||
|
||||
基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>
|
||||
@ -0,0 +1,87 @@
|
||||
<?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>
|
||||
|
||||
<groupId>com.xncoding</groupId>
|
||||
<artifactId>springboot-rabbitmq-rpc-server</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>springboot-rabbitmq-rpc-server</name>
|
||||
<description>集成消息队列RabbitMQ RPC - 服务端</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.10.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.vaadin.external.google</groupId>
|
||||
<artifactId>android-json</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<configuration>
|
||||
<!--<proc>none</proc>-->
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.20</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,12 @@
|
||||
package com.xncoding.pos;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.xncoding.pos.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* ExecutorConfig
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/5/17
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
public class ExecutorConfig {
|
||||
/**
|
||||
* Set the ThreadPoolExecutor's core pool size.
|
||||
*/
|
||||
private int corePoolSize = 10;
|
||||
/**
|
||||
* Set the ThreadPoolExecutor's maximum pool size.
|
||||
*/
|
||||
private int maxPoolSize = 200;
|
||||
/**
|
||||
* Set the capacity for the ThreadPoolExecutor's BlockingQueue.
|
||||
*/
|
||||
private int queueCapacity = 10;
|
||||
|
||||
// @Bean
|
||||
// public Executor mySimpleAsync() {
|
||||
// ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
// executor.setCorePoolSize(corePoolSize);
|
||||
// executor.setMaxPoolSize(maxPoolSize);
|
||||
// executor.setQueueCapacity(queueCapacity);
|
||||
// executor.setThreadNamePrefix("MySimpleExecutor-");
|
||||
// executor.initialize();
|
||||
// return executor;
|
||||
// }
|
||||
|
||||
@Bean
|
||||
public Executor myAsync() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(corePoolSize);
|
||||
executor.setMaxPoolSize(maxPoolSize);
|
||||
executor.setQueueCapacity(queueCapacity);
|
||||
executor.setThreadNamePrefix("MyExecutor-");
|
||||
|
||||
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
|
||||
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
package com.xncoding.pos.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.amqp.core.*;
|
||||
import org.springframework.amqp.rabbit.AsyncRabbitTemplate;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
||||
import org.springframework.amqp.rabbit.support.DefaultMessagePropertiesConverter;
|
||||
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* RabbitConfig
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/3/1
|
||||
*/
|
||||
@Configuration
|
||||
public class RabbitConfig {
|
||||
/**
|
||||
* 同步RPC队列
|
||||
*/
|
||||
public static final String QUEUE_SYNC_RPC = "rpc.sync";
|
||||
|
||||
/**
|
||||
* 异步RPC队列,使用临时回复队列,或者使用“Direct reply-to”特性
|
||||
*/
|
||||
public static final String QUEUE_ASYNC_RPC = "rpc.async";
|
||||
|
||||
/**
|
||||
* 异步RPC队列,每个客户端使用不同的固定回复队列,需要额外提供correlationId以关联请求和响应
|
||||
*/
|
||||
public static final String QUEUE_ASYNC_RPC_WITH_FIXED_REPLY = "rpc.with.fixed.reply";
|
||||
|
||||
@Bean
|
||||
public Queue syncRPCQueue() {
|
||||
return new Queue(QUEUE_SYNC_RPC);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue asyncRPCQueue() {
|
||||
return new Queue(QUEUE_ASYNC_RPC);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue fixedReplyRPCQueue() {
|
||||
return new Queue(QUEUE_ASYNC_RPC_WITH_FIXED_REPLY);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue repliesQueue() {
|
||||
return new AnonymousQueue();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageConverter jsonMessageConverter(){
|
||||
return new Jackson2JsonMessageConverter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public SimpleMessageListenerContainer replyContainer(ConnectionFactory connectionFactory) {
|
||||
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
|
||||
container.setQueueNames(repliesQueue().getName());
|
||||
return container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
|
||||
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
|
||||
rabbitTemplate.setMessageConverter(jsonMessageConverter());
|
||||
return rabbitTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AsyncRabbitTemplate asyncRabbitTemplate(RabbitTemplate template, SimpleMessageListenerContainer container) {
|
||||
return new AsyncRabbitTemplate(template, container);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.xncoding.pos.model;
|
||||
|
||||
/**
|
||||
* User
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/5/17
|
||||
*/
|
||||
public class User {
|
||||
private String name;
|
||||
private Integer age;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
package com.xncoding.pos.server;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.xncoding.pos.model.User;
|
||||
import com.xncoding.pos.util.JacksonUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.amqp.AmqpException;
|
||||
import org.springframework.amqp.core.AmqpTemplate;
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.core.MessagePostProcessor;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.amqp.support.AmqpHeaders;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.handler.annotation.Header;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import static com.xncoding.pos.config.RabbitConfig.QUEUE_ASYNC_RPC;
|
||||
import static com.xncoding.pos.config.RabbitConfig.QUEUE_ASYNC_RPC_WITH_FIXED_REPLY;
|
||||
|
||||
|
||||
@Component
|
||||
public class AsyncRPCServer {
|
||||
|
||||
@Autowired
|
||||
AmqpTemplate amqpTemplate;
|
||||
|
||||
@Autowired
|
||||
AsyncTask asyncTask;
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@RabbitListener(queues = QUEUE_ASYNC_RPC)
|
||||
public void processAsyncRpc(Message message, @Header(AmqpHeaders.REPLY_TO) String replyTo) {
|
||||
String body = new String(message.getBody(), Charset.forName("UTF-8"));
|
||||
User user = JacksonUtil.json2Bean(body, new TypeReference<User>(){});
|
||||
logger.info("recevie message {} and reply to {}, user.name={}", body, replyTo, user.getName());
|
||||
if (replyTo.startsWith("amq.rabbitmq.reply-to")) {
|
||||
logger.debug("starting with version 3.4.0, the RabbitMQ server now supports Direct reply-to");
|
||||
} else {
|
||||
logger.info("fall back to using a temporary reply queue");
|
||||
}
|
||||
ListenableFuture<String> asyncResult = asyncTask.expensiveOperation(body);
|
||||
asyncResult.addCallback(new ListenableFutureCallback<String>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
amqpTemplate.convertAndSend(replyTo, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
logger.error("接受到QUEUE_ASYNC_RPC失败", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@RabbitListener(queues = QUEUE_ASYNC_RPC_WITH_FIXED_REPLY)
|
||||
public void processAsyncRpcFixed(User user,
|
||||
@Header(AmqpHeaders.REPLY_TO) String replyTo,
|
||||
@Header(AmqpHeaders.CORRELATION_ID) byte[] correlationId) {
|
||||
// String body = new String(message.getBody(), Charset.forName("UTF-8"));
|
||||
// User user = JacksonUtil.json2Bean(body, new TypeReference<User>(){});
|
||||
logger.info("user.name={}", user.getName());
|
||||
logger.info("use a fixed reply queue={}, correlationId={}", replyTo, new String(correlationId));
|
||||
ListenableFuture<String> asyncResult = asyncTask.expensiveOperation(user.getName());
|
||||
asyncResult.addCallback(new ListenableFutureCallback<String>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
amqpTemplate.convertAndSend(replyTo, (Object) result, m -> {
|
||||
//https://stackoverflow.com/questions/42382307/messageproperties-setcorrelationidstring-is-not-working
|
||||
m.getMessageProperties().setCorrelationId(correlationId);
|
||||
return m;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
logger.error("接受到QUEUE_ASYNC_RPC_WITH_FIXED_REPLY失败", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.xncoding.pos.server;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.AsyncResult;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
@Component
|
||||
public class AsyncTask {
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Async
|
||||
public ListenableFuture<String> expensiveOperation(String message) {
|
||||
int millis = (int) (Math.random() * 5 * 1000);
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
String result = message + " executed by " + Thread.currentThread().getName() + " for " + millis + " ms";
|
||||
logger.info("task result {}", result);
|
||||
return new AsyncResult<String>(result);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.xncoding.pos.util;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* JacksonUtil
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/3/4
|
||||
*/
|
||||
public class JacksonUtil {
|
||||
private static ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public static String bean2Json(Object obj) {
|
||||
try {
|
||||
return mapper.writeValueAsString(obj);
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// public static <T> T json2Bean(String jsonStr, Class<T> objClass) {
|
||||
// try {
|
||||
// return mapper.readValue(jsonStr, objClass);
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
public static <T> T json2Bean(String jsonStr, TypeReference<T> typeReference) {
|
||||
try {
|
||||
return mapper.readValue(jsonStr, typeReference);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
##########################################################
|
||||
################## 所有profile共有的配置 #################
|
||||
##########################################################
|
||||
|
||||
################### spring配置 ###################
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
|
||||
---
|
||||
|
||||
#####################################################################
|
||||
######################## 开发环境profile ##########################
|
||||
#####################################################################
|
||||
spring:
|
||||
profiles: dev
|
||||
rabbitmq:
|
||||
host: 119.29.12.177
|
||||
port: 5672
|
||||
username: guest
|
||||
password: guest
|
||||
# publisher-confirms: true #支持发布确认
|
||||
# publisher-returns: true #支持发布返回
|
||||
# listener:
|
||||
# simple:
|
||||
# acknowledge-mode: manual #采用手动应答
|
||||
# concurrency: 1 #指定最小的消费者数量
|
||||
# max-concurrency: 20 #指定最大的消费者数量
|
||||
# retry:
|
||||
# enabled: true #是否支持重试
|
||||
|
||||
logging:
|
||||
level:
|
||||
ROOT: INFO
|
||||
com:
|
||||
xncoding: DEBUG
|
||||
file: D:/logs/rabbitmq-rpc-server.log
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.3.6</version>
|
||||
<version>4.5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@ -6,16 +6,31 @@ import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.TrustStrategy;
|
||||
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* RestTemplate客户端连接池配置
|
||||
*
|
||||
@ -26,34 +41,43 @@ import org.springframework.web.client.RestTemplate;
|
||||
@Configuration
|
||||
public class RestClientConfig {
|
||||
@Bean
|
||||
public ClientHttpRequestFactory httpRequestFactory() {
|
||||
return new HttpComponentsClientHttpRequestFactory(httpClient());
|
||||
public RestTemplate restTemplate() {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
restTemplate.setRequestFactory(clientHttpRequestFactory());
|
||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(RestTemplateBuilder builder) {
|
||||
return new RestTemplate(httpRequestFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HttpClient httpClient() {
|
||||
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
|
||||
.register("http", PlainConnectionSocketFactory.getSocketFactory())
|
||||
.register("https", SSLConnectionSocketFactory.getSocketFactory())
|
||||
.build();
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
|
||||
connectionManager.setMaxTotal(5);
|
||||
connectionManager.setDefaultMaxPerRoute(5);
|
||||
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setSocketTimeout(8000)
|
||||
.setConnectTimeout(8000)
|
||||
.setConnectionRequestTimeout(8000)
|
||||
.build();
|
||||
|
||||
return HttpClientBuilder.create()
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.setConnectionManager(connectionManager)
|
||||
.build();
|
||||
public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
|
||||
try {
|
||||
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
|
||||
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
|
||||
public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
|
||||
return true;
|
||||
}
|
||||
}).build();
|
||||
httpClientBuilder.setSSLContext(sslContext);
|
||||
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
|
||||
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
|
||||
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
|
||||
.register("http", PlainConnectionSocketFactory.getSocketFactory())
|
||||
.register("https", sslConnectionSocketFactory).build();// 注册http和https请求
|
||||
// 开始设置连接池
|
||||
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
|
||||
poolingHttpClientConnectionManager.setMaxTotal(500); // 最大连接数500
|
||||
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); // 同路由并发数100
|
||||
httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
|
||||
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)); // 重试次数
|
||||
HttpClient httpClient = httpClientBuilder.build();
|
||||
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // httpClient连接配置
|
||||
clientHttpRequestFactory.setConnectTimeout(20000); // 连接超时
|
||||
clientHttpRequestFactory.setReadTimeout(30000); // 数据读取超时时间
|
||||
clientHttpRequestFactory.setConnectionRequestTimeout(20000); // 连接不够用的等待时间
|
||||
return clientHttpRequestFactory;
|
||||
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
|
||||
log.error("初始化HTTP连接池出错", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,3 +71,13 @@ CREATE TABLE `t_role_permission` (
|
||||
INSERT INTO `t_role_permission` VALUES (1, 1, 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');
|
||||
INSERT INTO `t_role_permission` VALUES (2, 1, 3, '2017-12-12 09:46:12', '2017-12-12 09:46:12');
|
||||
INSERT INTO `t_role_permission` VALUES (3, 2, 2, '2017-12-12 09:46:12', '2017-12-12 09:46:12');
|
||||
|
||||
-- 项目用户关联表
|
||||
DROP TABLE IF EXISTS `t_project_user`;
|
||||
CREATE TABLE `t_project_user` (
|
||||
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
|
||||
`user_id` INT(11) NOT NULL COMMENT '用户ID',
|
||||
`project_id` INT(11) NOT NULL COMMENT '项目ID',
|
||||
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='项目用户关联表';
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package com.xncoding.jwt.commons;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* JacksonUtil
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/3/4
|
||||
*/
|
||||
public class JacksonUtil {
|
||||
private static ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public static String bean2Json(Object obj) {
|
||||
try {
|
||||
return mapper.writeValueAsString(obj);
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// public static <T> T json2Bean(String jsonStr, Class<T> objClass) {
|
||||
// try {
|
||||
// return mapper.readValue(jsonStr, objClass);
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
public static <T> T json2Bean(String jsonStr, TypeReference<T> typeReference) {
|
||||
try {
|
||||
return mapper.readValue(jsonStr, typeReference);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,31 +1,25 @@
|
||||
package com.xncoding.jwt.config;
|
||||
|
||||
import com.xncoding.jwt.handler.SocketHandler;
|
||||
import com.xncoding.jwt.interceptor.WebSocketInterceptor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||
|
||||
/**
|
||||
* WebSocketConfig
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/2/28
|
||||
* @since 2018/3/22
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
|
||||
stompEndpointRegistry.addEndpoint("/simple")
|
||||
.setAllowedOrigins("*") //解决跨域问题
|
||||
.withSockJS();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableSimpleBroker("/topic");
|
||||
@EnableWebSocket
|
||||
public class WebSocketConfig implements WebSocketConfigurer {
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||
registry.addHandler(new SocketHandler(), "/app")
|
||||
.addInterceptors(new WebSocketInterceptor())
|
||||
.setAllowedOrigins("*");
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package com.xncoding.jwt.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
|
||||
/**
|
||||
* STOMP协议的WebStocket
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/2/28
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
public class WebSocketStompConfig extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
|
||||
stompEndpointRegistry.addEndpoint("/simple")
|
||||
.setAllowedOrigins("*") //解决跨域问题
|
||||
.withSockJS();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableSimpleBroker("/topic");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
package com.xncoding.jwt.handler;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.xncoding.jwt.commons.JacksonUtil;
|
||||
import com.xncoding.jwt.model.WsParam;
|
||||
import com.xncoding.jwt.model.WsResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* SocketHandler
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/3/22
|
||||
*/
|
||||
@Component
|
||||
public class SocketHandler extends TextWebSocketHandler {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Override
|
||||
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
logger.info("handleTextMessage start");
|
||||
// 将消息进行转化,因为是消息是json数据,可能里面包含了发送给某个人的信息,所以需要用json相关的工具类处理之后再封装成TextMessage,
|
||||
// 我这儿并没有做处理,消息的封装格式一般有{from:xxxx,to:xxxxx,msg:xxxxx},来自哪里,发送给谁,什么消息等等
|
||||
String msg = message.getPayload();
|
||||
logger.info("msg = " + msg);
|
||||
WsParam<String> wsParam = JacksonUtil.json2Bean(msg, new TypeReference<WsParam<String>>(){});
|
||||
if ("list".equals(wsParam.getMethod())) {
|
||||
logger.info("call list method...");
|
||||
WsResponse<String> response = new WsResponse<>();
|
||||
response.setResult("hello list");
|
||||
sendMessageToUser(session, new TextMessage(JacksonUtil.bean2Json(response)));
|
||||
}
|
||||
logger.info("handleTextMessage end");
|
||||
// 给所有用户群发消息
|
||||
//sendMessagesToUsers(msg);
|
||||
// 给指定用户群发消息
|
||||
//sendMessageToUser(userId, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
logger.info("Connected ... " + session.getId());
|
||||
sessions.add(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
||||
if (session.isOpen()) {
|
||||
session.close();
|
||||
}
|
||||
sessions.remove(session);
|
||||
logger.info(String.format("Session %s closed because of %s", session.getId(), status.getReason()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(WebSocketSession session, Throwable throwable) throws Exception {
|
||||
logger.error("error occured at sender " + session, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 给所有的用户发送消息
|
||||
*/
|
||||
public void sendMessagesToUsers(TextMessage message) {
|
||||
for (WebSocketSession user : sessions) {
|
||||
try {
|
||||
// isOpen()在线就发送
|
||||
if (user.isOpen()) {
|
||||
user.sendMessage(message);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息给指定的用户
|
||||
*/
|
||||
private void sendMessageToUser(WebSocketSession user, TextMessage message) {
|
||||
try {
|
||||
// 在线就发送
|
||||
if (user.isOpen()) {
|
||||
user.sendMessage(message);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("发送消息给指定的用户出错", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.xncoding.jwt.interceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.server.HandshakeInterceptor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* WebSocketInterceptor
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/3/22
|
||||
*/
|
||||
public class WebSocketInterceptor implements HandshakeInterceptor {
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
@Override
|
||||
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse arg1,
|
||||
WebSocketHandler arg2, Map<String, Object> arg3) throws Exception {
|
||||
// 将ServerHttpRequest转换成request请求相关的类,用来获取request域中的用户信息
|
||||
if (request instanceof ServletServerHttpRequest) {
|
||||
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
|
||||
HttpServletRequest httpRequest = servletRequest.getServletRequest();
|
||||
}
|
||||
logger.info("beforeHandshake完成");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterHandshake(ServerHttpRequest arg0, ServerHttpResponse arg1, WebSocketHandler arg2, Exception arg3) {
|
||||
logger.info("afterHandshake完成");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.xncoding.jwt.model;
|
||||
|
||||
/**
|
||||
* WsParam
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/3/22
|
||||
*/
|
||||
public class WsParam<T> {
|
||||
private String method;
|
||||
private T param;
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public T getParam() {
|
||||
return param;
|
||||
}
|
||||
|
||||
public void setParam(T param) {
|
||||
this.param = param;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.xncoding.jwt.model;
|
||||
|
||||
/**
|
||||
* WsResponse
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/3/22
|
||||
*/
|
||||
public class WsResponse<T> {
|
||||
private T result;
|
||||
|
||||
public T getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>广播式WebSocket</title>
|
||||
<script src="js/sockjs.min.js"></script>
|
||||
<script src="js/jquery-3.1.1.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript><h2 style="color: #e80b0a;">Sorry,浏览器不支持WebSocket</h2></noscript>
|
||||
<div>
|
||||
<div>
|
||||
<button id="connect" onclick="connect();">连接</button>
|
||||
<button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接</button>
|
||||
</div>
|
||||
|
||||
<div id="conversationDiv">
|
||||
<label>输入你的名字</label><input type="text" id="name"/>
|
||||
<button id="sendName" onclick="sendName();">发送</button>
|
||||
<p id="response"></p>
|
||||
<p id="callback"></p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var curTryNum = 0;
|
||||
var url = 'ws://localhost:8282/app';
|
||||
var ws;
|
||||
function connect() {
|
||||
ws = new WebSocket(url);
|
||||
/**
|
||||
* 因为服务端在 300s 未传输数据时会主动关闭连接,所以,客户端需要定时发送数据保持连接。
|
||||
*/
|
||||
var heartCheck = {
|
||||
timeout: 50000, //50s
|
||||
timeoutObj: null,
|
||||
reset: function(){
|
||||
clearInterval(this.timeoutObj);
|
||||
this.start();
|
||||
},
|
||||
start: function(){
|
||||
this.timeoutObj = setInterval(function(){
|
||||
if(ws.readyState === 1){
|
||||
ws.send("hb");
|
||||
}
|
||||
}, this.timeout)
|
||||
}
|
||||
};
|
||||
ws.onopen = function (evnt) {
|
||||
console.log("onopen: ", evnt);
|
||||
heartCheck.start();
|
||||
};
|
||||
ws.onmessage = function(message){
|
||||
// 无论收到什么信息,说明当前连接正常,将心跳检测的计时器重置
|
||||
heartCheck.reset();
|
||||
console.log("client received a message.data: " + message.data);
|
||||
if (message.data !== "hb_ok") {
|
||||
// 不要将ping的答复信息输出
|
||||
console.log("msg = " + JSON.stringify(message.data));
|
||||
var response = JSON.parse(message.data);
|
||||
console.log("message.data.method = " + response.method);
|
||||
showResponse(JSON.stringify(response.result));
|
||||
}
|
||||
};
|
||||
ws.onclose = function (event) {
|
||||
if (event.code !== 4500) {
|
||||
//4500为服务端在打开多tab时主动关闭返回的编码
|
||||
connect();
|
||||
}
|
||||
};
|
||||
setConnected(true);
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
if (ws != null) {
|
||||
ws.close();
|
||||
}
|
||||
setConnected(false);
|
||||
console.log("Disconnected");
|
||||
}
|
||||
|
||||
function sendName() {
|
||||
var data = {
|
||||
"method": "list",
|
||||
"param": $("#name").val()
|
||||
};
|
||||
ws.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
function showResponse(message) {
|
||||
$("#response").html(message);
|
||||
}
|
||||
function showCallback(message) {
|
||||
$("#callback").html(message);
|
||||
}
|
||||
function setConnected(connected) {
|
||||
document.getElementById("connect").disabled = connected;
|
||||
document.getElementById("disconnect").disabled = !connected;
|
||||
document.getElementById("conversationDiv").style.visibility = connected ? 'visible' : 'hidden';
|
||||
$("#response").html();
|
||||
$("#callback").html();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user