创建项目
进入网址 start.spring.io/
然后可以使用 IDEA 打开工程。
创建Controller
package com.congvee.springboot_hello.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
public String hello() {
return "Hello, World!";
}
}
接口调用
直接启动项目,默认运行在端口 8080 上,使用 postman 进行接口调试
如果想要自定义端口,可以在 application.properties 配置文件中添加 server.port=8081
响应统一结构
响应体的一般结构是:
{
"code": 0,
"message": "success",
"data": { ... }
}
code 0 表示成功,非 0 表示异常,可以自定义一些异常码。
可以这样定义统一类型:
package com.congvee.springboot_hello.common;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class ApiResponse<T> {
private int code;
private String message;
private T data;
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(0, "success", data);
}
public static <T> ApiResponse<T> error(int code, String message) {
return new ApiResponse<>(code, message, null);
}
public static <T> ApiResponse<T> error(int code, String message, T detail) {
return new ApiResponse<>(code, message, detail);
}
}
使用lombok注解需要额外引入依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
使用:
@GetMapping
public ApiResponse<String> hello() {
return ApiResponse.success("Hello World!");
}
接口调用:
统一转换
ResponseBodyAdvice 可以在正常响应到客户端之前做一些统一处理,我们可以将ApiResponse放在这里统一处理,这样Controller的返回值就不用每次都写ApiResponse了。
@Slf4j
@ControllerAdvice
public class ResponseWrapper implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
ObjectMapper mapper = new ObjectMapper();
try {
// String 类似特殊处理
if (body instanceof String) {
return mapper.writeValueAsString(ApiResponse.success(body));
}
return ApiResponse.success(body);
} catch (Exception e) {
// 这里抛出的异常是不会走全局异常处理器的
try {
ApiResponse<?> errorResp = ApiResponse.error(50000, "响应序列化失败");
String json = mapper.writeValueAsString(errorResp);
// 直接写到输出流
response.getBody().write(json.getBytes(StandardCharsets.UTF_8));
response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
} catch (IOException ex) {
// 如果连写异常响应都失败,只能默默记录日志
log.error("Failed to write error response", ex);
}
// 告诉 Spring:我已经写完,别再处理了
return null;
}
}
}
这样Controller又回到了这种写法:
@RestController
@RequestMapping("/api/hello")
@Validated
public class HelloController {
@GetMapping
public String hello() {
return "Hello World!";
}
}
接口调用: