最近更新时间:2023-02-03 17:38:12
创建一个Basic Http Java项目,示例如下:
在pom.xml文件需要添加下列依赖内容:
<properties>
<project.version>2.3.0</project.version>
</properties>
<dependencies>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-http-basic</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-json-jackson</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.41.v20210516</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.0-alpha6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.0-alpha6</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>
创建Server,加载handlers,启动服务start,最后加入服务器join。
package io.cloudevents.examples.http.basic.server;
import io.cloudevents.examples.http.basic.handler.CustomHandler;
import io.cloudevents.examples.http.basic.handler.HealthCheckHandler;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerList;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.Properties;
@Slf4j
public class JettyServer {
public static void main(String[] args) throws Exception {
String serverPort = loadHttpServerPort();
if (serverPort == null || serverPort.equals("")) {
log.error("Usage: HTTPServer <port>");
return;
}
Server server = new Server(new InetSocketAddress("localhost", Integer.parseInt(serverPort)));
HandlerList handlerList = new HandlerList();
handlerList.addHandler(new HealthCheckHandler());
handlerList.addHandler(new CustomHandler());
server.setHandler(handlerList);
server.start();
server.join();
}
public static String loadHttpServerPort() {
Properties properties = new Properties();
try {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("application.properties");
properties.load(inputStream);
String port = properties.getProperty("server.port");
log.info("Http Server Port: {}", port);
return port;
} catch (Exception e) {
log.error("Load Properties From Config error", e);
return null;
}
}
}
Http Server启动端口可以通过resources/application.properties文件进行配置。
server.port=8080
用于处理接收请求的业务逻辑,您可以自定义handler进行业务处理,下面列举出2个handler示例
HealthCheckHandler用于检测函数是否正常启动
package io.cloudevents.examples.http.basic.handler;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
@Slf4j
public class HealthCheckHandler extends AbstractHandler {
@Override
public void handle(String uri,
Request request,
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws IOException, ServletException {
if ("/health".equalsIgnoreCase(uri)) {
log.info("health check");
httpServletResponse.setContentType("application/json;charset=UTF-8");
OutputStream outputStream = httpServletResponse.getOutputStream();
String data = "Hands Up";
byte[] dataByteArr = data.getBytes(StandardCharsets.UTF_8);
outputStream.write(dataByteArr);
httpServletResponse.setContentLength(data.length());
httpServletResponse.setStatus(HttpStatus.OK_200);
((Request) request).setHandled(true);
}
}
}
CustomHandler用于处理事件函数请求
package io.cloudevents.examples.http.basic.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.message.MessageReader;
import io.cloudevents.core.message.MessageWriter;
import io.cloudevents.examples.http.basic.Foo;
import io.cloudevents.examples.http.basic.IOUtils;
import io.cloudevents.http.HttpMessageFactory;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Enumeration;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@Slf4j
public class CustomHandler extends AbstractHandler {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void handle(String uri,
Request request,
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws IOException, ServletException {
if (!"/event-invoke".equalsIgnoreCase(uri)) {
httpServletResponse.setStatus(HttpStatus.NOT_FOUND_404);
return;
}
if (!"POST".equalsIgnoreCase(request.getMethod())) {
httpServletResponse.setStatus(HttpStatus.METHOD_NOT_ALLOWED_405);
return;
}
CloudEvent receivedEvent = createMessageReader(httpServletRequest).toEvent();
log.info("begin receive event: {}", receivedEvent);
log.info("receive event string data: {}", new String(receivedEvent.getData().toBytes()));
Ks3CloudEventData ks3Data = objectMapper.readValue(receivedEvent.getData().toBytes(), Ks3CloudEventData.class);
log.info("ks3Data : {}", ks3Data );
createMessageWriter(httpServletResponse).writeBinary(receivedEvent);
((Request) request).setHandled(true);
}
private static MessageReader createMessageReader(HttpServletRequest httpServletRequest) throws IOException {
Consumer<BiConsumer<String, String>> forEachHeader = processHeader -> {
Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
processHeader.accept(name, httpServletRequest.getHeader(name));
}
};
byte[] body = IOUtils.toByteArray(httpServletRequest.getInputStream());
return HttpMessageFactory.createReader(forEachHeader, body);
}
其中createMessageReader方法将httpServletRequest请求数据转换成cloudevents对象格式,请求对象和和请求头均可以通过cloudevents对象进行获取。
createMessageWriter将cloudevents对象转换成HttpServletResponse协议对象来返回响应头和响应体。
在pom.xml文件中添加maven-assembly-plugin插件(打包插件您可以自行选择,此处将maven-assembly-plugin插件作为示例)。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>
io.cloudevents.examples.http.basic.server.JettyServer
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
使用下面命令将代码和及其依赖打包成可执行的jar包,编译后的jar包位于项目文件内的target目录内。
maven package
编译好的jar包需用zip工具进行压缩,用于后续控制台的代码包上传。
gradle使用build.gradle配置文件进行编译。build.gradle配置文件如下:
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '7.1.2'
}
group 'org.example'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'io.cloudevents:cloudevents-http-basic:2.3.0'
implementation 'io.cloudevents:cloudevents-json-jackson:2.3.0'
implementation 'org.eclipse.jetty:jetty-server:9.4.41.v20210516'
implementation 'org.slf4j:slf4j-api:2.0.0-alpha6'
implementation 'org.slf4j:slf4j-simple:2.0.0-alpha6'
implementation "org.projectlombok:lombok:1.18.22"
annotationProcessor "org.projectlombok:lombok:1.18.22"
}
description = 'cloudevents-basic-http-example'
shadowJar {
manifest {
attributes 'Main-Class': 'io.cloudevents.examples.http.basic.JettyServer'
}
}
test {
useJUnitPlatform()
}
其中com.github.johnrengelman.shadow插件将程序打包fat jar,包含程序运行所有依赖的Jar包,可以直接使用java -jar 【name】运行。其中attributes 下Main-Class属性需要和代码中Main函数名称保持一致。
在项目的根目录下执行gradle shadow命令打包,编译输出如下:
gradle shadow
编译输出示例
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
编译后的jar包位于项目文件内的build/libs目录下。
如果显示编译失败,请根据输出的编译错误信息调整代码。
纯净模式