添加一个测试用响应
Change-Id: I2d7a9edfd5131b5e6cd364814647536d21d50254
diff --git a/Dockerfile b/Dockerfile
index 2d4db7a..b646295 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,41 +1,14 @@
-# 构建阶段
-FROM maven:3.9.6-amazoncorretto-17 AS build
-
-# 设置工作目录
-WORKDIR /build
-
-# 复制 pom.xml
-COPY pom.xml .
-
-# 下载依赖
-RUN mvn dependency:go-offline
-
-# 复制源代码
-COPY src ./src
-
-# 构建项目
-RUN mvn clean package -DskipTests
-
-# 运行阶段
-FROM amazoncorretto:17 AS final
+# 使用官方 OpenJDK 镜像
+FROM eclipse-temurin:17-jdk-jammy
# 设置工作目录
WORKDIR /team12
-# 设置时区
-ENV TZ=Asia/Shanghai
-RUN yum update -y && \
- yum install -y tzdata && \
- ln -fs /usr/share/zoneinfo/$TZ /etc/localtime && \
- echo $TZ > /etc/timezone && \
- yum clean all && \
- rm -rf /var/cache/yum
+# 复制 JAR 文件到容器
+COPY target/*.jar team12.jar
-# 从构建阶段复制构建好的 jar 文件
-COPY --from=build /build/target/*.jar team12.jar
-
-# 暴露端口
+# 暴露端口(与 application.yml/server.port 一致)
EXPOSE 8080
-# 启动命令
+# 启动应用
ENTRYPOINT ["java", "-jar", "team12.jar"]
\ No newline at end of file
diff --git a/src/main/java/com/pt/controller/AdminController.java b/src/main/java/com/pt/controller/AdminController.java
index 1ddfc92..22e2b86 100644
--- a/src/main/java/com/pt/controller/AdminController.java
+++ b/src/main/java/com/pt/controller/AdminController.java
@@ -31,7 +31,9 @@
Admin admin = adminService.findByUsernameAndPassword(username, password);
if (admin != null) {
ans.put("result", "Login successful");
- ans.put("token", JWTUtils.generateToken(username, Constants.UserRole.ADMIN, (int)1.2e8));
+ ans.put("data", Map.of(
+ "token", JWTUtils.generateToken(username, Constants.UserRole.ADMIN, (int)1.2e8)
+ ));
return ResponseEntity.ok().body(ans);
} else {
ans.put("result", "Invalid username or password");
diff --git a/src/main/java/com/pt/controller/CommentController.java b/src/main/java/com/pt/controller/CommentController.java
index a85d131..17dabb3 100644
--- a/src/main/java/com/pt/controller/CommentController.java
+++ b/src/main/java/com/pt/controller/CommentController.java
@@ -72,7 +72,9 @@
List<Comment> comments = commentService.getCommentsByPostId(postId);
ans.put("result", "Comments retrieved successfully");
- ans.put("comments", comments);
+ ans.put("data", Map.of(
+ "comments", comments
+ ));
return ResponseEntity.ok(ans);
}
}
diff --git a/src/main/java/com/pt/controller/PostController.java b/src/main/java/com/pt/controller/PostController.java
index 387cc2d..0ab86ed 100644
--- a/src/main/java/com/pt/controller/PostController.java
+++ b/src/main/java/com/pt/controller/PostController.java
@@ -92,7 +92,9 @@
posts.removeIf(post -> !post.getPublishDate().toString().equals(date));
}
ans.put("result", "Post retrieved successfully");
- ans.put("post", posts);
+ ans.put("data", Map.of(
+ "post", posts
+ ));
return ResponseEntity.ok(ans);
}
diff --git a/src/main/java/com/pt/controller/UserController.java b/src/main/java/com/pt/controller/UserController.java
index 3978831..7603f9d 100644
--- a/src/main/java/com/pt/controller/UserController.java
+++ b/src/main/java/com/pt/controller/UserController.java
@@ -43,8 +43,7 @@
userService.save(newUser);
Map<String, Object> ans = new HashMap<>();
- ans.put("success", true);
- ans.put("message", "User registered successfully");
+ ans.put("result", "User registered successfully");
ans.put("data", newUser);
return ResponseEntity.ok().body(ans);
@@ -52,9 +51,9 @@
}
@PostMapping("/login")
- public ResponseEntity<?> loginUser(@RequestBody Map<String, String> request) {
- String username = request.get("username");
- String password = request.get("password");
+ public ResponseEntity<?> loginUser(@RequestParam("username") String username,
+ @RequestParam("password") String password) {
+
if (username == null || password == null) {
return ResponseEntity.badRequest().body("Missing username or password");
@@ -64,16 +63,11 @@
Map<String, Object> ans = new HashMap<>();
if (user != null) {
String token = JWTUtils.generateToken(username, Constants.UserRole.USER, Constants.DEFAULT_EXPIRE_TIME);
- ans.put("success", true);
- ans.put("message", "Login successful");
- ans.put("data", Map.of(
- "token", token,
- "user", user
- ));
+ ans.put("result", "Login successful");
+ ans.put("data", token);
return ResponseEntity.ok().body(ans);
} else {
- ans.put("success", false);
- ans.put("message", "Invalid username or password");
+ ans.put("result", "Invalid username or password");
return ResponseEntity.badRequest().body(ans);
}
}
@@ -82,17 +76,21 @@
public ResponseEntity<?> updateUsername(@RequestHeader("token") String token,
@RequestParam("username") String oldUsername,
@RequestParam("newUsername") String newUsername) {
+ Map<String, Object> ans = new HashMap<>();
if(!JWTUtils.checkToken(token, oldUsername, Constants.UserRole.USER)) {
- return ResponseEntity.badRequest().body("Invalid token");
+ ans.put("result", "Invalid token");
+ return ResponseEntity.badRequest().body(ans);
}
User user = userService.findByUsername(oldUsername);
if (user != null) {
user.setUsername(newUsername);
userService.save(user);
- return ResponseEntity.ok("Username updated successfully");
+ ans.put("result", "Username updated successfully");
+ return ResponseEntity.ok(ans);
} else {
- return ResponseEntity.badRequest().body("User not found");
+ ans.put("result", "User not found");
+ return ResponseEntity.badRequest().body(ans);
}
}
@@ -100,17 +98,21 @@
public ResponseEntity<?> updatePassword(@RequestHeader("token") String token,
@RequestParam("username") String username,
@RequestParam("newPassword") String newPassword) {
+ Map<String, Object> ans = new HashMap<>();
if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
- return ResponseEntity.badRequest().body("Invalid token");
+ ans.put("result", "Invalid token");
+ return ResponseEntity.badRequest().body(ans);
}
User user = userService.findByUsername(username);
if (user != null) {
user.setPassword(newPassword);
userService.save(user);
- return ResponseEntity.ok("Password updated successfully");
+ ans.put("result", "Password updated successfully");
+ return ResponseEntity.ok(ans);
} else {
- return ResponseEntity.badRequest().body("Invalid username or password");
+ ans.put("result", "Invalid username or password");
+ return ResponseEntity.badRequest().body(ans);
}
}
@@ -118,17 +120,22 @@
public ResponseEntity<?> updateEmail(@RequestHeader("token") String token,
@RequestParam("username") String username,
@RequestParam("newEmail") String newEmail) {
+
+ Map<String, Object> ans = new HashMap<>();
if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
- return ResponseEntity.badRequest().body("Invalid token");
+ ans.put("result", "Invalid token");
+ return ResponseEntity.badRequest().body(ans);
}
User user = userService.findByUsername(username);
if (user != null) {
user.setEmail(newEmail);
userService.save(user);
- return ResponseEntity.ok("Email updated successfully");
+ ans.put("result", "Email updated successfully");
+ return ResponseEntity.ok(ans);
} else {
- return ResponseEntity.badRequest().body("User not found");
+ ans.put("result", "User not found");
+ return ResponseEntity.badRequest().body(ans);
}
}
@@ -137,16 +144,20 @@
@RequestParam("username") String username,
@RequestParam("targetUsername") String targetUsername
) {
+ Map<String, Object> ans = new HashMap<>();
if(!JWTUtils.checkToken(token, username, Constants.UserRole.ADMIN)) {
- return ResponseEntity.badRequest().body("Invalid token");
+ ans.put("result", "Invalid token");
+ return ResponseEntity.badRequest().body(ans);
}
User user = userService.findByUsername(targetUsername);
if (user != null) {
userService.deleteById(user.getUid());
- return ResponseEntity.ok("User deleted successfully");
+ ans.put("result", "User deleted successfully");
+ return ResponseEntity.ok(ans);
} else {
- return ResponseEntity.badRequest().body("User not found");
+ ans.put("result", "User not found");
+ return ResponseEntity.badRequest().body(ans);
}
}
@@ -159,26 +170,30 @@
Map<String, Object> ans = new HashMap<>();
ans.put("result", "User list retrieved successfully");
- ans.put("amount", userService.listAll().size());
- ans.put("users", userService.listAll());
+ ans.put("data", Map.of(
+ "amount", userService.listAll().size(),
+ "users", userService.listAll()
+ ));
return ResponseEntity.ok(ans);
}
@GetMapping("/get/info")
public ResponseEntity<?> getUserInfo(@RequestHeader("token") String token,
@RequestParam("username") String username) {
+ Map<String, Object> ans = new HashMap<>();
if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
- return ResponseEntity.badRequest().body("Invalid token");
+ ans.put("result", "Invalid token");
+ return ResponseEntity.badRequest().body(ans);
}
User user = userService.findByUsername(username);
if (user != null) {
- Map<String, Object> ans = new HashMap<>();
ans.put("result", "User info retrieved successfully");
- ans.put("user", user);
+ ans.put("data", user);
return ResponseEntity.ok(ans);
} else {
- return ResponseEntity.badRequest().body("User not found");
+ ans.put("result", "User not found");
+ return ResponseEntity.badRequest().body(ans);
}
}
}
diff --git a/src/main/java/com/pt/testResponse/TestController.java b/src/main/java/com/pt/testResponse/TestController.java
new file mode 100644
index 0000000..82b3f58
--- /dev/null
+++ b/src/main/java/com/pt/testResponse/TestController.java
@@ -0,0 +1,15 @@
+package com.pt.testResponse;
+
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@CrossOrigin(origins = "*")
+public class TestController {
+
+ @GetMapping("/test")
+ public String testResponse() {
+ return "Hello, world!";
+ }
+}
diff --git a/src/main/java/com/pt/utils/BdecodeUtils.java b/src/main/java/com/pt/utils/BdecodeUtils.java
new file mode 100644
index 0000000..c77f8b4
--- /dev/null
+++ b/src/main/java/com/pt/utils/BdecodeUtils.java
@@ -0,0 +1,84 @@
+package com.pt.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+public class BdecodeUtils {
+ public static Object decode(byte[] data) throws IOException {
+ try (ByteArrayInputStream in = new ByteArrayInputStream(data)) {
+ return decodeNext(in);
+ }
+ }
+
+ private static Object decodeNext(InputStream in) throws IOException {
+ int prefix = in.read();
+ if (prefix == -1) {
+ throw new IOException("Unexpected end of stream");
+ }
+
+ if (prefix >= '0' && prefix <= '9') {
+ // 字符串,回退一个字节给parseString处理
+ in.reset();
+ return parseString(in, prefix);
+ } else if (prefix == 'i') {
+ return parseInteger(in);
+ } else if (prefix == 'l') {
+ return parseList(in);
+ } else if (prefix == 'd') {
+ return parseDict(in);
+ } else {
+ throw new IOException("Invalid bencode prefix: " + (char) prefix);
+ }
+ }
+
+ private static String parseString(InputStream in, int firstDigit) throws IOException {
+ // 读长度前缀
+ StringBuilder lenStr = new StringBuilder();
+ lenStr.append((char) firstDigit);
+ int b;
+ while ((b = in.read()) != -1 && b != ':') {
+ lenStr.append((char) b);
+ }
+ int length = Integer.parseInt(lenStr.toString());
+
+ // 读内容
+ byte[] buf = new byte[length];
+ int read = in.read(buf);
+ if (read < length) throw new IOException("Unexpected end of stream reading string");
+ return new String(buf);
+ }
+
+ private static long parseInteger(InputStream in) throws IOException {
+ StringBuilder intStr = new StringBuilder();
+ int b;
+ while ((b = in.read()) != -1 && b != 'e') {
+ intStr.append((char) b);
+ }
+ return Long.parseLong(intStr.toString());
+ }
+
+ private static List<Object> parseList(InputStream in) throws IOException {
+ List<Object> list = new ArrayList<>();
+ int b;
+ while ((b = in.read()) != 'e') {
+ in.reset();
+ list.add(decodeNext(in));
+ }
+ return list;
+ }
+
+ private static Map<String, Object> parseDict(InputStream in) throws IOException {
+ Map<String, Object> map = new LinkedHashMap<>();
+ int b;
+ while ((b = in.read()) != 'e') {
+ in.reset();
+ String key = (String) decodeNext(in);
+ Object value = decodeNext(in);
+ map.put(key, value);
+ }
+ return map;
+ }
+}
+
diff --git a/src/main/java/com/pt/utils/BencodeUtils.java b/src/main/java/com/pt/utils/BencodeUtils.java
new file mode 100644
index 0000000..2d3850d
--- /dev/null
+++ b/src/main/java/com/pt/utils/BencodeUtils.java
@@ -0,0 +1,107 @@
+package com.pt.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+public class BencodeUtils {
+
+ // 通用bencode编码接口
+ public static void encode(Object obj, OutputStream out) throws IOException {
+ if (obj instanceof String) {
+ encodeString((String) obj, out);
+ } else if (obj instanceof Number) {
+ encodeInteger(((Number) obj).longValue(), out);
+ } else if (obj instanceof byte[]) {
+ encodeBytes((byte[]) obj, out);
+ } else if (obj instanceof List) {
+ encodeList((List<?>) obj, out);
+ } else if (obj instanceof Map) {
+ encodeMap((Map<String, Object>) obj, out);
+ } else {
+ throw new IllegalArgumentException("Unsupported type: " + obj.getClass());
+ }
+ }
+
+ public static byte[] encode(Object obj) {
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+ encode(obj, baos);
+ return baos.toByteArray();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static void encodeString(String s, OutputStream out) throws IOException {
+ byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
+ out.write(String.valueOf(bytes.length).getBytes(StandardCharsets.US_ASCII));
+ out.write(':');
+ out.write(bytes);
+ }
+
+ private static void encodeBytes(byte[] bytes, OutputStream out) throws IOException {
+ out.write(String.valueOf(bytes.length).getBytes(StandardCharsets.US_ASCII));
+ out.write(':');
+ out.write(bytes);
+ }
+
+ private static void encodeInteger(long value, OutputStream out) throws IOException {
+ out.write('i');
+ out.write(Long.toString(value).getBytes(StandardCharsets.US_ASCII));
+ out.write('e');
+ }
+
+ private static void encodeList(List<?> list, OutputStream out) throws IOException {
+ out.write('l');
+ for (Object item : list) {
+ encode(item, out);
+ }
+ out.write('e');
+ }
+
+ private static void encodeMap(Map<String, Object> map, OutputStream out) throws IOException {
+ out.write('d');
+ List<String> keys = new ArrayList<>(map.keySet());
+ Collections.sort(keys); // bencode字典必须按key排序
+ for (String key : keys) {
+ encodeString(key, out);
+ encode(map.get(key), out);
+ }
+ out.write('e');
+ }
+
+ // 构造单个compact peer的二进制格式 (4字节IP + 2字节端口)
+ public static byte[] buildCompactPeer(String ip, int port) {
+ try {
+ InetAddress addr = InetAddress.getByName(ip);
+ ByteBuffer buffer = ByteBuffer.allocate(6);
+ buffer.put(addr.getAddress());
+ buffer.putShort((short) port);
+ return buffer.array();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // 构造多个compact peer的二进制拼接
+ public static byte[] buildCompactPeers(List<String> ips, List<Integer> ports) {
+ if (ips.size() != ports.size()) throw new IllegalArgumentException("IPs and ports list size mismatch");
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ for (int i = 0; i < ips.size(); i++) {
+ out.write(buildCompactPeer(ips.get(i), ports.get(i)), 0, 6);
+ }
+ return out.toByteArray();
+ }
+
+ // 构造tracker响应字典,至少包含interval和peers
+ public static byte[] buildTrackerResponse(int interval, byte[] peersCompact) {
+ Map<String, Object> dict = new LinkedHashMap<>();
+ dict.put("interval", interval);
+ dict.put("peers", peersCompact);
+ return encode(dict);
+ }
+}