chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:31:35 +08:00
commit c275ba2868
13613 changed files with 2980806 additions and 0 deletions
@@ -0,0 +1,190 @@
# Calculator HTTP Streaming Demo
This project demonstrates HTTP streaming using Server-Sent Events (SSE) with Spring Boot WebFlux. It consists of two applications:
- **Calculator Server**: A reactive web service that performs calculations and streams results using SSE
- **Calculator Client**: A client application that consumes the streaming endpoint
## Prerequisites
- Java 17 or higher
- Maven 3.6 or higher
## Project Structure
```
java/
├── calculator-server/ # Spring Boot server with SSE endpoint
│ ├── src/main/java/com/example/calculatorserver/
│ │ ├── CalculatorServerApplication.java
│ │ └── CalculatorController.java
│ └── pom.xml
├── calculator-client/ # Spring Boot client application
│ ├── src/main/java/com/example/calculatorclient/
│ │ └── CalculatorClientApplication.java
│ └── pom.xml
└── README.md
```
## How It Works
1. The **Calculator Server** exposes a `/calculate` endpoint that:
- Accepts query parameters: `a` (number), `b` (number), `op` (operation)
- Supported operations: `add`, `sub`, `mul`, `div`
- Returns Server-Sent Events with calculation progress and result
2. The **Calculator Client** connects to the server and:
- Makes a request to calculate `7 * 5`
- Consumes the streaming response
- Prints each event to the console
## Running the Applications
### Option 1: Using Maven (Recommended)
#### 1. Start the Calculator Server
Open a terminal and navigate to the server directory:
```bash
cd calculator-server
mvn clean package
mvn spring-boot:run
```
The server will start on `http://localhost:8080`
You should see output like:
```
Started CalculatorServerApplication in X.XXX seconds
Netty started on port 8080 (http)
```
#### 2. Run the Calculator Client
Open a **new terminal** and navigate to the client directory:
```bash
cd calculator-client
mvn clean package
mvn spring-boot:run
```
The client will connect to the server, perform the calculation, and display the streaming results.
### Option 2: Using Java directly
#### 1. Compile and run the server:
```bash
cd calculator-server
mvn clean package
java -jar target/calculator-server-0.0.1-SNAPSHOT.jar
```
#### 2. Compile and run the client:
```bash
cd calculator-client
mvn clean package
java -jar target/calculator-client-0.0.1-SNAPSHOT.jar
```
## Testing the Server Manually
You can also test the server using a web browser or curl:
### Using a web browser:
Visit: `http://localhost:8080/calculate?a=10&b=5&op=add`
### Using curl:
```bash
curl "http://localhost:8080/calculate?a=10&b=5&op=add" -H "Accept: text/event-stream"
```
## Expected Output
When running the client, you should see streaming output similar to:
```
event:info
data:Calculating: 7.0 mul 5.0
event:result
data:35.0
```
## Supported Operations
- `add` - Addition (a + b)
- `sub` - Subtraction (a - b)
- `mul` - Multiplication (a * b)
- `div` - Division (a / b, returns NaN if b = 0)
## API Reference
### GET /calculate
**Parameters:**
- `a` (required): First number (double)
- `b` (required): Second number (double)
- `op` (required): Operation (`add`, `sub`, `mul`, `div`)
**Response:**
- Content-Type: `text/event-stream`
- Returns Server-Sent Events with calculation progress and result
**Example Request:**
```
GET /calculate?a=7&b=5&op=mul HTTP/1.1
Host: localhost:8080
Accept: text/event-stream
```
**Example Response:**
```
event: info
data: Calculating: 7.0 mul 5.0
event: result
data: 35.0
```
## Troubleshooting
### Common Issues
1. **Port 8080 already in use**
- Stop any other applications using port 8080
- Or change the server port in `calculator-server/src/main/resources/application.yml`
2. **Connection refused**
- Make sure the server is running before starting the client
- Check that the server started successfully on port 8080
3. **Parameter name issues**
- This project includes Maven compiler configuration with `-parameters` flag
- If you encounter parameter binding issues, ensure the project is built with this configuration
### Stopping the Applications
- Press `Ctrl+C` in the terminal where each application is running
- Or use `mvn spring-boot:stop` if running as a background process
## Technology Stack
- **Spring Boot 3.3.1** - Application framework
- **Spring WebFlux** - Reactive web framework
- **Project Reactor** - Reactive streams library
- **Netty** - Non-blocking I/O server
- **Maven** - Build tool
- **Java 17+** - Programming language
## Next Steps
Try modifying the code to:
- Add more mathematical operations
- Include error handling for invalid operations
- Add request/response logging
- Implement authentication
- Add unit tests
@@ -0,0 +1,50 @@
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>calculator-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
<spring.boot.version>3.3.1</spring.boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring Boot WebFlux for WebClient -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,35 @@
package com.example.calculatorclient;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
@SpringBootApplication
public class CalculatorClientApplication implements CommandLineRunner {
private final WebClient client = WebClient.builder()
.baseUrl("http://localhost:8080")
.build();
public static void main(String[] args) {
SpringApplication.run(CalculatorClientApplication.class, args);
}
@Override
public void run(String... args) {
client.get()
.uri(uriBuilder -> uriBuilder
.path("/calculate")
.queryParam("a", 7)
.queryParam("b", 5)
.queryParam("op", "mul")
.build())
.accept(MediaType.TEXT_EVENT_STREAM)
.retrieve()
.bodyToFlux(String.class)
.doOnNext(System.out::println)
.blockLast();
}
}
@@ -0,0 +1,3 @@
spring:
main:
web-application-type: none
@@ -0,0 +1,50 @@
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>calculator-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
<spring.boot.version>3.3.1</spring.boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring Boot WebFlux for SSE -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,51 @@
package com.example.calculatorserver;
import java.time.Duration;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import org.springframework.http.codec.ServerSentEvent;
@RestController
public class CalculatorController {
@GetMapping(value = "/calculate", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> calculate(@RequestParam double a,
@RequestParam double b,
@RequestParam String op) {
double result;
switch (op) {
case "add":
result = a + b;
break;
case "sub":
result = a - b;
break;
case "mul":
result = a * b;
break;
case "div":
result = b != 0 ? a / b : Double.NaN;
break;
default:
result = Double.NaN;
}
return Flux.<ServerSentEvent<String>>just(
ServerSentEvent.<String>builder()
.event("info")
.data("Calculating: " + a + " " + op + " " + b)
.build(),
ServerSentEvent.<String>builder()
.event("result")
.data(String.valueOf(result))
.build()
)
.delayElements(Duration.ofSeconds(1));
}
}
@@ -0,0 +1,12 @@
package com.example.calculatorserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CalculatorServerApplication {
public static void main(String[] args) {
SpringApplication.run(CalculatorServerApplication.class, args);
}
}