在 zuul 网关中获取到用户访问的数据,保存到 es 中。服务间的交互采用 stream。
spring cloud 工程。
search 模块。
虚拟机中开启 rabbitmq 和 elasticsearch。
// pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.5.4</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.5.4</version>
</dependency>
// application.yml
server:
port: 8086
spring:
rabbitmq:
host: 11.36.144.157
port: 5672
username: test
password: test
virtual-host: /virtual2
data:
elasticsearch:
host: 11.36.144.157
port: 9200
index: openapi-index
type: openapi-type
application:
name: openapi-search
eureka:
client:
service-url:
defaultZone: http://localhost:8080/eureka
// SearchApplication.java
@SpringBootApplication
@EnableEurekaClient
public class SearchApplication {
public static void main(String[] args) {
SpringApplication.run(SearchApplication.class, args);
}
}
// EsConfig.java
@Configuration
public class EsConfig {
@Value("${spring.data.elasticsearch.host}")
private String host;
@Value("${spring.data.elasticsearch.port}")
private int port;
@Bean
public RestHighLevelClient restHighLevelClient() {
HttpHost httpHost = new HttpHost(host, port);
RestClientBuilder builder = RestClient.builder(httpHost);
RestHighLevelClient client = new RestHighLevelClient(builder);
return client;
}
}
// SearchUtils.java
public class SearchUtils {
public static void create(String index, String type, RestHighLevelClient restHighLevelClient) throws IOException {
Settings.Builder settings = Settings.builder()
.put("number_of_shards", 3)
.put("number_of_replicas", 1);
XContentBuilder contentBuilder = JsonXContent.contentBuilder()
.startObject()
.startObject("properties")
.startObject("apiName")
.field("type", "keyword")
.endObject()
.startObject("app_key")
.field("type", "keyword")
.endObject()
.startObject("content")
.field("type", "text")
// .field("analyzer", "ik_max_word")
.endObject()
.startObject("remoteIp")
.field("type", "ip")
.endObject()
.startObject("responseTime")
.field("type", "date")
.field("format","yyyy-MM-dd HH:mm:ss")
.endObject()
.startObject("receiveTime")
.field("type", "date")
.field("format","yyyy-MM-dd HH:mm:ss")
.endObject()
.startObject("serverIp")
.field("type", "ip")
.endObject()
.startObject("totalTime")
.field("type", "long")
.endObject()
.endObject()
.endObject();
CreateIndexRequest request = new CreateIndexRequest(index)
.settings(settings)
.mapping(type,contentBuilder);
restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
}
}
// SearchService.java
public interface SearchService {
void createIndex() throws IOException;
boolean isExists() throws IOException;
void add(String json) throws IOException;
}
// SearchServiceImpl.java
@Service
public class SearchServiceImpl implements SearchService {
@Value("${spring.data.elasticsearch.index}")
private String index;
@Value("${spring.data.elasticsearch.type}")
private String type;
@Autowired
private RestHighLevelClient highLevelClient;
@Override
public void createIndex() throws IOException {
if (!isExists()) {
SearchUtils.create(index, type, highLevelClient);
}
}
@Override
public boolean isExists() throws IOException {
GetIndexRequest request = new GetIndexRequest();
request.indices(index);
return highLevelClient.indices().exists(request, RequestOptions.DEFAULT);
}
@Override
public void add(String json) throws IOException {
IndexRequest request = new IndexRequest(index, type);
request.source(json, XContentType.JSON);
highLevelClient.index(request, RequestOptions.DEFAULT);
}
}
// ReceiveMessageStream.java
public interface ReceiveMessageStream {
@Input("openapilog")
SubscribableChannel subscribable_channel();
}
// ReceiveMessageListener.java
@Component
@EnableBinding(ReceiveMessageStream.class)
public class ReceiveMessageListener {
@Autowired
private SearchService searchService;
@StreamListener("openapilog")
public void receive(String json) {
try {
searchService.add(json);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// SearchController.java
@RestController
@RequestMapping("/search")
public class SearchController {
@Autowired
private SearchService searchService;
@RequestMapping("/createIndex")
public String createIndex() {
try {
searchService.createIndex();
return "success";
} catch (IOException e) {
e.printStackTrace();
}
return "faild";
}
}
gateway 网关模块。
// pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
// application.yml
server:
port: 8085
spring:
application:
name: openapi-gateway
rabbitmq:
host: 11.36.144.157
port: 5672
username: test
password: test
virtual-host: /virtual2
eureka:
client:
service-url:
defaultZone: http://localhost:8080/eureka
# zuul actuator 监控,http://localhost/actuator/routes
management:
endpoints:
web:
exposure:
include: "*"
#zuul:
# ignored-services: "*"
// SendMessageStream.java
public interface SendMessageStream {
@Output("openapilog")
MessageChannel message_channel();
}
// GatewayController.java
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
@EnableBinding(SendMessageStream.class)
public class GatewayController {
public static void main(String[] args) {
SpringApplication.run(GatewayController.class, args);
}
}
// LoggerBean.java
@Data
public class LoggerBean {
private String apiName;
private String app_key;
private String content;
private String remoteIp;
private String serverIp;
private long totalTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date responseTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date receiveTime;
}
// LoggerPreFilter.java
@Component
public class LoggerPreFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 10;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
// 保存开始时间
RequestContext.getCurrentContext().set("startTime", new Date());
return null;
}
}
// LoggerFilter.java
@Component
public class LoggerFilter extends ZuulFilter {
@Autowired
private SendMessageStream sendMessageStream;
@Autowired
private ObjectMapper objectMapper;
@Override
public String filterType() {
// 后置过滤器
return FilterConstants.POST_TYPE;
}
@Override
public int filterOrder() {
return 10;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
String method = request.getParameter("method");
String appkey = request.getParameter("appkey");
LoggerBean loggerBean = new LoggerBean();
loggerBean.setApiName(method);
loggerBean.setApp_key(appkey);
// 请求的参数
loggerBean.setContent(request.getQueryString());
loggerBean.setRemoteIp(request.getRemoteAddr());
try {
// 服务器 ip
loggerBean.setServerIp(InetAddress.getLocalHost().getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
}
Date now = new Date();
loggerBean.setResponseTime(now);
Date startDate = (Date)currentContext.get("startTime");
loggerBean.setReceiveTime(startDate);
loggerBean.setTotalTime(now.getTime() - startDate.getTime());
try {
sendMessageStream.message_channel().send(new GenericMessage<String>(objectMapper.writeValueAsString(loggerBean)));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
测试。发送 http://localhost:8085/openapi-search/search/createIndex 请求,然后 kibana http://11.36.144.157:5601/ 查看数据。