Skip to content

Controller 开发

This content is not available in your language yet.

在 Web 应用开发中,控制器(Controller)是连接用户请求与业务逻辑的桥梁。Feat Cloud 采用 编译期注解处理(AOT) 技术,在编译阶段就将注解转换为高效的路由代码,运行时无需反射,性能接近手写代码。

本节将带你从零开始构建一个完整的控制器,理解 Feat Cloud 的 AOT 机制如何工作。

完成本节学习后,你将能够:

  • 理解 Feat Cloud 的 AOT 编译期处理机制
  • 使用 @Controller 定义控制器及其基础路径
  • 使用 @RequestMapping 映射 URL 和 HTTP 方法
  • 使用 @Param@PathParam 获取请求参数
  • 理解 Session、Context 等内置参数的注入机制
  • 配置 Gzip 压缩优化响应性能

Feat Cloud 与传统 Spring Boot 的最大区别在于:路由映射在编译期完成,而非运行时反射

当你编译代码时,feat-cloud-starter 中的注解处理器会:

  1. 扫描带有 @Controller 注解的类
  2. 解析@RequestMapping 定义的路径和方法
  3. 生成CloudService 实现类(如 XxxControllerCloudService
  4. 注册路由到 Router

生成的代码示例(简化):

编译期自动生成,无需手动编写
public class UserControllerCloudService extends AbstractCloudService {
private UserController bean;
public void loadBean(ApplicationContext ctx) {
bean = new UserController(); // 直接实例化,无反射
}
public void router(ApplicationContext ctx, Router router) {
// 直接注册路由,路径在编译期确定
router.route("/users/hello", new String[]{"GET"}, new RouterHandler() {
public void handle(Context ctx) {
String result = bean.hello(); // 直接调用,无代理
ctx.Response.write(result.getBytes());
}
});
}
}

在实际项目中,通常会将 Controller 按功能模块拆分到不同类中。以下是一个典型的项目结构:

src/main/java/com/example/
├── Bootstrap.java # 启动类
├── controller/
│ ├── UserController.java # 用户模块
│ └── OrderController.java# 订单模块
└── service/
└── UserService.java # 业务逻辑

UserController.java

UserController.java
package com.example.controller;
import tech.smartboot.feat.cloud.annotation.Controller;
import tech.smartboot.feat.cloud.annotation.RequestMapping;
import tech.smartboot.feat.cloud.annotation.RequestMethod;
@Controller("users")
public class UserController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
return "hello controller";
}
}

启动应用后,你会在控制台看到:

Feat Router:
|-> /users/hello ==> UserController@hello
http://0.0.0.0:8080/

访问 http://localhost:8080/users/hello,输出:

hello controller

@Controllervalue 属性定义该控制器下所有方法的 URL 前缀。

@Controller("users") // 基础路径: /users
public class UserController {
@RequestMapping("/list") // 完整路径: /users/list
public String list() {
return "user list";
}
}

路径组合规则:

控制器路径方法路径完整 URL
users/list/users/list
api/v1/users/api/v1/users
(空)/hello/hello

使用 @Param 注解从 URL 查询字符串提取参数值。

@RequestMapping(value = "/search", method = RequestMethod.GET)
public String search(@Param("keyword") String keyword,
@Param("page") int page) {
return "搜索: " + keyword + ", 页码: " + page;
}
Terminal window
curl "http://localhost:8080/users/search?keyword=feat&page=1"

使用 @PathParam 注解从 URL 路径提取变量值。

@RequestMapping(value = "/:userId", method = RequestMethod.GET)
public String getUser(@PathParam("userId") String userId) {
return "用户ID: " + userId;
}
Terminal window
curl http://localhost:8080/users/12345
UserController.java
package com.example.controller;
import tech.smartboot.feat.cloud.annotation.Controller;
import tech.smartboot.feat.cloud.annotation.Param;
import tech.smartboot.feat.cloud.annotation.PathParam;
import tech.smartboot.feat.cloud.annotation.RequestMapping;
import tech.smartboot.feat.cloud.annotation.RequestMethod;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@Controller("users")
public class UserController {
// 基础路径示例
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
return "hello controller";
}
// 查询参数示例
@RequestMapping(value = "/search", method = RequestMethod.GET)
public String search(@Param("keyword") String keyword) {
return "search: " + keyword;
}
// 路径参数示例
@RequestMapping(value = "/:username", method = RequestMethod.GET)
public Map<String, Object> profile(@PathParam("username") String username) {
Map<String, Object> data = new HashMap<>();
data.put("username", username);
data.put("roles", Collections.singletonList("user"));
return data;
}
}

测试命令:

Terminal window
curl http://localhost:8080/users/hello
# 输出: hello controller

public enum RequestMethod {
GET, // 获取资源
HEAD, // 获取资源头部信息
POST, // 创建资源
PUT, // 更新资源(全量)
PATCH, // 部分更新资源
DELETE, // 删除资源
OPTIONS,// 获取支持的请求方法
TRACE // 回显服务器收到的请求
}

为同一路径配置不同 HTTP 方法,实现 RESTful API:

ArticleController.java
@Controller("articles")
public class ArticleController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String list() {
return "list articles";
}
@RequestMapping(value = "/", method = RequestMethod.POST)
public String create() {
return "create article";
}
@RequestMapping(value = "/:id", method = RequestMethod.GET)
public String get(@PathParam("id") String id) {
return "get article: " + id;
}
@RequestMapping(value = "/:id", method = RequestMethod.PUT)
public String update(@PathParam("id") String id) {
return "update article: " + id;
}
@RequestMapping(value = "/:id", method = RequestMethod.DELETE)
public String delete(@PathParam("id") String id) {
return "delete article: " + id;
}
}

API 端点总结:

HTTP 方法URL操作
GET/articles获取文章列表
POST/articles创建新文章
GET/articles/:id获取指定文章
PUT/articles/:id更新指定文章
DELETE/articles/:id删除指定文章

除了 @Param@PathParam,Feat Cloud 支持直接注入多种内置对象。

import tech.smartboot.feat.core.server.Session;
@RequestMapping("/session")
public String session(Session session) {
// 获取会话 ID
String sessionId = session.getSessionId();
// 存储会话属性
session.setAttribute("user", "smartboot");
// 读取会话属性
String user = (String) session.getAttribute("user");
return "Session ID: " + sessionId + ", User: " + user;
}
import tech.smartboot.feat.router.Context;
@RequestMapping("/context")
public String context(Context context) {
// 获取请求 URI
String uri = context.Request.getRequestURI();
// 获取请求方法
String method = context.Request.getMethod();
// 获取请求头
String contentType = context.Request.getHeader("Content-Type");
return "URI: " + uri + ", Method: " + method;
}
import tech.smartboot.feat.cloud.AsyncResponse;
@RequestMapping("/async")
public AsyncResponse async() {
AsyncResponse response = new AsyncResponse();
// 在异步线程中完成响应
new Thread(() -> {
try {
Thread.sleep(1000); // 模拟耗时操作
response.write("异步响应完成");
response.complete();
} catch (InterruptedException e) {
response.complete();
}
}).start();
return response;
}

Feat Cloud 的 JSON 序列化在编译期完成代码生成,而非运行时反射:

// 编译期生成的序列化代码示例(简化)
public void serializeUser(User user, OutputStream os) {
os.write('{');
os.write("\"username\":".getBytes());
os.write('"');
os.write(user.getUsername().getBytes());
os.write('"');
os.write(',');
os.write("\"age\":".getBytes());
os.write(String.valueOf(user.getAge()).getBytes());
os.write('}');
}

性能对比:

对比项传统反射Feat Cloud
反射开销
字段访问反射调用直接调用
类型检查运行时编译期
内存分配较多极少

序列化规则:

  • String 类型直接输出为纯文本
  • 基本类型、包装类型、Date、Timestamp 等生成直接序列化代码
  • 自定义对象在编译期分析字段并生成序列化逻辑
  • 深层级对象(>4层)或数组回退到 FastJSON2 处理

@Controller 注解支持开启 Gzip 压缩,减少响应体积:

@Controller(
value = "api",
gzip = true, // 开启 Gzip 压缩
gzipThreshold = 256 // 压缩阈值:256 字节
)
public class CompressedController {
@RequestMapping(value = "/large", method = RequestMethod.GET)
public String largeResponse() {
// 当响应内容超过 256 字节时,自动启用 Gzip 压缩
return "这是一段很长的文本内容...";
}
}

Gzip 属性说明:

属性类型默认值说明
gzipbooleanfalse是否开启 Gzip 压缩
gzipThresholdint256压缩阈值(字节),低于此值不压缩

生产级控制器示例,展示各种特性的综合应用:

OrderController.java
package com.example.controller;
import tech.smartboot.feat.cloud.annotation.Controller;
import tech.smartboot.feat.cloud.annotation.Param;
import tech.smartboot.feat.cloud.annotation.PathParam;
import tech.smartboot.feat.cloud.annotation.RequestMapping;
import tech.smartboot.feat.cloud.annotation.RequestMethod;
import tech.smartboot.feat.core.server.Session;
import java.util.HashMap;
import java.util.Map;
@Controller(
value = "api/v1/orders",
gzip = true,
gzipThreshold = 512
)
public class OrderController {
/**
* 获取订单列表(支持分页)
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public Map<String, Object> list(
@Param("page") int page,
@Param("size") int size,
Session session) {
Map<String, Object> result = new HashMap<>();
result.put("page", page);
result.put("size", size);
result.put("sessionId", session.getSessionId());
result.put("orders", new String[]{});
return result;
}
/**
* 获取单个订单详情
*/
@RequestMapping(value = "/:orderId", method = RequestMethod.GET)
public Map<String, Object> detail(@PathParam("orderId") String orderId) {
Map<String, Object> order = new HashMap<>();
order.put("orderId", orderId);
order.put("status", "completed");
order.put("amount", 199.99);
return order;
}
/**
* 创建订单
*/
@RequestMapping(value = "/", method = RequestMethod.POST)
public Map<String, Object> create(@Param("productId") String productId,
@Param("quantity") int quantity) {
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("orderId", "ORD-" + System.currentTimeMillis());
result.put("productId", productId);
result.put("quantity", quantity);
return result;
}
/**
* 更新订单状态
*/
@RequestMapping(value = "/:orderId/status", method = RequestMethod.PUT)
public Map<String, Object> updateStatus(
@PathParam("orderId") String orderId,
@Param("status") String status) {
Map<String, Object> result = new HashMap<>();
result.put("orderId", orderId);
result.put("newStatus", status);
result.put("updated", true);
return result;
}
/**
* 取消订单
*/
@RequestMapping(value = "/:orderId", method = RequestMethod.DELETE)
public Map<String, Object> cancel(@PathParam("orderId") String orderId) {
Map<String, Object> result = new HashMap<>();
result.put("orderId", orderId);
result.put("cancelled", true);
return result;
}
}

API 测试命令:

Terminal window
curl "http://localhost:8080/api/v1/orders/?page=1&size=10"

本节详细介绍了 Feat Cloud 控制器的核心概念和使用方法:

  1. AOT 机制:编译期生成路由代码,运行时无反射,性能更高
  2. 基础配置:使用 @Controller 定义基础路径,@RequestMapping 映射端点
  3. 参数绑定@Param 获取查询参数,@PathParam 获取路径参数
  4. HTTP 方法:使用 RequestMethod 实现 RESTful API
  5. 内置注入:支持 SessionContextAsyncResponse 等对象注入
  6. 高级特性gzip 属性开启响应压缩