Basic Http Server应用示例

最近更新时间:2022-05-06 16:51:27

查看PDF

创建一个Basic Http Java项目,示例如下:

1. 添加pom依赖

在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>

2. 新建一个main函数

创建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;
        }
    }
}

3. Http Server监听端口资源配置

Http Server启动端口可以通过resources/application.properties文件进行配置。

server.port=8080

4. 添加Handler实现

用于处理接收请求的业务逻辑,您可以自定义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协议对象来返回响应头和响应体。

5. 编译打包

在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包。

maven package 

编译后的jar包位于项目文件内的target目录内,并根据pom.xml内的artifactId、version字段命名为cloudevents-basic-http-example-2.3.0.jar

6. Jar包上传云函数

  • 登陆云函数控制台
  • 在顶部菜单栏,选择地域和命名空间
  • 在函数管理页面,选择新建函数
  • 在环境配置页面,在代码上传的下拉列表下,选择上传代码包,或通过对象存储(ks3)上传方式上传打包好的Jar包。
  • 监听端口和资源配置文件保持一致(默认8080)
  • 点击最下方创建按钮
    删了.png

7. 示例支持Gradle打包编译方式

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目录下。
如果显示编译失败,请根据输出的编译错误信息调整代码。

文档内容是否对您有帮助?

根本没帮助
文档较差
文档一般
文档不错
文档很好

在文档使用中是否遇到以下问题

内容不全,不深入
内容更新不及时
描述不清晰,比较混乱
系统或功能太复杂,缺乏足够的引导
内容冗长

更多建议

0/200

评价建议不能为空

提交成功!

非常感谢您的反馈,我们会继续努力做到更好!

问题反馈