对网站专业性建设_宣传推广设计整体改进方案,浙江网站建设制作流程,取消网站备案号,做jsp网站时怎么预览常见的http状态码
ResponseStatus(HttpStatus.CREATED) 是 Spring Framework 中的注解#xff0c;用于指定 HTTP 响应状态码。
1. 基本说明
HttpStatus.CREATED 对应 HTTP 状态码 201表示请求成功且创建了新的资源通常用于 POST 请求的处理方法上
2. 使用场景和示例
基本…常见的http状态码
ResponseStatus(HttpStatus.CREATED) 是 Spring Framework 中的注解用于指定 HTTP 响应状态码。
1. 基本说明
HttpStatus.CREATED 对应 HTTP 状态码 201表示请求成功且创建了新的资源通常用于 POST 请求的处理方法上
2. 使用场景和示例
基本使用
RestController
RequestMapping(/api/users)
public class UserController {PostMappingResponseStatus(HttpStatus.CREATED) // 将返回 201 状态码public User createUser(RequestBody User user) {return userService.createUser(user);}
}带有详细响应的使用
RestController
RequestMapping(/api/products)
public class ProductController {PostMappingResponseStatus(HttpStatus.CREATED)public ResponseEntityProduct createProduct(RequestBody Product product) {Product savedProduct productService.save(product);// 创建资源的 URIURI location ServletUriComponentsBuilder.fromCurrentRequest().path(/{id}).buildAndExpand(savedProduct.getId()).toUri();// 返回 201 状态码和资源位置return ResponseEntity.created(location).body(savedProduct);}
}3. 常用的 HTTP 状态码注解
// 成功相关
ResponseStatus(HttpStatus.OK) // 200 - 请求成功返回资源或结果
ResponseStatus(HttpStatus.CREATED) // 201 - 资源创建成功
ResponseStatus(HttpStatus.NO_CONTENT) // 204 - 成功但无返回内容// 客户端错误
ResponseStatus(HttpStatus.BAD_REQUEST) // 400 - 请求格式错误,客户端请求无效
ResponseStatus(HttpStatus.UNAUTHORIZED) // 401 - 未授权需身份验证
ResponseStatus(HttpStatus.FORBIDDEN) // 403 - 禁止访问
ResponseStatus(HttpStatus.NOT_FOUND) // 404 - 资源未找到
ResponseStatus(HttpStatus.CONFLICT) // 409 - 资源冲突// 服务器错误
ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 500 - 服务器内部错误如果需要更灵活地设置响应内容如返回自定义的响应体或头部信息可以使用 ResponseEntity而不是 ResponseStatus
ResponseStatus 是一种简洁的方式用于指定固定的 HTTP 状态码但它的功能相对有限。如果需要更灵活地设置响应内容如自定义响应体、响应头、动态状态码等可以使用 ResponseEntity。 1. 为什么选择 ResponseEntity
ResponseEntity 是 Spring 提供的一个强大的工具用于构建 HTTP 响应。它允许你
动态设置 HTTP 状态码自定义响应头返回复杂的响应体更灵活地处理不同的场景 2. ResponseEntity 的基本用法
示例 1: 返回自定义状态码和响应体
PostMapping(/users)
public ResponseEntityString createUser(RequestBody UserRequest userRequest) {userService.createUser(userRequest);return ResponseEntity.status(HttpStatus.CREATED).body(User created successfully);
}ResponseEntity.status(HttpStatus.CREATED)设置 HTTP 状态码为 201 Created。.body(User created successfully)设置响应体为自定义的字符串。 示例 2: 返回带有响应头的信息
PostMapping(/users)
public ResponseEntityString createUser(RequestBody UserRequest userRequest) {userService.createUser(userRequest);// 设置自定义响应头HttpHeaders headers new HttpHeaders();headers.add(Custom-Header, CustomHeaderValue);return ResponseEntity.status(HttpStatus.CREATED).headers(headers).body(User created successfully);
}HttpHeaders用于设置响应头。.headers(headers)将自定义的响应头添加到响应中。 示例 3: 返回带有资源位置的响应
在 RESTful API 中创建资源后通常会返回 Location 头指向新创建资源的 URI。
PostMapping(/users)
public ResponseEntityVoid createUser(RequestBody UserRequest userRequest) {Long userId userService.createUser(userRequest);// 构造资源的 URIURI location ServletUriComponentsBuilder.fromCurrentRequest().path(/{id}).buildAndExpand(userId).toUri();// 返回 201 Created 和 Location 头return ResponseEntity.created(location).build();
}ServletUriComponentsBuilder用于动态构建资源的 URI。.created(location)设置状态码为 201 Created并添加 Location 头。 示例 4: 动态返回不同的状态码
PostMapping(/users)
public ResponseEntityString createUser(RequestBody UserRequest userRequest) {if (userService.isDuplicate(userRequest)) {return ResponseEntity.status(HttpStatus.CONFLICT).body(User already exists);}userService.createUser(userRequest);return ResponseEntity.status(HttpStatus.CREATED).body(User created successfully);
}如果用户已存在返回 409 Conflict。如果创建成功返回 201 Created。 3. 与 ResponseStatus 的对比
特性ResponseStatusResponseEntity设置状态码固定状态码不能动态设置可以动态设置状态码自定义响应体不支持支持返回任意类型的响应体自定义响应头不支持支持通过 HttpHeaders 设置响应头适用场景简单场景状态码固定复杂场景需要动态响应代码简洁性更简洁代码稍显冗长 4. 综合示例结合异常处理
自定义异常类
ResponseStatus(HttpStatus.NOT_FOUND) // 默认返回 404
public class UserNotFoundException extends RuntimeException {public UserNotFoundException(String message) {super(message);}
}使用 ResponseEntity 处理异常
RestController
RequestMapping(/users)
public class UserController {GetMapping(/{id})public ResponseEntityUser getUser(PathVariable Long id) {User user userService.findById(id).orElseThrow(() - new UserNotFoundException(User not found with id: id));return ResponseEntity.ok(user); // 返回 200 和用户信息}ExceptionHandler(UserNotFoundException.class)public ResponseEntityErrorResponse handleUserNotFound(UserNotFoundException ex) {ErrorResponse errorResponse new ErrorResponse(USER_NOT_FOUND, ex.getMessage());return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);}
}ExceptionHandler捕获异常并返回自定义的响应。ErrorResponse自定义的错误响应体。 5. 总结
ResponseStatus适合简单场景状态码固定代码简洁。ResponseEntity适合复杂场景允许动态设置状态码、响应头和响应体。
如果你的需求需要动态响应内容如返回资源位置、错误信息、或自定义头部信息ResponseEntity 是更灵活的选择。通过使用 ResponseEntity我们可以更精确地控制 HTTP 响应的各个方面使 API 更加灵活和专业。这对于构建复杂的 RESTful API 特别有用因为它允许我们根据不同的业务场景返回不同的响应。
RestController/ResponseBody ResponseEntity
使用 RestController 或 ResponseBody 返回对象时Spring 会自动将返回的对象序列化为 JSON 并写入响应体RestController 或 ResponseBody 返回的对象会自动设置状态码为 200 OK。 缺点无法直接设置响应头或动态状态码。使用 RestController 或 ResponseBody 返回对象 如果需要返回特定的 HTTP 状态码可以结合 ResponseEntity 使用。
使用 RestController 或 ResponseBody 直接返回对象时的主要缺点是无法直接设置响应头或动态状态码。以下是这些限制的详细说明和解决方案
1. 基本限制示例
RestController
RequestMapping(/api/users)
public class UserController {// 直接返回对象的方式GetMapping(/{id})ResponseBodypublic User getUser(PathVariable Long id) {return userService.findById(id); // 只能返回 200 OK}// 无法直接设置响应头PostMappingResponseBodypublic User createUser(RequestBody User user) {return userService.save(user); // 应该返回 201 Created但只能是 200 OK}
}2. 主要限制 状态码限制 默认总是返回 200 OK无法动态设置状态码无法返回创建成功201等特定状态码 响应头限制 无法添加自定义响应头无法设置 Content-Disposition 等特殊头部无法控制缓存相关头部 错误处理限制 无法直接返回错误状态码需要依赖全局异常处理
3. 解决方案
方案一使用 ResponseEntity
RestController
RequestMapping(/api/users)
public class UserController {// 使用 ResponseEntity 返回特定状态码PostMappingpublic ResponseEntityUser createUser(RequestBody User user) {User savedUser userService.save(user);return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);}// 设置自定义响应头GetMapping(/{id})public ResponseEntityUser getUser(PathVariable Long id) {return userService.findById(id).map(user - ResponseEntity.ok().header(X-Custom-Header, value).body(user)).orElse(ResponseEntity.notFound().build());}
}方案二使用 HttpServletResponse
RestController
RequestMapping(/api/users)
public class UserController {// 注入 HttpServletResponsePostMapping(/manual)ResponseBodypublic User createUserManual(RequestBody User user,HttpServletResponse response) {User savedUser userService.save(user);response.setStatus(HttpServletResponse.SC_CREATED);response.setHeader(X-Custom-Header, value);return savedUser;}
}方案三使用统一响应包装类
// 统一响应包装类
public class ApiResponseT {private int code;private String message;private T data;private MapString, String headers new HashMap();// 构造方法和静态工厂方法public static T ApiResponseT success(T data) {return new ApiResponse(200, Success, data);}public static T ApiResponseT created(T data) {return new ApiResponse(201, Created, data);}
}// 使用响应包装类的控制器
RestController
RequestMapping(/api/users)
public class UserController {PostMappingpublic ApiResponseUser createUser(RequestBody User user) {User savedUser userService.save(user);return ApiResponse.created(savedUser);}
}// 响应拦截器
Component
public class ApiResponseInterceptor implements ResponseBodyAdviceApiResponse? {Overridepublic boolean supports(MethodParameter returnType, Class? extends HttpMessageConverter? converterType) {return ApiResponse.class.isAssignableFrom(returnType.getParameterType());}Overridepublic ApiResponse? beforeBodyWrite(ApiResponse? body, MethodParameter returnType,MediaType selectedContentType,Class? extends HttpMessageConverter? selectedConverterType,ServerHttpRequest request,ServerHttpResponse response) {if (body ! null) {response.setStatusCode(HttpStatus.valueOf(body.getCode()));body.getHeaders().forEach((key, value) - response.getHeaders().add(key, value));}return body;}
}方案四使用 AOP 拦截
Aspect
Component
public class ResponseHeaderAspect {Around(annotation(responseHeaders))public Object addResponseHeaders(ProceedingJoinPoint joinPoint, ResponseHeaders responseHeaders) throws Throwable {Object result joinPoint.proceed();HttpServletResponse response ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse();if (response ! null) {for (Header header : responseHeaders.value()) {response.setHeader(header.name(), header.value());}}return result;}
}// 自定义注解
Target(ElementType.METHOD)
Retention(RetentionPolicy.RUNTIME)
public interface ResponseHeaders {Header[] value();
}Target(ElementType.METHOD)
Retention(RetentionPolicy.RUNTIME)
public interface Header {String name();String value();
}// 使用示例
RestController
RequestMapping(/api/users)
public class UserController {PostMappingResponseHeaders({Header(name X-Custom-Header, value value),Header(name X-Created-By, value system)})public User createUser(RequestBody User user) {return userService.save(user);}
}方案五使用过滤器
Component
public class ResponseModifierFilter implements Filter {Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {HttpServletResponse httpResponse (HttpServletResponse) response;ContentCachingResponseWrapper responseWrapper new ContentCachingResponseWrapper(httpResponse);chain.doFilter(request, responseWrapper);// 修改响应if (isUserCreationEndpoint(request)) {responseWrapper.setStatus(HttpServletResponse.SC_CREATED);responseWrapper.setHeader(X-Custom-Header, value);}responseWrapper.copyBodyToResponse();}
}特性RestController / ResponseBodyResponseEntityHttpServletResponse默认状态码固定为 200 OK可动态设置可动态设置自定义响应头不支持支持支持动态状态码不支持支持支持代码复杂性简单中等较高推荐场景简单的 RESTful API需要动态状态码或自定义头部的场景特殊场景如文件流、低级操作
详细解释如何使用 RestController 或 ResponseBody 结合 ResponseEntity 来返回对象和特定的 HTTP 状态码。
1. 基本用法
RestController
RequestMapping(/api/users)
public class UserController {PostMappingpublic ResponseEntityUser createUser(RequestBody User user) {User savedUser userService.save(user);return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);}GetMapping(/{id})public ResponseEntityUser getUser(PathVariable Long id) {return userService.findById(id).map(ResponseEntity::ok) // 返回 200 OK.orElse(ResponseEntity.notFound().build()); // 返回 404 Not Found}
}2. 统一响应格式
// 统一响应格式
public class ApiResponseT {private int code; // 状态码private String message; // 消息private T data; // 数据private LocalDateTime timestamp LocalDateTime.now(); // 时间戳// 成功静态方法public static T ApiResponseT success(T data) {return new ApiResponse(200, Success, data);}// 错误静态方法public static T ApiResponseT error(int code, String message) {return new ApiResponse(code, message, null);}// 构造方法、getter和setter
}3. CRUD 操作示例
RestController
RequestMapping(/api/users)
public class UserController {private final UserService userService;// 构造注入public UserController(UserService userService) {this.userService userService;}// 创建用户PostMappingpublic ResponseEntityApiResponseUser createUser(RequestBody Valid User user) {User savedUser userService.save(user);return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(savedUser));}// 获取用户GetMapping(/{id})public ResponseEntityApiResponseUser getUser(PathVariable Long id) {return userService.findById(id).map(user - ResponseEntity.ok(ApiResponse.success(user))).orElse(ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponse.error(404, User not found)));}// 更新用户PutMapping(/{id})public ResponseEntityApiResponseUser updateUser(PathVariable Long id, RequestBody Valid User user) {return userService.findById(id).map(existingUser - {User updatedUser userService.update(id, user);return ResponseEntity.ok(ApiResponse.success(updatedUser));}).orElse(ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponse.error(404, User not found)));}// 删除用户DeleteMapping(/{id})public ResponseEntityApiResponseVoid deleteUser(PathVariable Long id) {if (userService.existsById(id)) {userService.deleteById(id);return ResponseEntity.ok(ApiResponse.success(null));}return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponse.error(404, User not found));}// 获取用户列表分页GetMappingpublic ResponseEntityApiResponsePageUser getUsers(RequestParam(defaultValue 0) int page,RequestParam(defaultValue 10) int size) {PageUser users userService.findAll(PageRequest.of(page, size));return ResponseEntity.ok(ApiResponse.success(users));}
}4. 异常处理
RestControllerAdvice
public class GlobalExceptionHandler {// 处理验证错误ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntityApiResponseMapString, String handleValidationErrors(MethodArgumentNotValidException ex) {MapString, String errors new HashMap();ex.getBindingResult().getFieldErrors().forEach(error - errors.put(error.getField(), error.getDefaultMessage()));return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.error(400, Validation failed, errors));}// 处理业务逻辑异常ExceptionHandler(BusinessException.class)public ResponseEntityApiResponseVoid handleBusinessException(BusinessException ex) {return ResponseEntity.status(ex.getStatus()).body(ApiResponse.error(ex.getStatus().value(), ex.getMessage()));}// 处理其他未知异常ExceptionHandler(Exception.class)public ResponseEntityApiResponseVoid handleUnknownException(Exception ex) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ApiResponse.error(500, Internal server error));}
}5. 自定义业务异常
public class BusinessException extends RuntimeException {private final HttpStatus status;public BusinessException(String message, HttpStatus status) {super(message);this.status status;}public HttpStatus getStatus() {return status;}
}6. 带条件的响应示例
RestController
RequestMapping(/api/orders)
public class OrderController {// 创建订单PostMappingpublic ResponseEntityApiResponseOrder createOrder(RequestBody Valid OrderRequest request) {// 检查库存if (!inventoryService.checkStock(request)) {return ResponseEntity.status(HttpStatus.CONFLICT).body(ApiResponse.error(409, Insufficient stock));}// 检查用户信用if (!userService.checkCredit(request.getUserId())) {return ResponseEntity.status(HttpStatus.PAYMENT_REQUIRED).body(ApiResponse.error(402, Insufficient credit));}// 创建订单Order order orderService.createOrder(request);// 如果是加急订单添加特殊响应头if (request.isUrgent()) {return ResponseEntity.status(HttpStatus.CREATED).header(X-Priority, High).body(ApiResponse.success(order));}return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(order));}
}7. 文件上传响应示例
RestController
RequestMapping(/api/files)
public class FileController {PostMapping(/upload)public ResponseEntityApiResponseFileInfo uploadFile(RequestParam(file) MultipartFile file) {try {FileInfo savedFile fileService.store(file);return ResponseEntity.status(HttpStatus.CREATED).header(Location, /api/files/ savedFile.getId()).body(ApiResponse.success(savedFile));} catch (IOException e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ApiResponse.error(500, Failed to upload file));}}GetMapping(/download/{id})public ResponseEntityResource downloadFile(PathVariable String id) {Resource file fileService.loadAsResource(id);return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, attachment; filename\ file.getFilename() \).body(file);}
}8. 返回流式数据
如果需要返回流式数据如文件下载可以结合 ResponseEntity 和 InputStreamResource。
示例返回文件下载
RestController
RequestMapping(/files)
public class FileController { GetMapping(/download/{filename}) public ResponseEntityInputStreamResource downloadFile(PathVariable String filename) throws IOException { File file fileService.getFile(filename); InputStreamResource resource new InputStreamResource(new FileInputStream(file)); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, attachment; filename file.getName()) .contentLength(file.length()) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(resource); }
} 响应 状态码200 OK 响应头 Content-Disposition: attachment; filenamemyfile.txt 响应体文件内容
9. 使用建议 统一响应格式 使用统一的响应封装类如 ApiResponse包含必要的状态码、消息和数据字段添加时间戳便于调试和日志追踪 适当的状态码 200: 成功获取资源201: 成功创建资源204: 成功处理但无返回内容400: 请求参数错误401: 未认证403: 无权限404: 资源不存在409: 资源冲突500: 服务器错误 异常处理 使用全局异常处理器统一处理异常区分业务异常和系统异常提供清晰的错误信息 响应头设置 根据需要设置自定义响应头文件操作时设置适当的 Content-Type 和 Content-Disposition 验证处理 使用 Valid 注解进行请求验证提供详细的验证错误信息
通过这种方式可以构建出统一、规范的 API 响应便于客户端处理和调试。
10. 最佳实践建议
优先使用 RestController 或 ResponseBody 如果不需要动态设置状态码或响应头直接返回对象即可简单高效。 使用 ResponseEntity 解决局限性 当需要动态设置状态码或自定义响应头时推荐使用 ResponseEntity它是 Spring 提供的标准解决方案代码优雅且易于维护。 仅在特殊场景下使用 HttpServletResponse 如果需要直接操作底层响应流如文件下载、流式数据可以使用 HttpServletResponse。 优先使用 ResponseEntity 最清晰和直接的解决方案提供完整的响应控制类型安全且易于维护 统一响应格式 定义统一的响应包装类使用响应拦截器统一处理便于维护和扩展 分层处理 控制器层业务逻辑和基本响应拦截器层通用响应头和状态码过滤器层全局响应修改 异常处理
RestControllerAdvice
public class GlobalExceptionHandler {ExceptionHandler(Exception.class)public ResponseEntityApiResponseString handleException(Exception ex) {ApiResponseString response ApiResponse.error(500, Internal Server Error,ex.getMessage());return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);}
}文档和注释
/*** 用户控制器* 注意直接返回对象时无法设置状态码和响应头* 建议使用 ResponseEntity 或其他替代方案*/
RestController
RequestMapping(/api/users)
public class UserController {// 控制器方法...
}通过以上方案可以克服 RestController 和 ResponseBody 的限制实现更灵活的响应控制。选择合适的方案取决于具体需求和项目架构。