springboot常见的一些相关注解总结
作者:把csdn当日记本的菜鸡
Spring 注解大全
本文档详细介绍了 Spring 框架中常用的核心注解,帮助开发者更好地理解和使用这些注解。Spring 注解极大地简化了配置,提高了开发效率,是现代 Spring 应用开发的基础。
1. @Controller
@Controller 是 Spring Framework 中用于标记Web 控制器的核心注解,属于 Spring MVC 的核心组件。它用于定义一个类作为处理 HTTP 请求的入口点,负责接收请求、调用业务逻辑并返回视图或数据。
核心作用
- 请求映射:通过 @RequestMapping 或其派生注解(如 @GetMapping、@PostMapping)将 HTTP 请求映射到控制器的方法。
- 视图解析:返回字符串时,Spring 会使用视图解析器(如 Thymeleaf、JSP)将其转换为实际的视图(如 HTML 页面)。
- 数据绑定:自动将请求参数、表单数据或路径变量绑定到方法参数(结合 @RequestParam、@PathVariable 等注解)。
基础用法示例
场景 1:返回视图
@Controller
@RequestMapping("/users")
public class UserController {
// 处理 GET /users/profile?name=John
@GetMapping("/profile")
public String getProfile(@RequestParam String name, Model model) {
model.addAttribute("userName", name); // 将数据传递给视图
return "userProfile"; // 对应视图解析器配置的模板(如 userProfile.html)
}
}
场景 2:返回 JSON 数据(需配合 @ResponseBody)
@Controller
@RequestMapping("/api")
public class ApiController {
// 返回 JSON 数据(需要手动添加 @ResponseBody)
@GetMapping("/data")
@ResponseBody
public User getData() {
return new User("Alice", 30); // 自动转换为 JSON
}
}
@Controller vs @RestController
@Controller:
- 传统 MVC 控制器,默认返回视图名称。若需返回 JSON/XML 等数据,需在方法上添加 @ResponseBody。
@RestController:
- @Controller + @ResponseBody 的组合注解,所有方法默认返回数据而非视图(自动序列化为 JSON/XML)。
@RestController
@RequestMapping("/api")
public class UserRestController {
@GetMapping("/user")
public User getUser() {
return new User("Bob", 25); // 自动返回 JSON
}
}
关键注解配合使用
| 注解 | 作用 | 示例 |
|---|---|---|
| @RequestMapping | 类/方法级请求映射 | @RequestMapping(“/home”) |
| @GetMapping | 快捷注解(GET 请求) | @GetMapping(“/list”) |
| @PostMapping | 快捷注解(POST 请求) | @PostMapping(“/save”) |
| @PathVariable | 绑定 URI 模板变量 | @GetMapping(“/users/{id}”) public User getUser(@PathVariable Long id) |
| @RequestParam | 绑定请求参数 | @RequestParam String name |
| @RequestBody | 绑定请求体数据(JSON/XML) | public void saveUser(@RequestBody User user) |
| @ModelAttribute | 绑定表单数据到对象 | public String handleForm(@ModelAttribute User user) |
高级特性
视图解析器配置
在 Spring Boot 中,默认集成 Thymeleaf 或 FreeMarker,通过 application.properties 配置:
spring.mvc.view.prefix=/WEB-INF/views/ # 视图模板前缀 spring.mvc.view.suffix=.html # 视图模板后缀
会话管理
@SessionAttributes:在控制器类上声明需要存储到会话中的模型属性。
@Controller
@SessionAttributes("user") // 将 "user" 属性存储到会话中
public class SessionController {
@GetMapping("/set")
public String setSession(Model model) {
model.addAttribute("user", new User("Alice"));
return "sessionPage";
}
}
异常处理
@ExceptionHandler:在控制器内处理局部异常。
@Controller
public class ErrorController {
@ExceptionHandler(Exception.class)
public String handleException() {
return "errorPage"; // 异常时返回错误页面
}
}
最佳实践
明确职责分离:
- 控制器负责接收请求和调用服务层,业务逻辑应放在 Service 层。
- 避免在控制器中编写复杂逻辑。
合理使用注解:
- RESTful API 优先使用 @RestController。
- 传统 Web 应用使用 @Controller + 视图解析器。
参数校验:
- 结合 @Valid 和 BindingResult 进行请求参数校验。
@PostMapping("/save")
public String saveUser(@Valid @ModelAttribute User user, BindingResult result) {
if (result.hasErrors()) {
return "formPage"; // 校验失败返回表单
}
// 保存用户...
}
- 静态资源处理:
- 确保静态资源(如 CSS、JS)路径不被控制器拦截,通过 WebMvcConfigurer 配置。
完整示例代码
@Controller
@RequestMapping("/products")
public class ProductController {
// 返回视图(需配置视图解析器)
@GetMapping("/list")
public String listProducts(Model model) {
model.addAttribute("products", productService.getAll());
return "products/list"; // 对应 /templates/products/list.html
}
// 返回 JSON 数据
@GetMapping("/{id}")
@ResponseBody
public Product getProduct(@PathVariable Long id) {
return productService.getById(id);
}
// 处理表单提交
@PostMapping("/save")
public String saveProduct(@Valid @ModelAttribute Product product, BindingResult result) {
if (result.hasErrors()) {
return "products/form";
}
productService.save(product);
return "redirect:/products/list";
}
}
通过合理使用 @Controller 及其相关注解,可以构建出结构清晰、职责分明的 Web 应用,同时兼顾传统 MVC 和 RESTful API 的开发需求。
2. @RestController
@RestController 是 Spring 4.0 引入的组合注解,等价于 @Controller + @ResponseBody。它是构建 RESTful Web 服务的核心注解,专门用于创建 REST API。
核心作用
- 简化 REST API 开发:无需在每个方法上添加 @ResponseBody
- 自动序列化:方法返回值自动序列化为 JSON/XML 格式
- 前后端分离支持:适用于前后端分离架构的后端 API 开发
基本用法
简单 REST 控制器
@RestController
@RequestMapping("/api/users")
public class UserRestController {
@GetMapping
public List<User> getUsers() {
return userService.getAllUsers();
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
@PostMapping
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
return userService.updateUser(id, user);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
}
与其他注解配合使用
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:3000") // 支持跨域
public class UserRestController {
@GetMapping("/user")
public User getUser() {
return new User("Bob", 25); // 自动返回 JSON
}
// 特定方法覆盖类级别的映射
@GetMapping("/admin/user")
@CrossOrigin(origins = "http://admin.example.com")
public User getAdminUser() {
return new User("Admin", 30);
}
}
特点
- 组合注解特性:@RestController = @Controller + @ResponseBody
- 默认返回数据:所有方法默认返回数据而非视图
- 自动序列化:方法返回值会自动序列化为 JSON/XML
- 适用于 RESTful API:专门为 RESTful Web 服务设计
- 减少样板代码:无需在每个方法上添加 @ResponseBody
高级用法示例
1. 自定义响应格式
// 统一响应结果类
public class Result<T> {
private int code;
private String message;
private T data;
// 构造方法、getter 和 setter...
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("success");
result.setData(data);
return result;
}
}
@RestController
@RequestMapping("/api/users")
public class UserRestController {
@GetMapping
public Result<List<User>> getUsers() {
List<User> users = userService.getAllUsers();
return Result.success(users);
}
@GetMapping("/{id}")
public Result<User> getUser(@PathVariable Long id) {
User user = userService.getUserById(id);
return Result.success(user);
}
}
2. 异常处理
@RestController
@RequestMapping("/api/users")
public class UserRestController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
User user = userService.getUserById(id);
if (user == null) {
throw new UserNotFoundException("User not found with id: " + id);
}
return user;
}
}
// 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<Result<String>> handleUserNotFound(UserNotFoundException e) {
Result<String> result = new Result<>();
result.setCode(404);
result.setMessage(e.getMessage());
return ResponseEntity.status(404).body(result);
}
}
最佳实践
专门用于 API 开发:@RestController 专门用于构建 RESTful API,不适用于需要返回视图的场景。
合理组织 URL 结构:使用 @RequestMapping 在类级别定义基础路径,方法级别定义具体操作。
统一响应格式:建议使用统一的响应格式,方便前端处理。
配合异常处理:结合 @RestControllerAdvice 进行全局异常处理,提供一致的错误响应。
启用 CORS:对于前后端分离的应用,合理配置跨域支持。
// 推荐的 RESTful 控制器结构
@RestController
@RequestMapping("/api/v1/users")
@CrossOrigin
public class UserRestController {
@Autowired
private UserService userService;
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userService.findAll();
return ResponseEntity.ok(users);
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
User savedUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(
@PathVariable Long id,
@Valid @RequestBody User user) {
return userService.update(id, user)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteById(id);
return ResponseEntity.noContent().build();
}
}
通过合理使用 @RestController 注解,可以快速构建符合 RESTful 设计规范的 Web API,满足现代 Web 应用的开发需求。
3. @RequestMapping
@RequestMapping 是 Spring MVC 中最基础和重要的注解之一,用于将 Web 请求映射到具体的处理方法上。它可以应用在类级别或方法级别,提供灵活的请求映射配置。
核心作用
- URL 映射:将特定 URL 路径的请求映射到处理方法
- HTTP 方法限定:指定处理的 HTTP 请求方法(GET、POST、PUT、DELETE 等)
- 请求条件匹配:基于请求参数、请求头等条件进行匹配
- 内容类型控制:指定可处理的请求内容类型和返回的内容类型
基本用法
类级别使用
@Controller
@RequestMapping("/users")
public class UserController {
// 实际映射路径为 /users
@RequestMapping("")
public String getUsers() {
return "userList";
}
// 实际映射路径为 /users/create
@RequestMapping("/create")
public String createUserForm() {
return "userCreateForm";
}
// 实际映射路径为 /users
@RequestMapping(method = RequestMethod.POST)
public String createUser() {
// 创建用户逻辑
return "userCreated";
}
}
方法级别使用
@Controller
public class UserController {
@RequestMapping("/users")
public String getUsers() {
return "userList";
}
@RequestMapping(value = "/users", method = RequestMethod.POST)
public String createUser() {
// 创建用户逻辑
return "userCreated";
}
@RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
public String getUser(@PathVariable Long id) {
// 获取用户逻辑
return "userDetail";
}
}
主要属性
| 属性 | 类型 | 说明 |
|---|---|---|
| value/path | String[] | 指定请求的 URL 路径,支持 Ant 风格模式(如 /users/*、/users/**) |
| method | RequestMethod[] | 指定请求的方法类型(GET、POST、PUT、DELETE、PATCH 等) |
| params | String[] | 指定请求参数条件(如 “version=1”、“!version”) |
| headers | String[] | 指定请求头条件(如 “Accept=text/plain”) |
| consumes | String[] | 指定处理请求的提交内容类型(Content-Type) |
| produces | String[] | 指定返回内容的类型(Accept) |
高级用法示例
1. Ant 风格路径匹配
@Controller
@RequestMapping("/files")
public class FileController {
// 匹配 /files/anyfile.txt
@RequestMapping("/*.txt")
public String getTextFile() {
return "textFileView";
}
// 匹配 /files/path/to/anyfile.json
@RequestMapping("/**/*.json")
public String getJsonFile() {
return "jsonFileView";
}
// 匹配 /files/abc 或 /files/def 等
@RequestMapping("/{fileName:^[a-z]+}")
public String getFile(@PathVariable String fileName) {
return "fileView";
}
}
2. 请求参数和头部条件
@Controller
public class ApiController {
// 仅匹配带有 version=2 参数的请求
@RequestMapping(value = "/api/data", params = "version=2")
public String getDataV2() {
return "dataV2";
}
// 仅匹配 Accept 头部为 application/json 的请求
@RequestMapping(value = "/api/data", headers = "Accept=application/json")
@ResponseBody
public String getJsonData() {
return "{\"data\":\"json\"}";
}
// 仅匹配 Content-Type 为 application/json 且 Accept 为 text/html 的请求
@RequestMapping(value = "/api/data",
consumes = "application/json",
produces = "text/html")
public String processData() {
return "processedData";
}
}
3. 多种 HTTP 方法支持
@Controller
@RequestMapping("/api/users")
public class UserController {
// 支持 GET 和 POST 方法
@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})
public String handleUsers(HttpServletRequest request) {
if ("GET".equals(request.getMethod())) {
return "userList";
} else {
return "userCreated";
}
}
// 支持所有 HTTP 方法
@RequestMapping("/{id}")
public String handleUser(@PathVariable Long id, HttpServletRequest request) {
switch (request.getMethod()) {
case "GET": return "userDetail";
case "PUT": return "userUpdated";
case "DELETE": return "userDeleted";
default: return "error";
}
}
}
最佳实践
优先使用派生注解:对于简单的 RESTful API,推荐使用 @GetMapping、@PostMapping 等派生注解,使代码更清晰。
合理组织类级别和方法级别映射:将通用路径前缀放在类级别,具体操作放在方法级别。
避免过于复杂的映射规则:复杂的映射会增加维护难度,应尽量保持简洁。
使用 produces 和 consumes 明确内容类型:有助于提高 API 的可读性和正确性。
// 推荐的 RESTful 风格
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
public List<User> getUsers() {
return userService.getAllUsers();
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
@PostMapping(consumes = "application/json")
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
return userService.updateUser(id, user);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
}
通过合理使用 @RequestMapping 注解及其派生注解,可以构建出清晰、规范的 Web API 接口。
4. @RequestParam
@RequestParam 注解用于将 HTTP 请求参数(查询参数或表单参数)绑定到方法参数上。它是处理客户端传递参数的重要注解。
核心作用
- 参数绑定:将请求中的参数值自动绑定到方法参数
- 类型转换:自动将字符串参数转换为相应的 Java 类型
- 参数验证:通过 required 属性控制参数是否必须
- 默认值设置:通过 defaultValue 属性设置参数默认值
基本用法
简单参数绑定
@GetMapping("/users/search")
public String searchUsers(@RequestParam("name") String name,
@RequestParam("age") Integer age) {
// 处理请求参数
// 例如:/users/search?name=Tom&age=25
return "userList";
}
可选参数和默认值
@GetMapping("/users")
public String getUsers(@RequestParam(value = "page", defaultValue = "1") Integer page,
@RequestParam(value = "size", defaultValue = "10") Integer size,
@RequestParam(value = "sort", required = false) String sort) {
// page 和 size 参数有默认值,即使不传也会有值
// sort 参数是可选的,不传时为 null
return "userList";
}
数组和集合参数
@GetMapping("/users/batch")
public String batchDelete(@RequestParam("ids") Long[] ids) {
// 处理多个 ID
// 例如:/users/batch?ids=1&ids=2&ids=3
return "batchDeleted";
}
@GetMapping("/users/filter")
public String filterUsers(@RequestParam("tags") List<String> tags) {
// 处理标签列表
// 例如:/users/filter?tags=VIP&tags=Active
return "filteredList";
}
主要属性
| 属性 | 类型 | 说明 |
|---|---|---|
| value/name | String | 指定要绑定的请求参数名称 |
| required | boolean | 是否必须存在该参数,默认为 true |
| defaultValue | String | 默认值,当参数不存在时使用(设置后 required 自动为 false) |
高级用法示例
1. 复杂对象参数绑定
// 用户搜索条件类
public class UserSearchCriteria {
private String name;
private Integer age;
private String email;
// getter 和 setter 方法...
}
@Controller
public class UserController {
// 通过 @RequestParam 绑定复杂对象的属性
@GetMapping("/users/search")
public String searchUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer age,
@RequestParam(required = false) String email,
Model model) {
UserSearchCriteria criteria = new UserSearchCriteria();
criteria.setName(name);
criteria.setAge(age);
criteria.setEmail(email);
List<User> users = userService.searchUsers(criteria);
model.addAttribute("users", users);
return "userList";
}
}
2. 参数验证
@GetMapping("/users/page")
public String getUsersPaginated(
@RequestParam(value = "page", defaultValue = "1")
@Min(1) Integer page,
@RequestParam(value = "size", defaultValue = "10")
@Min(1) @Max(100) Integer size) {
// 使用 Bean Validation 进行参数验证
// page 必须大于等于 1
// size 必须在 1-100 之间
return "userList";
}
最佳实践
合理使用 defaultValue:对于分页、排序等场景,设置合理的默认值可以提高用户体验。
注意 required 属性:设置了 defaultValue 后,required 属性会自动设为 false。
类型转换注意事项:确保请求参数能够正确转换为目标类型,避免类型转换异常。
处理集合参数:对于需要传递多个同名参数的场景,可以使用数组或集合类型。
// 推荐的参数处理方式
@RestController
@RequestMapping("/api/users")
public class UserController {
// 分页查询
@GetMapping
public Page<User> getUsers(
@RequestParam(value = "page", defaultValue = "0") int page,
@RequestParam(value = "size", defaultValue = "20") int size,
@RequestParam(value = "sort", defaultValue = "id") String sort) {
return userService.getUsers(PageRequest.of(page, size, Sort.by(sort)));
}
// 搜索功能
@GetMapping("/search")
public List<User> searchUsers(
@RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "department", required = false) String department) {
return userService.searchUsers(keyword, department);
}
}
通过合理使用 @RequestParam 注解,可以轻松处理各种请求参数场景,使 Web 接口更加灵活和易用。
5. @PathVariable
@PathVariable 注解用于将 URI 模板变量绑定到方法参数上,是 RESTful API 设计中的重要注解。它允许从 URL 路径中提取变量值。
核心作用
- 路径变量提取:从 URL 路径中提取指定的变量值
- RESTful 风格支持:支持 RESTful 风格的 URL 设计
- 类型自动转换:自动将路径变量转换为相应的 Java 类型
- 正则表达式支持:支持使用正则表达式对路径变量进行约束
基本用法
简单路径变量
@GetMapping("/users/{id}")
public String getUser(@PathVariable("id") Long id) {
// 处理 /users/123 这样的请求
// id 参数值为 123
return "userDetail";
}
// 当方法参数名与路径变量名一致时,可以省略 value 属性
@GetMapping("/users/{id}")
public String getUser(@PathVariable Long id) {
return "userDetail";
}
多个路径变量
// 多个路径变量
@GetMapping("/users/{userId}/orders/{orderId}")
public String getOrder(@PathVariable("userId") Long userId,
@PathVariable("orderId") Long orderId) {
return "orderDetail";
}
// 混合使用路径变量和请求参数
@GetMapping("/users/{userId}/orders")
public String getUserOrders(@PathVariable("userId") Long userId,
@RequestParam(value = "status", required = false) String status) {
return "orderList";
}
主要属性
| 属性 | 类型 | 说明 |
|---|---|---|
| value/name | String | 指定要绑定的路径变量名称 |
| required | boolean | 是否必须存在该路径变量,默认为 true |
高级用法示例
1. 正则表达式约束
@RestController
public class FileController {
// 限制 id 只能是数字
@GetMapping("/files/{id:\\d+}")
public String getFile(@PathVariable Long id) {
return "fileContent";
}
// 限制文件名格式
@GetMapping("/images/{filename:.+\\.(jpg|png|gif)}")
public String getImage(@PathVariable String filename) {
return "imageContent";
}
// 日期格式约束
@GetMapping("/events/{date:\\d{4}-\\d{2}-\\d{2}}")
public String getEvent(@PathVariable("date") String date) {
return "eventDetail";
}
}
2. 复杂路径变量处理
@RestController
@RequestMapping("/api")
public class ResourceController {
// 处理版本化的 API
@GetMapping("/v{version:\\d+}/users/{userId}")
public String getUser(@PathVariable Integer version,
@PathVariable Long userId) {
if (version < 2) {
// 返回旧版本数据格式
return "userOldFormat";
} else {
// 返回新版本数据格式
return "userNewFormat";
}
}
// 处理多级路径
@GetMapping("/categories/{categoryPath:.+}")
public String getCategory(@PathVariable String categoryPath) {
// categoryPath 可以包含多级路径,如 "electronics/computers/laptops"
String[] paths = categoryPath.split("/");
return "categoryDetail";
}
}
最佳实践
路径变量命名规范:使用有意义的变量名,提高代码可读性。
类型安全:选择合适的 Java 类型,避免类型转换异常。
正则表达式约束:对路径变量使用正则表达式进行约束,提高 API 的健壮性。
避免敏感信息:不要在路径变量中传递敏感信息,如密码、密钥等。
// 推荐的 RESTful 风格设计
@RestController
@RequestMapping("/api")
public class UserController {
// 获取用户信息
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
// 获取用户的订单
@GetMapping("/users/{userId}/orders")
public List<Order> getUserOrders(@PathVariable Long userId) {
return orderService.getOrdersByUserId(userId);
}
// 获取订单详情
@GetMapping("/users/{userId}/orders/{orderId}")
public Order getOrder(@PathVariable Long userId,
@PathVariable Long orderId) {
return orderService.getOrder(userId, orderId);
}
}
通过合理使用 @PathVariable 注解,可以构建出符合 RESTful 设计规范的 Web API,使 URL 更加直观和易于理解。
6. @GetMapping
@GetMapping 是 Spring 4.3 引入的组合注解,等价于 @RequestMapping(method = RequestMethod.GET)。它是处理 HTTP GET 请求的快捷方式,专门用于数据查询操作。
核心作用
- 简化 GET 请求映射:替代 @RequestMapping(method = RequestMethod.GET)
- 语义明确:明确表示该方法处理 GET 请求
- 提高可读性:使代码更加简洁和易读
基本用法
简单查询操作
@RestController
@RequestMapping("/api/users")
public class UserController {
// 查询所有用户
@GetMapping
public List<User> getUsers() {
return userService.getAllUsers();
}
// 根据 ID 查询用户
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
// 带查询参数的 GET 请求
@GetMapping(params = "name")
public List<User> getUsersByName(@RequestParam String name) {
return userService.getUsersByName(name);
}
}
复杂查询场景
@RestController
@RequestMapping("/api/products")
public class ProductController {
// 分页查询
@GetMapping
public Page<Product> getProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "name") String sortBy) {
return productService.getProducts(PageRequest.of(page, size, Sort.by(sortBy)));
}
// 条件查询
@GetMapping("/search")
public List<Product> searchProducts(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) String category,
@RequestParam(required = false) BigDecimal minPrice,
@RequestParam(required = false) BigDecimal maxPrice) {
return productService.searchProducts(keyword, category, minPrice, maxPrice);
}
// 查询统计信息
@GetMapping("/count")
public long getProductCount() {
return productService.count();
}
}
主要属性
@GetMapping 注解继承了 @RequestMapping 的所有属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| value/path | String[] | 指定请求的 URL 路径 |
| params | String[] | 指定请求参数条件 |
| headers | String[] | 指定请求头条件 |
| consumes | String[] | 指定处理请求的提交内容类型 |
| produces | String[] | 指定返回内容的类型 |
高级用法示例
1. 条件映射
@RestController
@RequestMapping("/api/data")
public class DataController {
// 仅当请求包含 version=2 参数时匹配
@GetMapping(params = "version=2")
public String getDataV2() {
return "data version 2";
}
// 仅当请求包含 format=json 参数时匹配
@GetMapping(params = "format=json", produces = "application/json")
@ResponseBody
public Map<String, Object> getJsonData() {
Map<String, Object> data = new HashMap<>();
data.put("message", "json data");
return data;
}
// 仅当 Accept 头部为 text/xml 时匹配
@GetMapping(produces = "text/xml")
public String getXmlData() {
return "<data>xml data</data>";
}
}
2. 与其他注解配合
@RestController
@RequestMapping("/api/users")
public class UserController {
// 结合缓存注解
@GetMapping("/{id}")
@Cacheable(value = "users", key = "#id")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
// 结合权限控制
@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public List<User> getAllUsers() {
return userService.getAllUsers();
}
// 异步处理
@GetMapping("/async")
public Callable<String> getAsyncData() {
return () -> {
// 模拟耗时操作
Thread.sleep(1000);
return "async data";
};
}
}
最佳实践
专门用于查询操作:@GetMapping 专门用于处理查询请求,符合 HTTP 方法语义。
幂等性保证:GET 请求应该是幂等的,不应产生副作用。
合理使用缓存:对于频繁查询的数据,可以结合缓存机制提高性能。
避免敏感信息:不要在 GET 请求的 URL 中传递敏感信息,因为 URL 可能被记录在日志中。
参数验证:对于复杂的查询参数,应进行适当的验证。
// 推荐的查询接口设计
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// 基础查询
@GetMapping
public ResponseEntity<Page<User>> getUsers(
@RequestParam(defaultValue = "0") @Min(0) int page,
@RequestParam(defaultValue = "10") @Min(1) @Max(100) int size) {
Page<User> users = userService.findAll(PageRequest.of(page, size));
return ResponseEntity.ok(users);
}
// 条件查询
@GetMapping(params = "name")
public ResponseEntity<List<User>> getUsersByName(
@RequestParam String name,
@RequestParam(defaultValue = "false") boolean exact) {
List<User> users = exact ?
userService.findByName(name) :
userService.findByNameContaining(name);
return ResponseEntity.ok(users);
}
// 统计查询
@GetMapping("/statistics")
public ResponseEntity<Map<String, Object>> getUserStatistics() {
Map<String, Object> statistics = userService.getStatistics();
return ResponseEntity.ok(statistics);
}
}
通过合理使用 @GetMapping 注解,可以构建出语义清晰、易于维护的查询接口,提高 Web API 的质量和可读性。
7. @PostMapping
@PostMapping 是 Spring 4.3 引入的组合注解,等价于 @RequestMapping(method = RequestMethod.POST)。它是处理 HTTP POST 请求的快捷方式,专门用于创建资源和提交数据操作。
核心作用
- 简化 POST 请求映射:替代 @RequestMapping(method = RequestMethod.POST)
- 语义明确:明确表示该方法处理 POST 请求
- 提高可读性:使代码更加简洁和易读
- 资源创建:主要用于创建新资源
基本用法
创建资源
@RestController
@RequestMapping("/api/users")
public class UserController {
// 创建新用户
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
User savedUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
// 创建用户的订单
@PostMapping("/{userId}/orders")
public ResponseEntity<Order> createOrder(
@PathVariable Long userId,
@RequestBody Order order) {
Order savedOrder = orderService.createOrder(userId, order);
return ResponseEntity.status(HttpStatus.CREATED).body(savedOrder);
}
}
表单提交处理
@Controller
@RequestMapping("/users")
public class UserController {
// 处理表单提交
@PostMapping("/register")
public String registerUser(@ModelAttribute User user, BindingResult result) {
if (result.hasErrors()) {
return "registerForm";
}
userService.save(user);
return "redirect:/users/" + user.getId();
}
// 文件上传
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
// 处理文件上传逻辑
redirectAttributes.addFlashAttribute("message",
"文件上传成功: " + file.getOriginalFilename());
return "redirect:/users/status";
}
}
主要属性
@PostMapping 注解继承了 @RequestMapping 的所有属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| value/path | String[] | 指定请求的 URL 路径 |
| params | String[] | 指定请求参数条件 |
| headers | String[] | 指定请求头条件 |
| consumes | String[] | 指定处理请求的提交内容类型 |
| produces | String[] | 指定返回内容的类型 |
高级用法示例
1. 内容类型限定
@RestController
@RequestMapping("/api/data")
public class DataController {
// 仅处理 JSON 格式的请求
@PostMapping(consumes = "application/json")
public ResponseEntity<String> handleJsonData(@RequestBody Map<String, Object> data) {
// 处理 JSON 数据
return ResponseEntity.ok("JSON data processed");
}
// 仅处理 XML 格式的请求
@PostMapping(consumes = "application/xml", produces = "application/xml")
public ResponseEntity<String> handleXmlData(@RequestBody String xmlData) {
// 处理 XML 数据
String response = "<response>XML data processed</response>";
return ResponseEntity.ok(response);
}
// 仅处理表单数据
@PostMapping(consumes = "application/x-www-form-urlencoded")
public ResponseEntity<String> handleFormData(@RequestParam Map<String, String> formData) {
// 处理表单数据
return ResponseEntity.ok("Form data processed");
}
}
2. 与其他注解配合
@RestController
@RequestMapping("/api/users")
public class UserController {
// 结合验证注解
@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody User user,
BindingResult result) {
if (result.hasErrors()) {
return ResponseEntity.badRequest().build();
}
User savedUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
// 结合事务注解
@PostMapping("/batch")
@Transactional
public ResponseEntity<List<User>> createUsers(@RequestBody List<User> users) {
List<User> savedUsers = userService.saveAll(users);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUsers);
}
// 结合安全注解
@PostMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<User> createAdminUser(@RequestBody User user) {
user.setRole("ADMIN");
User savedUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
}
最佳实践
幂等性考虑:POST 请求通常不是幂等的,多次执行会产生不同的结果。
返回 201 状态码:创建资源成功时应返回 HTTP 201 (CREATED) 状态码。
返回 Location 头部:创建资源后,应在响应中包含 Location 头部,指向新创建的资源。
参数验证:对传入的数据进行验证,确保数据的完整性和正确性。
事务处理:对于涉及多个操作的复杂创建逻辑,应使用事务确保数据一致性。
// 推荐的资源创建接口设计
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody User user,
HttpServletRequest request) {
// 保存用户
User savedUser = userService.save(user);
// 构建资源 URI
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(savedUser.getId())
.toUri();
// 返回 201 状态码和 Location 头部
return ResponseEntity.created(location).body(savedUser);
}
// 批量创建
@PostMapping("/batch")
public ResponseEntity<List<User>> createUsers(@Valid @RequestBody List<User> users) {
if (users.size() > 100) {
return ResponseEntity.badRequest().build();
}
List<User> savedUsers = userService.saveAll(users);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUsers);
}
}
通过合理使用 @PostMapping 注解,可以构建出符合 HTTP 语义的资源创建接口,提供良好的 RESTful API 体验。
8. @DeleteMapping
@DeleteMapping 是 Spring 4.3 引入的组合注解,等价于 @RequestMapping(method = RequestMethod.DELETE)。它是处理 HTTP DELETE 请求的快捷方式,专门用于删除资源操作。
核心作用
- 简化 DELETE 请求映射:替代 @RequestMapping(method = RequestMethod.DELETE)
- 语义明确:明确表示该方法处理 DELETE 请求
- 提高可读性:使代码更加简洁和易读
- 资源删除:主要用于删除指定资源
基本用法
删除单个资源
@RestController
@RequestMapping("/api/users")
public class UserController {
// 根据 ID 删除用户
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteById(id);
return ResponseEntity.noContent().build();
}
// 条件删除
@DeleteMapping(params = "status")
public ResponseEntity<Void> deleteUsersByStatus(@RequestParam String status) {
userService.deleteByStatus(status);
return ResponseEntity.noContent().build();
}
}
批量删除
@RestController
@RequestMapping("/api/users")
public class UserController {
// 批量删除用户
@DeleteMapping("/batch")
public ResponseEntity<Void> deleteUsers(@RequestBody List<Long> ids) {
userService.deleteAllById(ids);
return ResponseEntity.noContent().build();
}
// 删除所有用户(谨慎使用)
@DeleteMapping
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Void> deleteAllUsers() {
userService.deleteAll();
return ResponseEntity.noContent().build();
}
}
主要属性
@DeleteMapping 注解继承了 @RequestMapping 的所有属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| value/path | String[] | 指定请求的 URL 路径 |
| params | String[] | 指定请求参数条件 |
| headers | String[] | 指定请求头条件 |
| consumes | String[] | 指定处理请求的提交内容类型 |
| produces | String[] | 指定返回内容的类型 |
高级用法示例
1. 软删除实现
@RestController
@RequestMapping("/api/users")
public class UserController {
// 软删除:标记为已删除而不是物理删除
@DeleteMapping("/{id}")
public ResponseEntity<Void> softDeleteUser(@PathVariable Long id) {
userService.softDelete(id);
return ResponseEntity.noContent().build();
}
// 永久删除
@DeleteMapping("/{id}/permanent")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Void> permanentDeleteUser(@PathVariable Long id) {
userService.permanentDelete(id);
return ResponseEntity.noContent().build();
}
}
2. 关联删除
@RestController
@RequestMapping("/api/users")
public class UserController {
// 删除用户及其关联数据
@DeleteMapping("/{id}")
@Transactional
public ResponseEntity<Void> deleteUserWithRelations(
@PathVariable Long id,
@RequestParam(defaultValue = "false") boolean cascade) {
if (cascade) {
// 级联删除关联数据
orderService.deleteByUserId(id);
userService.deleteById(id);
} else {
// 检查是否有关联数据
if (orderService.existsByUserId(id)) {
return ResponseEntity.status(HttpStatus.CONFLICT).build();
}
userService.deleteById(id);
}
return ResponseEntity.noContent().build();
}
}
最佳实践
幂等性:DELETE 请求应该是幂等的,多次删除同一个资源应该返回相同的结果。
返回 204 状态码:删除成功时通常返回 HTTP 204 (NO CONTENT) 状态码。
安全性考虑:删除操作应该谨慎处理,特别是批量删除和删除所有数据的操作。
权限控制:删除敏感资源时应进行权限验证。
软删除:对于重要数据,建议使用软删除而不是物理删除。
// 推荐的删除接口设计
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(
@PathVariable Long id,
Authentication authentication) {
// 检查资源是否存在
if (!userService.existsById(id)) {
return ResponseEntity.notFound().build();
}
// 检查权限
if (!userService.canDelete(id, authentication)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
// 执行删除
userService.deleteById(id);
// 返回 204 状态码
return ResponseEntity.noContent().build();
}
// 批量删除
@DeleteMapping("/batch")
public ResponseEntity<Map<String, Object>> deleteUsers(@RequestBody List<Long> ids) {
Map<String, Object> result = new HashMap<>();
try {
int deletedCount = userService.deleteAllById(ids);
result.put("deletedCount", deletedCount);
result.put("totalCount", ids.size());
return ResponseEntity.ok(result);
} catch (Exception e) {
result.put("error", e.getMessage());
return ResponseEntity.badRequest().body(result);
}
}
}
通过合理使用 @DeleteMapping 注解,可以构建出符合 HTTP 语义的资源删除接口,提供安全可靠的删除操作。
9. @ResponseBody
@ResponseBody 是 Spring MVC 中的重要注解,用于指示方法返回值应直接写入 HTTP 响应体中,而不是被视图解析器解析为视图名称。它是构建 RESTful API 的关键注解之一。
核心作用
- 响应体直接输出:将方法返回值直接写入 HTTP 响应体
- 自动序列化:自动将 Java 对象序列化为 JSON、XML 等格式
- 视图解析绕过:跳过视图解析器,直接返回数据
- RESTful 支持:支持构建 RESTful Web 服务
基本用法
在方法上使用
@Controller
@RequestMapping("/api")
public class ApiController {
// 返回 JSON 数据
@GetMapping("/user")
@ResponseBody
public User getUser() {
return new User("Alice", 30); // 自动转换为 JSON
}
// 返回字符串数据
@GetMapping("/message")
@ResponseBody
public String getMessage() {
return "Hello, World!";
}
// 返回集合数据
@GetMapping("/users")
@ResponseBody
public List<User> getUsers() {
return Arrays.asList(new User("Alice", 30), new User("Bob", 25));
}
}
在类上使用
// 等价于在每个方法上添加 @ResponseBody
@RestController // @RestController = @Controller + @ResponseBody
@RequestMapping("/api/users")
public class UserRestController {
@GetMapping
public List<User> getUsers() {
return userService.getAllUsers();
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
}
特点
- 自动序列化:返回值会自动序列化为 JSON/XML
- 绕过视图解析:不经过视图解析器
- 适用于 RESTful API:专门用于构建 RESTful Web 服务
- 内容协商:根据请求的 Accept 头部返回相应格式的数据
高级用法示例
1. 自定义序列化
@Controller
public class DataController {
// 返回自定义格式的数据
@GetMapping(value = "/data", produces = "application/json")
@ResponseBody
public String getJsonData() {
return "{"name": "Alice", "age": 30}";
}
// 返回 XML 数据
@GetMapping(value = "/data.xml", produces = "application/xml")
@ResponseBody
public String getXmlData() {
return "<user><name>Alice</name><age>30</age></user>";
}
// 返回二进制数据
@GetMapping(value = "/image", produces = "image/png")
@ResponseBody
public byte[] getImage() throws IOException {
// 返回图片数据
return Files.readAllBytes(Paths.get("path/to/image.png"));
}
}
2. ResponseEntity 结合使用
@Controller
public class UserController {
// 使用 ResponseEntity 提供更多控制
@GetMapping("/user/{id}")
@ResponseBody
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.getUserById(id);
if (user != null) {
return ResponseEntity.ok(user);
} else {
return ResponseEntity.notFound().build();
}
}
// 带自定义头部的响应
@PostMapping("/user")
@ResponseBody
public ResponseEntity<User> createUser(@RequestBody User user) {
User savedUser = userService.save(user);
return ResponseEntity
.created(URI.create("/api/user/" + savedUser.getId()))
.header("X-Custom-Header", "CustomValue")
.body(savedUser);
}
}
最佳实践
优先使用 @RestController:对于 RESTful API,优先使用 @RestController 而不是在每个方法上添加 @ResponseBody。
合理设置 Content-Type:使用 produces 属性明确指定返回内容类型。
异常处理:结合 @ExceptionHandler 或 @ControllerAdvice 处理序列化异常。
大数据处理:对于大文件下载等场景,考虑使用 StreamingResponseBody。
// 推荐的 RESTful API 设计
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// 查询所有用户
@GetMapping(produces = "application/json")
public ResponseEntity<List<User>> getUsers() {
List<User> users = userService.findAll();
return ResponseEntity.ok(users);
}
// 根据 ID 查询用户
@GetMapping(value = "/{id}", produces = "application/json")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// 创建用户
@PostMapping(consumes = "application/json", produces = "application/json")
public ResponseEntity<User> createUser(@Valid @RequestBody User user,
HttpServletRequest request) {
User savedUser = userService.save(user);
// 构建资源 URI
URI location = ServletUriComponentsBuilder
.fromContextPath(request)
.path("/api/users/{id}")
.buildAndExpand(savedUser.getId())
.toUri();
return ResponseEntity.created(location).body(savedUser);
}
}
通过合理使用 @ResponseBody 注解,可以轻松构建出能够返回各种格式数据的 Web API,满足现代 Web 应用的多样化需求。
10. @Service
@Service 是 Spring Framework 中用于标记业务逻辑层组件的核心注解,属于 Spring 的典型分层架构注解之一。它将类标识为 Spring 容器管理的服务 Bean,通常用于处理业务逻辑。
核心作用
- 业务逻辑标识:明确标识业务逻辑层组件,提高代码可读性
- 自动注册:标记的类会自动注册为 Spring 容器中的 Bean
- 依赖注入支持:可被其他组件通过 @Autowired 等注解注入使用
- 事务管理集成:与 Spring 事务管理机制无缝集成
基本用法
简单服务类
@Service
public class UserService {
public User queryById(Long id) {
return userMapper.findById(id);
}
public List<User> getAllUsers() {
return userMapper.findAll();
}
public User saveUser(User user) {
return userMapper.save(user);
}
}
带名称的服务类
@Service("userService")
public class UserServiceImpl implements UserService {
@Override
public User queryById(Long id) {
return userMapper.findById(id);
}
}
特点
- 组件扫描支持:@Service 是 @Component 的特化,会被组件扫描自动发现
- 默认单例模式:Spring 容器中默认以单例模式管理服务 Bean
- 依赖注入支持:可被其他组件通过 @Autowired、@Resource 等注解注入
- 生命周期管理:支持 @PostConstruct 和 @PreDestroy 等生命周期注解
高级用法示例
1. 事务管理
@Service
@Transactional
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional(readOnly = true)
public User findById(Long id) {
return userMapper.findById(id);
}
// 默认具有事务支持
public User save(User user) {
User savedUser = userMapper.save(user);
// 可能的其他业务逻辑
return savedUser;
}
// 需要新事务的方法
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logUserAction(Long userId, String action) {
// 记录用户操作日志
}
}
2. 与其他注解配合
@Service
@Scope("prototype") // 每次请求创建新实例
@Primary // 标记为主要实现
public class DefaultUserService implements UserService {
@Autowired
private UserRepository userRepository;
@Override
@Cacheable("users") // 启用缓存
public User findById(Long id) {
return userRepository.findById(id);
}
@Override
@CacheEvict(value = "users", key = "#user.id") // 更新时清除缓存
public User save(User user) {
return userRepository.save(user);
}
}
最佳实践
明确业务边界:每个服务类应该具有明确的业务职责,遵循单一职责原则。
合理使用事务:
- 在服务层配置事务管理
- 根据业务需求设置合适的事务传播行为
- 读取操作使用 readOnly = true 提高性能
异常处理:在服务层处理业务异常,避免将底层异常直接抛出。
接口与实现分离:定义服务接口,通过实现类添加 @Service 注解。
// 推荐的服务层设计
@Service
@Transactional(readOnly = true)
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private UserValidator userValidator;
@Override
public User findById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("User not found: " + id));
}
@Override
@Transactional
public User save(User user) {
// 参数验证
userValidator.validate(user);
// 保存用户
User savedUser = userRepository.save(user);
// 发布事件
applicationEventPublisher.publishEvent(new UserSavedEvent(savedUser));
return savedUser;
}
@Override
@Transactional
public void deleteById(Long id) {
User user = findById(id);
userRepository.delete(user);
// 清理相关资源
cleanupRelatedResources(user);
}
private void cleanupRelatedResources(User user) {
// 清理用户相关的资源
}
}
通过合理使用 @Service 注解,可以构建出结构清晰、职责分明的业务逻辑层,提高代码的可维护性和可测试性。
11. @Autowired
@Autowired 是 Spring Framework 中实现依赖注入(DI)的核心注解之一。它用于自动装配 Bean 之间的依赖关系,是 Spring IoC 容器实现控制反转的关键机制。
核心作用
- 自动装配:自动将匹配的 Bean 注入到字段、构造函数或方法中
- 解耦合:降低组件间的耦合度,提高代码的可测试性和可维护性
- 简化配置:减少 XML 配置或 Java 配置的工作量
- 类型安全:基于类型进行装配,提供编译时和运行时的安全性
基本用法
字段注入
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User queryById(Long id) {
return userMapper.findById(id);
}
}
构造函数注入
@Service
public class UserService {
private final UserMapper userMapper;
// Spring 4.3+ 后,单构造函数场景下可省略 @Autowired
@Autowired
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
public User queryById(Long id) {
return userMapper.findById(id);
}
}
方法注入
@Service
public class UserService {
private UserMapper userMapper;
@Autowired
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
public User queryById(Long id) {
return userMapper.findById(id);
}
}
主要属性
| 属性 | 类型 | 说明 |
|---|---|---|
| required | boolean | 是否必须找到匹配的 Bean,默认为 true。设置为 false 时,找不到匹配的 Bean 不会抛出异常 |
高级用法示例
1. 集合注入
@Service
public class PaymentService {
// 注入所有 PaymentProcessor 的实现
@Autowired
private List<PaymentProcessor> paymentProcessors;
// 注入所有 PaymentProcessor 实现及其名称
@Autowired
private Map<String, PaymentProcessor> paymentProcessorMap;
public void processPayment(String type, BigDecimal amount) {
PaymentProcessor processor = paymentProcessorMap.get(type + "PaymentProcessor");
if (processor != null) {
processor.process(amount);
}
}
}
2. 泛型注入
@Service
public class GenericService {
// 注入 String 类型的 Repository
@Autowired
private GenericRepository<String> stringRepository;
// 注入 Integer 类型的 Repository
@Autowired
private GenericRepository<Integer> integerRepository;
}
3. 条件注入
@Service
public class ConditionalService {
// 可选注入,如果找不到 Bean 则为 null
@Autowired(required = false)
private OptionalFeature optionalFeature;
public void performOperation() {
// 使用可选功能
if (optionalFeature != null) {
optionalFeature.perform();
}
// 其他操作
}
}
最佳实践
优先使用构造函数注入:
- 保证依赖不可变性(final 字段)
- 确保依赖完整性(避免 NullPointerException)
- 提高类的可测试性
避免循环依赖:
- 重新设计组件结构
- 使用 @Lazy 注解延迟加载
- 考虑使用 Setter 注入解决循环依赖
合理使用 required 属性:
- 对于必须的依赖保持 required = true(默认值)
- 对于可选的依赖设置 required = false
// 推荐的依赖注入方式
@Service
public class UserService {
private final UserRepository userRepository;
private final EmailService emailService;
// 构造函数注入(推荐)
public UserService(UserRepository userRepository,
@Autowired(required = false) EmailService emailService) {
this.userRepository = userRepository;
this.emailService = emailService;
}
public User createUser(User user) {
User savedUser = userRepository.save(user);
// 可选功能
if (emailService != null) {
emailService.sendWelcomeEmail(savedUser);
}
return savedUser;
}
}
通过合理使用 @Autowired 注解,可以实现松耦合、高内聚的组件设计,提高代码的可维护性和可测试性。
12. @Resource
@Resource 是 Java 标准注解(JSR-250)中用于依赖注入的注解,与 Spring 的 @Autowired 注解功能相似但装配机制不同。它提供了更灵活的装配方式,支持按名称或类型进行装配。
核心作用
- 标准化依赖注入:作为 Java 标准注解,提供跨框架的依赖注入能力
- 灵活装配机制:支持按名称或类型装配,优先按名称装配
- 减少框架绑定:使用标准注解降低对特定框架的依赖
- 兼容性支持:在不同 Java EE 兼容框架中保持一致性
基本用法
默认装配
@Service
public class UserService {
// 按字段名称装配,如果找不到则按类型装配
@Resource
private UserMapper userMapper;
public User queryById(Long id) {
return userMapper.findById(id);
}
}
按名称装配
@Service
public class UserService {
// 明确按名称装配
@Resource(name = "userDatabaseMapper")
private UserMapper userMapper;
// 装配特定名称的 DAO
@Resource(name = "jdbcUserDao")
private UserDao userDao;
}
按类型装配
@Service
public class UserService {
// 按类型装配,忽略字段名称
@Resource(type = UserMapper.class)
private UserMapper userMapper;
}
主要属性
| 属性 | 类型 | 说明 |
|---|---|---|
| name | String | 指定要注入的 Bean 名称,按名称装配 |
| type | Class | 指定要注入的 Bean 类型,按类型装配 |
@Autowired 与 @Resource 的区别
| 特性 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring 框架 | Java 标准 (JSR-250) |
| 装配方式 | 默认按类型装配 | 默认按名称装配,名称不存在时按类型装配 |
| 属性 | required | name, type |
| 适用场景 | Spring 特定项目 | 跨框架通用项目 |
| 性能 | 略快 | 略慢(需解析名称和类型) |
高级用法示例
1. 混合使用场景
@Service
public class PaymentService {
// 使用 @Resource 按名称装配特定支付处理器
@Resource(name = "alipayProcessor")
private PaymentProcessor alipayProcessor;
// 使用 @Autowired 按类型装配所有支付处理器
@Autowired
private List<PaymentProcessor> allProcessors;
public void processPayment(String type, BigDecimal amount) {
switch (type) {
case "alipay":
alipayProcessor.process(amount);
break;
default:
// 使用其他处理器
break;
}
}
}
2. 在不同环境中切换实现
@Component
@Profile("production")
public class ProductionEmailService implements EmailService {
// 生产环境实现
}
@Component
@Profile("development")
public class DevelopmentEmailService implements EmailService {
// 开发环境实现
}
@Service
public class NotificationService {
// 在不同环境中自动切换实现
@Resource
private EmailService emailService;
public void sendNotification(String message) {
emailService.send(message);
}
}
最佳实践
选择合适的注解:
- 在纯 Spring 项目中优先使用 @Autowired
- 在需要跨框架兼容的项目中使用 @Resource
明确装配策略:
- 需要精确控制时使用 name 或 type 属性
- 一般情况下可依赖默认装配机制
保持一致性:
- 在同一项目中保持依赖注入注解的使用一致性
- 团队内部应制定明确的编码规范
// 推荐的 @Resource 使用方式
@Service
public class OrderService {
// 明确按名称装配
@Resource(name = "orderRepository")
private OrderRepository orderRepository;
// 按类型装配(适用于单一实现)
@Resource(type = PaymentService.class)
private PaymentService paymentService;
// 默认装配(适用于名称匹配的场景)
@Resource
private InventoryService inventoryService;
public void processOrder(Order order) {
// 处理订单逻辑
orderRepository.save(order);
paymentService.processPayment(order);
inventoryService.updateInventory(order);
}
}
通过合理使用 @Resource 注解,可以在享受依赖注入便利的同时,保持代码的标准化和框架无关性。
13. @CrossOrigin
@CrossOrigin 是 Spring MVC 中用于处理跨域资源共享(CORS)的注解。它允许您在 Web 应用中轻松配置跨域请求策略,解决浏览器同源策略限制。
核心作用
- 跨域访问控制:允许指定域的请求访问当前服务的资源
- HTTP 方法控制:限制允许的 HTTP 请求方法
- 请求头管理:控制允许的请求头和暴露的响应头
- 预检请求缓存:通过 maxAge 属性优化预检请求性能
基本用法
类级别使用
@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "http://localhost:3000")
public class UserController {
@GetMapping
public List<User> getUsers() {
return userService.getAllUsers();
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
}
方法级别使用
@RestController
@RequestMapping("/api")
public class ApiController {
// 允许来自特定域的请求
@CrossOrigin(origins = "http://localhost:3000")
@GetMapping("/user")
public User getUser() {
return new User("Bob", 25);
}
// 允许多个域的请求
@CrossOrigin(origins = {"http://localhost:3000", "http://localhost:4000"})
@GetMapping("/admin")
public User getAdmin() {
return new User("Admin", 30);
}
}
主要属性
| 属性 | 类型 | 说明 |
|---|---|---|
| origins | String[] | 允许的源地址,支持通配符"*"表示允许所有域 |
| methods | RequestMethod[] | 允许的 HTTP 方法,默认允许所有标准方法 |
| allowedHeaders | String[] | 允许的请求头,"*"表示允许所有头 |
| exposedHeaders | String[] | 浏览器可以访问的响应头 |
| maxAge | long | 预检请求的缓存时间(秒),默认为 1800 秒 |
| allowCredentials | boolean | 是否允许携带凭证(如 Cookie),默认为 false |
高级用法示例
1. 全局 CORS 配置
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:3000", "http://localhost:4000")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.exposedHeaders("X-Custom-Header")
.allowCredentials(true)
.maxAge(3600);
}
}
2. 复杂的跨域配置
@RestController
@RequestMapping("/api")
public class ComplexController {
// 允许所有域,但限制方法和头
@CrossOrigin(
origins = "*",
methods = {RequestMethod.GET, RequestMethod.POST},
allowedHeaders = {"Content-Type", "Authorization"},
exposedHeaders = {"X-Total-Count"},
maxAge = 3600
)
@GetMapping("/data")
public List<Data> getData() {
return dataService.getAll();
}
// 需要携带凭证的跨域请求
@CrossOrigin(
origins = "http://trusted-domain.com",
allowCredentials = "true"
)
@PostMapping("/secure")
public ResponseEntity<String> secureOperation() {
return ResponseEntity.ok("Secure operation completed");
}
}
最佳实践
安全性考虑:
- 避免在生产环境中使用 origins = “*”,除非确实需要
- 对于需要携带凭证的请求,必须指定具体的源地址
- 限制允许的 HTTP 方法和请求头
性能优化:
- 合理设置 maxAge 值,减少预检请求次数
- 尽量在类级别而非方法级别配置 CORS
配置方式选择:
- 全局配置适用于统一的跨域策略
- 局部配置适用于特殊接口的跨域需求
// 推荐的生产环境 CORS 配置
@RestController
@RequestMapping("/api/users")
@CrossOrigin(
origins = {"https://myapp.example.com", "https://admin.example.com"},
methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE},
allowedHeaders = {"Content-Type", "Authorization", "X-Requested-With"},
exposedHeaders = {"X-Total-Count"},
maxAge = 3600
)
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public ResponseEntity<List<User>> getUsers() {
List<User> users = userService.findAll();
return ResponseEntity.ok(users);
}
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
User savedUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
}
通过合理使用 @CrossOrigin 注解,可以有效解决跨域问题,同时确保应用的安全性和性能。
14. @Configuration
@Configuration 是 Spring Framework 中用于定义配置类的核心注解。它标识一个类作为 Spring IoC 容器的配置源,通常与 [@Bean](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_14_annotation_third_bean_manager/src/main/java/com/itheima/config/JdbcConfig.java#L22-L22) 注解配合使用来定义和管理 Bean。
核心作用
- 配置类标识:标识一个类作为配置类,替代传统的 XML 配置文件
- Bean 定义:与 [@Bean](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_14_annotation_third_bean_manager/src/main/java/com/itheima/config/JdbcConfig.java#L22-L22) 注解配合,定义和配置 Spring Bean
- 组件扫描支持:作为 [@Component](file:///D:/workspace/spring_clouds/10-riskmgmt/perisk/src/main/java/com/citics/riskmgnt/perisk/common/ThreadPoolUtil.java#L23-L23) 的特化版本,可被组件扫描自动发现
- 条件化配置:可与 [@Profile](file:///D:/workspace/spring_clouds/10-riskmgmt/amxrisk/src/main/java/com/citics/riskmgnt/amxrisk/config/RestTemplateConfig.java#L23-L23)、[@Conditional](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_11_annotation_aop/src/main/java/com/itheima/config/SpringConfig.java#L9-L9) 等注解结合,实现条件化配置
基本用法示例
简单配置类
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserServiceImpl();
}
@Bean
public UserMapper userMapper() {
return new UserMapperImpl();
}
}
带属性注入的配置类
@Configuration
public class DatabaseConfig {
@Value("${database.url}")
private String databaseUrl;
@Value("${database.username}")
private String username;
@Value("${database.password}")
private String password;
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(databaseUrl);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
主要属性
@Configuration 注解本身没有属性,但通常与其他注解配合使用:
| 注解 | 作用 | 示例 |
|---|---|---|
| [@PropertySource](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_13_annotation_di/src/main/java/com/itheima/config/SpringConfig.java#L9-L9) | 加载属性文件 | @PropertySource(“classpath:jdbc.properties”) |
| [@ComponentScan](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_12_annotation_bean_manager/src/main/java/com/itheima/config/SpringConfig.java#L8-L8) | 指定组件扫描路径 | @ComponentScan(“com.example”) |
| [@Import](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_14_annotation_third_bean_manager/src/main/java/com/itheima/config/SpringConfig.java#L11-L11) | 导入其他配置类 | @Import({ServiceConfig.class, DaoConfig.class}) |
高级特性
条件化配置
@Configuration
@Profile("production")
public class ProductionDatabaseConfig {
@Bean
public DataSource dataSource() {
// 生产环境数据源配置
return new HikariDataSource();
}
}
@Configuration
@Profile("development")
public class DevelopmentDatabaseConfig {
@Bean
public DataSource dataSource() {
// 开发环境数据源配置
return new DriverManagerDataSource();
}
}
导入其他配置
@Configuration
@ComponentScan("com.example")
@Import({DatabaseConfig.class, SecurityConfig.class})
@PropertySource("classpath:application.properties")
public class MainConfig {
@Bean
public ApplicationService applicationService() {
return new ApplicationServiceImpl();
}
}
最佳实践
- 明确配置职责:每个配置类应该有明确的职责,如数据库配置、安全配置等
- 合理使用 [@Import](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_14_annotation_third_bean_manager/src/main/java/com/itheima/config/SpringConfig.java#L11-L11):通过 [@Import](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_14_annotation_third_bean_manager/src/main/java/com/itheima/config/SpringConfig.java#L11-L11) 注解组合多个配置类,提高配置的模块化
- 属性注入:使用 [@Value](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_16_spring_junit/src/main/java/com/itheima/config/JdbcConfig.java#L13-L13) 注解注入配置属性,实现配置与代码的分离
- 避免复杂逻辑:配置类中应避免复杂的业务逻辑,专注于 Bean 的配置
// 推荐的配置类设计
@Configuration
@PropertySource("classpath:app.properties")
@ComponentScan(basePackages = "com.example")
@Import({DatabaseConfig.class, SecurityConfig.class})
public class ApplicationConfig {
@Value("${app.name:MyApplication}")
private String applicationName;
@Bean
public ApplicationService applicationService(
UserService userService,
NotificationService notificationService) {
ApplicationServiceImpl service = new ApplicationServiceImpl();
service.setUserService(userService);
service.setNotificationService(notificationService);
service.setApplicationName(applicationName);
return service;
}
}
通过合理使用 @Configuration 注解,可以构建出结构清晰、模块化的配置体系,提高应用的可维护性和可测试性。
15. @Bean
@Bean 是 Spring Framework 中用于在配置类中定义 Bean 的核心注解。它告诉 Spring 容器,被注解的方法将返回一个对象,该对象应该被注册为 Spring 应用上下文中的 Bean。
核心作用
- Bean 定义:在配置类中定义和配置 Spring Bean
- 生命周期管理:通过 initMethod 和 destroyMethod 属性管理 Bean 的生命周期
- 依赖注入:方法参数会自动从容器中获取并注入
- Bean 名称定制:通过 name 属性自定义 Bean 的名称
基本用法
简单 Bean 定义
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserServiceImpl();
}
@Bean
public UserMapper userMapper() {
return new UserMapperImpl();
}
}
依赖其他 Bean
@Configuration
public class AppConfig {
@Bean
public UserMapper userMapper() {
return new UserMapperImpl();
}
// 方法参数会自动从容器中获取并注入
@Bean
public UserService userService(UserMapper userMapper) {
UserServiceImpl service = new UserServiceImpl();
service.setUserMapper(userMapper);
return service;
}
}
主要属性
| 属性 | 类型 | 说明 |
|---|---|---|
| name | String[] | Bean 的名称,默认为方法名 |
| initMethod | String | 初始化方法名,在 Bean 初始化时调用 |
| destroyMethod | String | 销毁方法名,在 Bean 销毁时调用 |
| autowireCandidate | boolean | 是否作为自动装配的候选者,默认为 true |
高级用法示例
自定义 Bean 名称和生命周期方法
@Configuration
public class AppConfig {
@Bean(name = "customUserService", initMethod = "initialize", destroyMethod = "cleanup")
public UserService userService() {
UserServiceImpl userService = new UserServiceImpl();
userService.setSomeProperty("value");
return userService;
}
@Bean("namedMapper")
public UserMapper userMapper() {
return new UserMapperImpl();
}
}
作用域配置
@Configuration
public class AppConfig {
@Bean
@Scope("singleton") // 默认作用域
public UserService singletonUserService() {
return new UserServiceImpl();
}
@Bean
@Scope("prototype")
public UserMapper prototypeUserMapper() {
return new UserMapperImpl();
}
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public ShoppingCart sessionCart() {
return new ShoppingCart();
}
}
最佳实践
- 方法参数注入:利用方法参数自动注入依赖,比手动从容器获取更简洁
- 合理命名:对于需要自定义名称的 Bean,使用 name 属性明确指定
- 生命周期管理:对于需要初始化或清理操作的 Bean,配置 initMethod 和 destroyMethod
- 作用域选择:根据 Bean 的使用场景选择合适的作用域
// 推荐的 @Bean 使用方式
@Configuration
public class DatabaseConfig {
@Value("${database.pool.size:10}")
private int poolSize;
@Bean(name = "primaryDataSource", initMethod = "init", destroyMethod = "close")
public DataSource primaryDataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setMaximumPoolSize(poolSize);
// 其他配置...
return dataSource;
}
@Bean
@Scope("prototype")
public JdbcTemplate jdbcTemplate(DataSource primaryDataSource) {
return new JdbcTemplate(primaryDataSource);
}
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager txManager) {
return new TransactionTemplate(txManager);
}
}
通过合理使用 @Bean 注解,可以灵活地定义和配置 Spring 容器中的各种 Bean,满足不同场景的需求。
16. @Component
@Component 是 Spring Framework 中最基本的组件注解,用于标记任何 Spring 管理的组件。它是其他特定组件注解(如 [@Controller](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_19_springmvc_demo/src/main/java/com/itheima/controller/UserController.java#L9-L9)、[@Service](file:///D:/workspace/spring_clouds/10-riskmgmt/spec/src/main/java/com/citics/riskmgnt/spec/userauth/service/impl/UserAuthServiceImpl.java#L17-L17)、[@Repository](file:///D:/workspace/spring_clouds/10-riskmgmt/spec/src/main/java/com/citics/riskmgnt/spec/citicRuleCheck/dao/CiticRuleCheckDao.java#L10-L10))的基础注解。
核心作用
- 通用组件标识:标记一个类作为 Spring 容器管理的组件
- 自动注册:被 [@ComponentScan](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_12_annotation_bean_manager/src/main/java/com/itheima/config/SpringConfig.java#L8-L8) 扫描并注册为 Bean
- 依赖注入支持:可被其他组件通过 [@Autowired](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_13_annotation_di/src/main/java/com/itheima/service/impl/UserServiceImpl.java#L12-L12)、[@Resource](file:///D:/workspace/spring_clouds/10-riskmgmt/auth/src/main/java/com/citics/auth/login/service/impl/LoginServiceImpl.java#L29-L29) 等注解注入使用
- 基础注解:是 [@Controller](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_19_springmvc_demo/src/main/java/com/itheima/controller/UserController.java#L9-L9)、[@Service](file:///D:/workspace/spring_clouds/10-riskmgmt/spec/src/main/java/com/citics/riskmgnt/spec/userauth/service/impl/UserAuthServiceImpl.java#L17-L17)、[@Repository](file:///D:/workspace/spring_clouds/10-riskmgmt/spec/src/main/java/com/citics/riskmgnt/spec/citicRuleCheck/dao/CiticRuleCheckDao.java#L10-L10) 等注解的基础
基本用法
简单组件
@Component
public class MyComponent {
public void doSomething() {
System.out.println("执行某些操作");
}
}
带名称的组件
@Component("myCustomComponent")
public class MyComponent {
public void performAction() {
System.out.println("执行操作");
}
}
特点
- 通用性:适用于任何 Spring 管理的组件
- 自动发现:配合 [@ComponentScan](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_12_annotation_bean_manager/src/main/java/com/itheima/config/SpringConfig.java#L8-L8) 可自动注册为 Bean
- 可注入性:可被其他组件注入使用
- 继承性:其他组件注解的基础注解
与其他注解的关系
| 注解 | 用途 | 说明 |
|---|---|---|
| [@Repository](file:///D:/workspace/spring_clouds/10-riskmgmt/spec/src/main/java/com/citics/riskmgnt/spec/citicRuleCheck/dao/CiticRuleCheckDao.java#L10-L10) | 持久层组件 | 专门用于数据访问层,提供持久层异常转换 |
| [@Service](file:///D:/workspace/spring_clouds/10-riskmgmt/spec/src/main/java/com/citics/riskmgnt/spec/userauth/service/impl/UserAuthServiceImpl.java#L17-L17) | 业务层组件 | 专门用于业务逻辑层 |
| [@Controller](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_19_springmvc_demo/src/main/java/com/itheima/controller/UserController.java#L9-L9) | 控制层组件 | 专门用于 Web 控制层 |
| [@Component](file:///D:/workspace/spring_clouds/10-riskmgmt/perisk/src/main/java/com/citics/riskmgnt/perisk/common/ThreadPoolUtil.java#L23-L23) | 通用组件 | 适用于任何组件,是上述注解的基础 |
这些注解都是 @Component 的特化版本,具有相同的功能但语义更明确。
高级用法示例
条件化组件
@Component
@Profile("development")
public class DevelopmentService {
public void performAction() {
System.out.println("开发环境下的操作");
}
}
@Component
@Profile("production")
public class ProductionService {
public void performAction() {
System.out.println("生产环境下的操作");
}
}
带作用域的组件
@Component
@Scope("prototype")
public class PrototypeComponent {
public void doSomething() {
System.out.println("原型组件操作");
}
}
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionScopedComponent {
public void doSessionWork() {
System.out.println("会话范围组件操作");
}
}
最佳实践
- 语义化选择:优先使用语义更明确的注解([@Repository](file:///D:/workspace/spring_clouds/10-riskmgmt/spec/src/main/java/com/citics/riskmgnt/spec/citicRuleCheck/dao/CiticRuleCheckDao.java#L10-L10)、[@Service](file:///D:/workspace/spring_clouds/10-riskmgmt/spec/src/main/java/com/citics/riskmgnt/spec/userauth/service/impl/UserAuthServiceImpl.java#L17-L17)、[@Controller](file:///D:/workspace/spring_clouds/09-spring/src/main/java/com/spring/spring_19_springmvc_demo/src/main/java/com/itheima/controller/UserController.java#L9-L9)),只在没有合适注解时使用 [@Component](file:///D:/workspace/spring_clouds/10-riskmgmt/perisk/src/main/java/com/citics/riskmgnt/perisk/common/ThreadPoolUtil.java#L23-L23)
- 命名规范:对于需要自定义名称的组件,明确指定名称
- 组件职责:每个组件应有明确的职责,遵循单一职责原则
// 推荐的组件设计
@Component
public class FileStorageService {
private final StorageProperties storageProperties;
// 构造函数注入(推荐)
public FileStorageService(StorageProperties storageProperties) {
this.storageProperties = storageProperties;
}
public void saveFile(MultipartFile file) {
// 文件保存逻辑
String location = storageProperties.getLocation();
// 实际保存操作
}
public byte[] loadFile(String filename) {
// 文件加载逻辑
return new byte[0];
}
}
通过合理使用 @Component 及其特化注解,可以构建出结构清晰、职责明确的 Spring 应用程序,提高代码的可维护性和可读性。
17. @Value
@Value 是 Spring Framework 中用于注入属性值的核心注解。它可以将配置文件中的属性值、系统属性、环境变量等注入到 Spring 管理的 Bean 属性中。
核心作用
- 属性注入:将外部配置属性注入到 Bean 的字段或方法参数中
- 表达式支持:支持 Spring Expression Language (SpEL) 表达式
- 默认值设置:可以为属性设置默认值,提高应用的健壮性
- 配置分离:实现配置与代码的分离,便于维护和部署
基本用法
注入简单属性值
@Component
public class DatabaseConfig {
@Value("${database.url}")
private String databaseUrl;
@Value("${database.username}")
private String username;
@Value("${database.password}")
private String password;
// 使用注入的属性
public DataSource createDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(databaseUrl);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
设置默认值
@Component
public class AppConfig {
// 如果配置文件中没有定义 server.port,则使用默认值 8080
@Value("${server.port:8080}")
private int serverPort;
// 字符串默认值
@Value("${app.name:MyApplication}")
private String appName;
// 数组默认值
@Value("${app.servers:server1,server2,server3}")
private String[] servers;
}
主要属性
@Value 注解只有一个 value 属性,用于指定要注入的值:
| 属性 | 类型 | 说明 |
|---|---|---|
| value | String | 指定要注入的属性值或表达式 |
高级用法示例
使用 SpEL 表达式
@Component
public class ExpressionConfig {
// 字面量表达式
@Value("#{10 * 20}")
private int calculationResult;
// 系统属性
@Value("#{systemProperties['java.home']}")
private String javaHome;
// 随机值
@Value("#{T(java.lang.Math).random() * 100.0}")
private double randomNumber;
// 调用其他 Bean 的方法
@Value("#{databaseConfig.databaseUrl}")
private String dbUrlFromBean;
// 三元操作符
@Value("#{systemProperties['app.dev'] == 'true' ? 'dev' : 'prod'}")
private String environment;
}
注入集合类型
@Component
public class CollectionConfig {
// 注入列表(逗号分隔)
@Value("${app.roles:admin,user,guest}")
private List<String> roles;
// 注入集合
@Value("${app.permissions:read,write,execute}")
private Set<String> permissions;
// 注入映射(需要特殊格式)
@Value("#{${app.settings}}")
private Map<String, String> settings;
}
条件化注入
@Component
public class ConditionalConfig {
// 根据系统属性决定是否启用某个功能
@Value("#{systemProperties['feature.enabled'] ?: false}")
private boolean featureEnabled;
// 根据配置文件决定超时时间
@Value("#{${app.timeout:30} * 1000}")
private long timeoutInMillis;
}
最佳实践
合理使用默认值:为配置属性提供合理的默认值,增强应用的健壮性,避免因缺少配置导致应用启动失败。
类型安全:确保配置值能够正确转换为目标类型,避免类型转换异常。
配置分组:对于相关的配置项,考虑使用配置类进行分组管理。
避免硬编码:不要在 @Value 注解中硬编码敏感信息,应该使用配置文件或环境变量。
// 推荐的配置管理方式
@Component
@PropertySource("classpath:app.properties")
public class ApplicationConfig {
@Value("${app.name:DefaultApp}")
private String appName;
@Value("${app.version:1.0.0}")
private String appVersion;
@Value("${app.debug:false}")
private boolean debugMode;
@Value("${app.max-connections:100}")
private int maxConnections;
// 对于复杂配置,建议使用 @ConfigurationProperties
@Value("${app.whitelist:127.0.0.1,localhost}")
private List<String> whitelist;
// 提供 getter 方法供其他组件使用
public String getAppName() {
return appName;
}
public String getAppVersion() {
return appVersion;
}
public boolean isDebugMode() {
return debugMode;
}
public int getMaxConnections() {
return maxConnections;
}
public List<String> getWhitelist() {
return whitelist;
}
}
与其他注解的配合使用
与 @PropertySource 配合
@Configuration
@PropertySource("classpath:database.properties")
public class DatabaseConfiguration {
@Value("${database.driver:com.mysql.cj.jdbc.Driver}")
private String driverClassName;
@Value("${database.url}")
private String url;
@Value("${database.username}")
private String username;
@Value("${database.password}")
private String password;
@Bean
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setJdbcUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
在构造函数中使用
@Component
public class EmailService {
private final String smtpHost;
private final int smtpPort;
private final boolean useSSL;
// 构造函数注入配置值
public EmailService(
@Value("${mail.smtp.host:localhost}") String smtpHost,
@Value("${mail.smtp.port:25}") int smtpPort,
@Value("${mail.smtp.ssl:false}") boolean useSSL) {
this.smtpHost = smtpHost;
this.smtpPort = smtpPort;
this.useSSL = useSSL;
}
// 邮件发送逻辑
public void sendEmail(String to, String subject, String content) {
// 实现邮件发送逻辑
}
}
通过合理使用 @Value 注解,可以轻松地将外部配置注入到 Spring 应用中,实现配置与代码的分离,提高应用的灵活性和可维护性。
总结
到此这篇关于springboot常见的一些相关注解总结的文章就介绍到这了,更多相关springboot相关注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
