Spring 注解 和 DI 相关的注解 @Autowired 可以在构造函数、Setter 方法或字段注入中使用 @Autowired 注解,Spring 会解析并注入依赖。 构造函数注入:
1 2 3 4 5 6 7 8 class Car { Engine engine; @Autowired Car(Engine engine) { this .engine = engine; } }
Setter 注入:
1 2 3 4 5 6 7 8 class Car { Engine engine; @Autowired void setEngine (Engine engine) { this .engine = engine; } }
字段注入:
1 2 3 4 class Car { @Autowired Engine engine; }
@Autowired 有一个名为 required 的 boolean 参数,默认值为 true。当 Spring 找不到合适的 Bean 进行注入时,它会控制 Spring 的行为。当值为 true 时,会抛出异常,反之则不会。 注意,如果使用构造函数注入,所有构造函数参数都是 必须的 。 从 Spring 4.3 开始,除非声明了至少两个构造函数,否则不需要用 @Autowired 明确注解构造函数。
@Bean @Bean 用于标记工厂方法,用于实例化 Spring Bean:
1 2 3 4 @Bean Engine engine () { return new Engine (); }
生成的 Bean 的名称与工厂方法的名称相同。如果想使用不同的名称,可以使用此注解的 name 或 value 参数(value 是 name 的别名):
1 2 3 4 @Bean("engine") Engine getEngine () { return new Engine (); }
注意,所有注解为 @Bean 的方法必须位于 @Configuration 类中。
@Qualifier 在模糊情况下,使用 @Qualifier 注解与 @Autowired 注解一起,提供想要使用的 Bean 的 ID 或名称。
以下两个 Bean 实现了相同的接口:
1 2 3 class Bike implements Vehicle {}class Car implements Vehicle {}
如果 Spring 需要注入一个 Vehicle Bean,最终会出现多个匹配的定义。在这种情况下,可以使用 @Qualifier 注解显式地提供 Bean 的名称。
构造函数注入:
1 2 3 4 @Autowired Biker(@Qualifier("bike") Vehicle vehicle) { this .vehicle = vehicle; }
Setter 注入:
1 2 3 4 @Autowired void setVehicle (@Qualifier("bike") Vehicle vehicle) { this .vehicle = vehicle; }
或者:
1 2 3 4 5 @Autowired @Qualifier("bike") void setVehicle (Vehicle vehicle) { this .vehicle = vehicle; }
字段注入:
1 2 3 @Autowired @Qualifier("bike") Vehicle vehicle;
@Required @Required 用于 Setter 方法,以标记我们希望通过 XML 填充的依赖:
1 2 3 4 5 6 7 @Required void setColor (String color) { this .color = color; } <bean class="com.baeldung.annotations.Bike" > <property name="color" value="green" /> </bean>
否则,将抛出 BeanInitializationException 异常。
@Value 可以使用 @Value 向 Bean 注入属性值。它与构造函数、Setter 和字段注入兼容。
构造函数:
1 2 3 Engine(@Value("8") int cylinderCount) { this .cylinderCount = cylinderCount; }
Setter 方法:
1 2 3 4 @Autowired void setCylinderCount (@Value("8") int cylinderCount) { this .cylinderCount = cylinderCount; }
或者:
1 2 3 4 @Value("8") void setCylinderCount (int cylinderCount) { this .cylinderCount = cylinderCount; }
字段:
1 2 @Value("8") int cylinderCount;
注入静态值并不实用。因此,可以在 @Value 中使用占位符字符串来注入外部资源中定义的值,例如 .properties 或 .yaml 文件中的值。
假设有以下 .properties 文件:
engine.fuelType=petrol 可以用下面的方法注入 engine.fuelType 的值:
1 2 @Value("${engine.fuelType}") String fuelType;
甚至可以在 SpEL 中使用 @Value。
@DependsOn 可以使用此注解让 Spring 在注解的 Bean 之前初始化其他 Bean。通常情况下,这种行为是自动进行的,基于 Bean 之间的显式依赖关系。
只有当依赖关系是隐式的,例如 JDBC 驱动加载或静态变量初始化时,才需要此注解。
可以在依赖类上使用 @DependsOn 来指定依赖 Bean 的名称。注解的 value 参数需要一个包含依赖 Bean 名称的数组:
1 2 @DependsOn("engine") class Car implements Vehicle {}
或者,如果我们使用 @Bean 注解定义 Bean,那么就应该在工厂方法上使用 @DependsOn 注解:
1 2 3 4 5 @Bean @DependsOn("fuel") Engine engine () { return new Engine (); }
@Lazy 当我们希望延迟初始化 Bean 时,可以使用 @Lazy 注解。默认情况下,Spring 在 Application Context 启动时会立即创建所有 Singleton(单例)Bean。
不过,在某些情况下,我们需要在使用时创建 Bean,而不是在应用启动时。
这个注解会根据具体标注位置而有不同的表现,可以用在如下位置:
@Bean 注解的 Bean 工厂方法,可以延迟方法调用(从而延迟 Bean 的创建)。 @Configuration 类,包含的 @Bean 方法都将受到影响 @Component 类,而该组件类不是 @Configuration 类,则该 Bean 将被延迟地初始化 @Autowired 构造函数、Setter 方法或字段,用于延迟地(通过代理)加载依赖本身 该注解有一个名为 value 的参数,默认值为 true。它可以覆盖默认行为。
当全局设置为懒加载(lazy)时,可以标记要立即加载的 Bean,或者在使用 @Lazy 标记的 @Configuration 类中,配置特定的 @Bean 方法以进行立即加载:
1 2 3 4 5 6 7 8 9 10 @Configuration @Lazy class VehicleFactoryConfig { @Bean @Lazy(false) Engine engine () { return new Engine (); } }
@Lookup 使用 @Lookup 注解的方法会告诉 Spring,在调用该方法时返回该方法返回类型的实例。
@Primary 有时,需要定义多个相同类型的 Bean。在这种情况下,注入将不会成功,因为 Spring 不知道需要注入哪个 Bean。
上文已经介绍了处理这种情况的方法:用 @Qualifier 标记所有注入点,并指定所需的 Bean 名称。
可以使用 @Primary 注解来简化这种情况:将最常用的 Bean 标记为 @Primary,它将在未标记 @Qualifier 的注入点上被选中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Component @Primary class Car implements Vehicle {}@Component class Bike implements Vehicle {}@Component class Driver { @Autowired Vehicle vehicle; } @Component class Biker { @Autowired @Qualifier("bike") Vehicle vehicle; }
在前面的示例中,Car 注解了 @Primary。因此,在 Driver 类中,Spring 注入了一个 Car Bean。当然,在 Biker Bean 中,vehicle 字段的值将是 Bike 对象,因为它注解了 @Qualifier 并且指定了 Bean 名称。
@Scope 使用 @Scope 来定义 @Component 类或 @Bean 的 Scope(作用域),它可以是 singleton、prototype、request、session、globalSession 或某些自定义作用域。
例如:
1 2 3 @Component @Scope("prototype") class Engine {}
Context 配置注解 @Profile 如果我们希望 Spring 仅在特定 Profile(配置文件)处于活动状态时才启用 @Component 类或 @Bean 方法,可以使用 @Profile 对其进行标记。 使用注解的 value 参数配置 Profile 的名称:
1 2 3 @Component @Profile("sportDay") class Bike implements Vehicle {}
@Import 可以使用该注解来使用特定的 @Configuration 类,而无需进行组件扫描。 通过 @Import 注解的 value 参数来提供这些类:
1 2 @Import(VehiclePartSupplier.class) class VehicleFactoryConfig {}
@ImportResource 可以使用该注解导入 XML 配置。用 locations 参数或其别名 value 参数指定 XML 文件的位置:
1 2 3 @Configuration @ImportResource("classpath:/annotations.xml") class VehicleFactoryConfig {}
@PropertySource 通过该注解,可以为应用设置定义属性文件:
1 2 3 4 5 6 7 8 9 @Configuration @PropertySource("classpath:/annotations.properties") class VehicleFactoryConfig {}@PropertySource 利用了 Java 8 的重复注解功能,这意味着可以用它多次标记一个类:@Configuration @PropertySource("classpath:/annotations.properties") @PropertySource("classpath:/vehicle-factory.properties") class VehicleFactoryConfig {}
@PropertySources 可以使用此注解指定多个 @PropertySource 配置:
1 2 3 4 5 6 @Configuration @PropertySources({ @PropertySource("classpath:/annotations.properties"), @PropertySource("classpath:/vehicle-factory.properties") }) class VehicleFactoryConfig {}
注意,自 Java 8 以来,可以通过上述重复注解的特性来实现同样的功能。
Spring MVC 注解 @Controller @Controller 注解用于标识一个类为Spring MVC控制器,负责处理HTTP请求并返回视图。
1 2 3 4 @Controller public class MyController { }
@RestController @RestController 注解是@Controller和@ResponseBody的组合,用于RESTful Web服务的控制器。
1 2 3 4 @RestController public class MyRestController { }
@RequestMapping @RequestMapping 注解用于将HTTP请求映射到控制器的处理方法上。 注解属性介绍:
value: 请求的URL路径。
method: 支持的HTTP方法。
params: 请求参数条件。
headers: 请求头条件。
当value设置为”/users/{id}”,method为RequestMethod.GET,params为”active=true”,headers为”Accept=application/json”时:
1 2 3 4 5 6 7 GET /users/123 ?active=true Accept: application/json @RequestMapping(value = "/users/{id}", method = RequestMethod.GET, params = "active=true", headers = "Accept=application/json") public ResponseEntity<List<User>> listActiveUsers (@PathVariable int id) {}
@GetMapping @GetMapping 注解用于映射GET请求到控制器的方法上。 注解属性介绍:
当value设置为”/users/{id}”时,请求/users/123将映射到方法:
1 2 3 4 5 6 GET /users/123 @GetMapping("/users/{id}") public User getUser (@PathVariable int id) {}
@PostMapping @PostMapping 注解用于映射POST请求到控制器的方法上。 注解属性介绍:
value: 请求的URL路径。 当value设置为”/users”时,带有JSON请求体的POST请求将映射到方法:
1 2 3 4 5 6 7 8 9 10 11 POST /users Content-Type: application/json { "name" : "John Doe" , "age" : 30 } @PostMapping("/users") public User createUser (@RequestBody User user) {}
@PutMapping @PutMapping 注解用于映射HTTP PUT请求到控制器的方法上,通常用于更新资源。
注解属性介绍
value: 请求的URL路径。 当value设置为”/users/{id}”时,请求将映射到更新用户的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 PUT /users/123 Content-Type: application/json { "name" : "Jane Doe" , "age" : 25 } @PutMapping("/users/{id}") public User updateUser (@PathVariable int id, @RequestBody User userDetails) {}
@DeleteMapping @DeleteMapping 注解用于映射HTTP DELETE请求到控制器的方法上,用于删除资源。 注解属性介绍
当value设置为”/users/{id}”时,请求将映射到删除用户的方法:
1 2 3 4 5 6 7 8 9 DELETE /users/123 @DeleteMapping("/users/{id}") public ResponseEntity<?> deleteUser(@PathVariable int id) {}
@PatchMapping @PatchMapping 注解用于映射HTTP PATCH请求到控制器的方法上,通常用于部分更新资源。
注解属性介绍
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 当value设置为"/users/{id}" 时,请求将映射到部分更新用户的方法: PATCH /users/123 Content-Type: application/json { "name" : "Jane Doe" } @PatchMapping("/users/{id}") public User patchUser (@PathVariable int id, @RequestBody Map<String, Object> updates) {}
@RequestParam @RequestParam 注解用于将请求参数绑定到控制器方法的参数上。 注解属性介绍
value: 请求参数的名称。
required: 指示参数是否必须。
defaultValue: 参数的默认值。
当请求包含查询参数”page”和”size”时:
1 2 3 4 5 6 7 8 9 10 GET /items?page=1 &size=10 @GetMapping("/items") public List<Item> listItems ( @RequestParam(value = "page", defaultValue = "1") int page,@RequestParam(value = "size", defaultValue = "10") int size) {}
@PathVariable @PathVariable 注解用于将URL中的模板变量绑定到控制器方法的参数上。
注解属性介绍
value: 模板变量的名称。
required: 指示变量是否必须。
当URL模板包含”{id}”时,请求/users/123将映射到方法:
1 2 3 4 5 6 GET /users/123 @GetMapping("/users/{id}") public User getUserById (@PathVariable int id) {}
@RequestBody @RequestBody 注解用于将请求体绑定到控制器方法的参数上。
1 2 3 4 5 6 7 8 9 10 11 12 POST /users Content-Type: application/json { "name" : "John Doe" , "age" : 30 } @PostMapping("/users") public User createUser (@RequestBody User user) {}
@RequestHeader 注解用于将请求头绑定到控制器方法的参数上。
注解属性介绍
value: 请求头的名称。
required: 指示请求头是否必须。
请求包含自定义请求头”X-Request-ID”:
1 2 3 4 5 6 7 8 9 GET /users X-Request-ID: 123456789 注解业务案例 @GetMapping("/users") public List<User> listUsers (@RequestHeader(value = "X-Request-ID", required = false) String requestId) {}
@CookieValue @CookieValue 注解用于将请求中Cookie的值绑定到控制器方法的参数上。
注解属性介绍
value: Cookie的名称。
required: 指示Cookie是否必须。
请求包含名为”sessionId”的Cookie:
1 2 3 4 5 6 7 8 9 GET /users Cookie: sessionId=abc123def456 注解业务案例 @GetMapping("/users") public List<User> listUsers (@CookieValue(value = "sessionId", required = false) String sessionId) {}
@ModelAttribute @ModelAttribute 注解用于将请求参数或表单数据绑定到模型属性上。 注解属性介绍
value: 模型属性的名称。
required: 指示模型属性是否必须。
一个包含用户信息的POST请求:
1 2 3 4 5 6 7 8 9 10 11 12 POST /users Content-Type: application/x-www-form-urlencoded name=John+Doe&age=30 注解业务案例 @PostMapping("/users") public String addUser (Model model, @ModelAttribute User user) {model.addAttribute("user" , user); }
@SessionAttribute @SessionAttribute 注解用于将模型属性存储到HTTP会话中。 注解属性介绍
name: 会话属性的名称。
value: 会话属性的值。
将用户信息存储在会话中,以便跨请求访问:
1 2 3 4 5 6 7 8 9 10 GET /user/profile Cookie: JSESSIONID=abc123; user=John Doe 注解业务案例 @SessionAttribute(name = "user") public String showProfile (Model model) {String user = (String) model.asMap().get("user" );}
@RequestAttribute @RequestAttribute 注解用于将请求属性绑定到控制器方法的参数上。 注解属性介绍
从请求转发中携带属性:
1 2 3 4 5 6 7 8 9 10 11 POST /login ... Redirect /user/profile?role=admin 注解业务案例 @GetMapping("/user/profile") public String showProfile (@RequestAttribute("role") String role) {}
@ResponseStatus @ResponseStatus 注解用于指定HTTP响应的status。 注解属性介绍
当资源未找到时返回404状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 GET /users/999 HTTP/1.1 404 Not Found 注解业务案例 @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public ResponseEntity<Object> handleResourceNotFound () { } }
@ExceptionHandler @ExceptionHandler 注解用于处理控制器中抛出的特定异常。 注解属性介绍
捕获并处理自定义的业务异常:
1 2 3 4 5 6 7 8 9 10 11 12 13 POST /users ... HTTP/1.1 400 Bad Request 注解业务案例 @ControllerAdvice public class GlobalExceptionHandler {@ExceptionHandler(BusinessException.class) public ResponseEntity<Object> handleBusinessException (BusinessException ex) { } }
@CrossOrigin @CrossOrigin 注解用于启用跨源请求。
注解属性介绍
origins: 允许的来源。
methods: 允许的HTTP方法。
allowedHeaders: 允许的请求头。
允许特定域名进行跨域GET请求:
1 2 3 4 5 6 7 8 9 10 11 OPTIONS /api/data Access-Control-Request-Method: GET Origin: <http: 注解业务案例 @CrossOrigin(origins = "<http://example.com>", methods = {RequestMethod.GET}) @GetMapping("/api/data") public List<Data> getAllData () {}
@MatrixVariable @MatrixVariable 注解用于从URL的矩阵变量中获取值。
注解属性介绍
pathVar: 指定矩阵变量所在的路径变量名称。
从URL中获取矩阵变量的值:
1 2 3 4 5 6 7 8 GET /api/users/123 ;role=admin 注解业务案例 @GetMapping("/api/users/{id}") public User getUser (@MatrixVariable(name = "role", pathVar = "id") String role) {}
@InitBinder @InitBinder 注解用于在控制器中初始化WebDataBinder,通常用于注册自定义属性编辑器。
1 2 3 4 5 6 7 8 @Controller public class MyController { @InitBinder public void initBinder (WebDataBinder binder) { } }
@ResponseStatus @ResponseStatus 注解用于设置响应的HTTP状态码。 注解属性介绍
当发生特定异常时,返回HTTP 503 Service Unavailable状态码。
1 2 3 4 5 @ResponseStatus(value = HttpStatus.SERVICE_UNAVAILABLE) public class ServiceUnavailableException extends RuntimeException { }
@Validated @Validated 注解用于在类或方法级别指定验证组,增强验证逻辑。 注解属性介绍
使用特定的验证组对用户注册信息进行验证。
1 2 3 4 5 @Validated(UserValidationGroup.class) public class UserRegistrationController { }
@Validated Annotation with Groups @Validated 注解与groups属性结合使用,允许在方法级别指定多个验证组。 注解属性介绍
对更新操作使用不同的验证组。
1 2 3 4 5 @Validated({UpdateGroup.class, AnotherUpdateGroup.class}) public void updateEntity (@Valid @NotNull MyEntity entity) { }
@RequestBodyAdvice @RequestBodyAdvice 注解用于在读取请求正文之前或之后对请求正文进行处理。 注解属性介绍
beforeBodyRead: 指定在读取请求正文之前的处理。
afterBodyRead: 指定在读取请求正文之后的处理。
对请求正文进行日志记录或修改。
1 2 3 4 5 6 7 8 @ControllerAdvice public class MyRequestBodyAdvice { @RequestBodyAdvice(beforeBodyRead = "logBeforeRead") public void logRequestBody () { } }
@ControllerAdvice @ControllerAdvice 注解用于定义一个类,该类可以包含多个@ExceptionHandler、@InitBinder和@ModelAttribute方法。 注解属性介绍
1 2 3 4 5 @ControllerAdvice public class MyGlobalControllerAdvice { }
@MatrixParam @MatrixParam 注解用于从URL的矩阵变量中获取值。 注解属性介绍
从URL中获取矩阵变量的值:
1 2 3 4 5 6 7 8 GET /users;role=admin/123 注解业务案例 @GetMapping("/users/{id}") public User getUser (@MatrixParam(name = "role") String role) {}
@SessionAttributes @SessionAttributes 注解用于将模型属性添加到HTTP会话中,以便在多个请求之间保持它们的值。
注解属性介绍
names: 要存储在会话中的属性名称数组。
types: 要存储在会话中的属性类型。
将用户信息存储在会话中,以便在用户会话期间保持状态:
1 2 3 4 5 6 7 8 9 10 GET /user/profile Cookie: JSESSIONID=abc123; user=John Doe 注解业务案例 @Controller @SessionAttributes("user") public class UserController {}
@RequestAttribute @RequestAttribute 注解用于将请求属性绑定到控制器方法的参数上。 注解属性介绍
从请求中获取属性”searchQuery”:
1 2 3 4 5 6 7 8 GET /search?searchQuery=spring 注解业务案例 @GetMapping("/search") public String search (@RequestAttribute("searchQuery") String query) {}
@ModelAttribute @ModelAttribute 注解用于将请求参数或会话属性绑定到模型对象上。 注解属性介绍
将表单提交的参数绑定到用户对象上:
1 2 3 4 5 6 7 8 9 10 11 12 POST /user/register Content-Type: application/x-www-form-urlencoded name=John+Doe&email=<john.doe@example .com> 注解业务案例 @PostMapping("/user/register") public String registerUser (@ModelAttribute("user") User user) {}
@CookieValue @CookieValue 注解用于将请求中的Cookie值绑定到控制器方法的参数上。 注解属性介绍
从请求中获取名为”sessionId”的Cookie值:
1 2 3 4 5 6 7 8 9 GET /user/profile Cookie: sessionId=abc123 注解业务案例 @GetMapping("/user/profile") public String showProfile (@CookieValue("sessionId") String sessionId) {}
@RequestBody @RequestBody 注解用于将请求正文绑定到控制器方法的参数上。
接收JSON格式的请求正文:
1 2 3 4 5 6 7 8 9 10 11 12 13 POST /api/data Content-Type: application/json { "key" : "value" } 注解业务案例 @PostMapping("/api/data") public DataItem createDataItem (@RequestBody DataItem data) {}
@ResponseBody @ResponseBody 注解用于指示方法的返回值直接作为HTTP响应正文返回。
返回JSON格式的响应正文:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 GET /api/data/1 Content-Type: application/json { "id" : 1 , "key" : "value" } 注解业务案例 @GetMapping("/api/data/{id}") @ResponseBody public DataItem getDataItem (@PathVariable int id) {}
@ResponseStatus @ResponseStatus 注解用于设置响应的HTTP状态码。 注解属性介绍
1 2 3 4 5 6 @ResponseStatus(HttpStatus.NOT_FOUND) public class ResourceNotFoundException extends RuntimeException { }
@ExceptionHandler @ExceptionHandler 注解用于处理控制器抛出的特定异常。 注解属性介绍
1 2 3 4 5 6 7 @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<String> handleResourceNotFound () { } }
@ControllerAdvice @ControllerAdvice 注解用于定义一个类,该类可以包含多个@ExceptionHandler、@InitBinder和@ModelAttribute方法,用于全局异常处理和数据绑定。 注解属性介绍
注解业务案例
1 2 3 4 5 @ControllerAdvice public class GlobalControllerAdvice { }
@PostMapping with consumes Attribute @PostMapping 注解与 consumes 属性结合使用,用于指定请求体的媒体类型。
注解属性介绍
consumes: 指定请求体的媒体类型,如 application/json。
发送POST请求创建新用户,请求体为JSON格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 POST /users Content-Type: application/json { "name" : "John Doe" , "email" : "<john.doe@example.com>" } @PostMapping(value = "/users", consumes = "application/json") public ResponseEntity<User> createUser (@RequestBody User user) {}
@GetMapping with produces Attribute @GetMapping 注解与 produces 属性结合使用,用于指定响应的媒体类型。 注解属性介绍
produces: 指定响应的媒体类型,如 application/json。
发送GET请求获取用户列表,期望响应为JSON格式:
1 2 3 4 5 6 7 8 GET /users Accept: application/json @GetMapping(value = "/users", produces = "application/json") public ResponseEntity<List<User>> getUsers () {}
@ExceptionHandler with responseBody Attribute @ExceptionHandler 注解与 responseBody 属性结合使用,用于返回异常信息。 注解属性介绍
responseBody: 指定异常处理方法的返回值是否作为响应正文。
处理资源未找到的异常,并返回JSON格式的错误信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 GET /users/999 HTTP/1.1 404 Not Found Content-Type: application/json {"timestamp" : "2023-10-10T12:00:00" , "status" : 404 , "error" : "Not Found" } 注解业务案例 @ControllerAdvice public class GlobalExceptionHandler {@ExceptionHandler(ResourceNotFoundException.class) @ResponseBody public ResponseEntity<Object> handleResourceNotFound () { } }
@ControllerAdvice with basePackages @ControllerAdvice 注解与 basePackages 属性结合使用,用于定义全局异常处理和数据绑定的类。 注解属性介绍
basePackages: 指定要扫描的包,这些包中的控制器将使用 @ControllerAdvice 类中定义的方法。
1 2 3 4 5 @ControllerAdvice(basePackages = "com.example.web") public class GlobalControllerAdvice { }
@SessionAttribute with name @SessionAttribute 注解与 name 属性结合使用,用于从HTTP会话中获取属性。 注解属性介绍
从会话中获取名为”user”的属性:
1 2 3 4 5 6 7 8 9 GET /user/profile Cookie: JSESSIONID=abc123; user=John Doe 注解业务案例 @GetMapping("/user/profile") public String showProfile (@SessionAttribute("user") String user) {}
@RequestHeader 注解用于将特定的HTTP请求头值绑定到控制器方法的参数上。 注解属性介绍
value: 请求头的名称。
defaultValue: 当请求头不存在时使用的默认值。
1 2 3 4 5 6 7 8 9 10 11 获取User-Agent请求头的值: GET /api/resource User-Agent: Mozilla/5.0 (Windows NT 10.0 ; Win64; x64) 注解业务案例 @GetMapping("/api/resource") public ResponseEntity<?> handleRequest(@RequestHeader("User-Agent") String userAgent) {}
@Component @Component 是Spring的通用注解,用于标识一个类为Spring组件,可以被自动扫描和注册为Spring应用上下文的Bean。 注解属性介绍
1 2 3 4 5 @Component("myComponent") public class MyComponent { }
@Service @Service 是Spring的注解,用于标识一个类为服务层组件,通常包含业务逻辑。 注解业务案例
1 2 3 4 5 @Service public class MyService { }
@Repository @Repository 是Spring Data的注解,用于标识一个类为数据访问对象,通常用于数据库访问。
注解业务案例
1 2 3 4 5 @Repository public interface MyRepository extends JpaRepository <User, Long> { }
@Profile @Profile 注解用于根据激活的配置文件激活或禁用Bean。 注解属性介绍
注解业务案例
1 2 3 4 5 6 @Component @Profile("dev") public class DevConfig { }
@RequestPart @RequestPart 注解用于处理multipart/form-data请求中的部分,如文件上传。 注解属性介绍
处理包含文件的multipart请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 POST /api/upload Content-Type: multipart/form-data; boundary=----WebKitFormBoundary ------WebKitFormBoundary Content-Disposition: form-data; name="file" ; filename="image.png" Content-Type: image/png [文件内容] ------WebKitFormBoundary-- 注解业务案例 @PostMapping("/api/upload") public ResponseEntity<String> handleFileUpload ( @RequestPart("file") MultipartFile file) {}
Spring Boot 注解 @ConfigurationProperties @ConfigurationProperties 是 Spring Boot 提供的一个注解,主要用于将配置文件(如 application.properties 或 application.yml)中的属性值绑定到 Java 类的字段上。通过该注解,可以将一组相关的配置属性封装到一个 Java 类中,方便管理和使用。
1 2 3 4 5 6 7 @Component @ConfigurationProperties(prefix = "myapp") public class MyAppProperties { private String name; private int port; }
1 2 myapp.name =My Application myapp.port =8080
@EnableConfigurationProperties @EnableConfigurationProperties 用于启用 @ConfigurationProperties 注解的类。当使用 @ConfigurationProperties 注解标记一个类后,需要使用 @EnableConfigurationProperties 注解来告知 Spring Boot 去扫描并绑定这些配置属性类。
1 2 3 4 5 @Configuration @EnableConfigurationProperties(MyAppProperties.class) public class AppConfig { }
@ConditionalOnProperty @ConditionalOnProperty 是一个条件注解,用于根据配置文件中的属性值来决定是否加载某个 Bean 或配置类。只有当配置文件中指定的属性满足特定条件时,被该注解标记的 Bean 或配置类才会被创建和加载。
1 2 3 4 5 6 7 8 9 10 11 12 13 @Configuration public class ConditionalConfig { @Bean @ConditionalOnProperty(name = "myapp.feature.enabled", havingValue = "true") public MyFeature myFeature () { return new MyFeature (); } } class MyFeature { }
Spring Cloud 注解 Jackson 序列化注解 @JsonAnyGetter 该注解用于把可变的Map类型属性当做标准属性。 下例中,ExtendableBean实体有一个name属性和一组kay/value格式的可扩展属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class ExtendableBean { public String name; public Map<String, String> properties; @JsonAnyGetter public Map<String, String> getProperties () { return properties; } public ExtendableBean (String name) { this .name = name; properties = new HashMap <>(); } public void add (String key, String value) { properties.put(key, value); } }
说明: name属性访问级别是public, 是为了省略get/set方法, 简化示例 下面是把ExtendableBean实体序列化的过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 private static void whenSerializingUsingJsonAnyGetter_thenCorrect () { ExtendableBean bean = new ExtendableBean ("My bean" ); bean.add("attr1" , "val1" ); bean.add("attr2" , "val2" ); String result = null ; try { result = new ObjectMapper ().writeValueAsString(bean); } catch (JsonProcessingException e) { e.printStackTrace(); } System.out.println(result); }
序列化后的结果: {“name”:”My bean”,”attr2”:”val2”,”attr1”:”val1”}
@JsonGetter 该注解是@JsonProperty的两个作用中的一个, 用来标记一个方法是getter方法 下例中, 指定方法getTheName()是属性name属性的getter方法
1 2 3 4 5 6 7 8 9 10 public class MyBean { public int id; private String name; @JsonGetter("name") public String getTheName () { return name; } }
下面是序列化过程:
1 2 3 4 5 6 public void whenSerializingUsingJsonGetter_thenCorrect () throws JsonProcessingException { MyBean bean = new MyBean (1 , "My bean" ); String result = new ObjectMapper ().writeValueAsString(bean); }
@JsonPropertyOrder 该注解可以指定实体属性序列化后的顺序
1 2 3 4 5 @JsonPropertyOrder({ "name", "id" }) public class MyBean { public int id; public String name; }
序列化后的结果:{ “name”:”My bean”, “id”:1} 该注解有一个参数alphabetic, 如果为true, 表示按字母顺序序列化,此时输出结果:{ “id”:1, “name”:”My bean”}
@JsonRawValue 该注解可以让Jackson在序列化时把属性的值原样输出 下面的例子中, 我们给实体属性attrs赋值一个json字符串
1 2 3 4 5 6 7 8 9 10 11 public class RawBean { public String name; @JsonRawValue public String attrs; } public void whenSerializingUsingJsonRawValue_thenCorrect () throws JsonProcessingException { RawBean bean = new RawBean ("My bean" , "{\"attr\":false}" ); String result = new ObjectMapper ().writeValueAsString(bean); }
输出结果是: {“name”:”Mybean”,”attrs”:{“attr”:false}}
@JsonValue 该注解作用于一个方法, 并且只用被注解的方法序列化整个实体对象 把1.1的实体例修改如下:
1 2 3 4 5 6 7 8 9 10 class ExtendableBean { ........... @JsonValue public Map<String, String> getProperties () { return properties; } .......... }
序列化过程不变, 则结果是: {“attr2”:”val2”,”attr1”:”val1”} 可见, 属性name没有被序列化
@JsonRootName 如果wrapping是使能(enabled), 那么该注解用来指定root wrapper的名称 wrapping(包装)的含义是如果序列化实体User的结果是
1 2 3 4 5 { "id" : 1 , "name" : "John" }
那么wrapping后的效果如下:
1 2 3 4 5 6 7 { "User" : { "id" : 1 , "name" : "John" } }
下面看一个例子, 我们用该注解指明包装实体(wrapper entity)的包装器名称:
1 2 3 4 5 6 @JsonRootName(value = "user") public class UserWithRoot { public int id; public String name; }
包装器默认名称是实体类名, 这里就是UserWithRoot, 但是注解的value属性把包装器名称改为了user 序列化过程(和前面不同, 需要使能包装器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 private static void whenSerializingUsingJsonRootName_thenCorrect () { UserWithRoot user = new UserWithRoot (); user.id = 1 ; user.name = "jackma" ; try { ObjectMapper objectMapper = new ObjectMapper (); objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE); String result = objectMapper.writeValueAsString(user); System.out.println(result); } catch (JsonProcessingException e) { e.printStackTrace(); } }
序列化的结果:{“user”:{“id”:1,”name”:”jackma”}} 从Jackson .2.4版本开始, 新增了一个可选参数namespace, 该属性对json没效果, 但是对xml起作用, 修改本例的实体例:
1 2 3 4 5 6 @JsonRootName(value = "user", namespace = "alibaba") class UserWithRoot { public int id; public String name; }
用XmlMapper序列化:
1 2 3 4 5 6 private static void whenSerializingUsingJsonRootName_thenCorrect () { .............. XmlMapper xmlMapper = new XmlMapper (); xmlMapper.enable(SerializationFeature.WRAP_ROOT_VALUE); ..............
序列化结果:
1 2 3 4 <user xmlns ="alibaba" > <id xmlns ="" > 1</id > <name xmlns ="" > jackma</name > </user >
@JsonSerialize 该注解用于指定一个自定义序列化器(custom serializer)来序列化实体例的某属性 下例中, 用@JsonSerialize的参数using指明实体类属性eventDate的序列化器是CustomDateSerializer类:
1 2 3 4 5 6 7 public class Event { public String name; @JsonSerialize(using = CustomDateSerializer.class) public Date eventDate; }
下面是类CustomDateSerializer的定义:
1 2 3 4 5 6 7 8 9 10 11 public class CustomDateSerializer extends StdSerializer <Date> { private static SimpleDateFormat formatter = new SimpleDateFormat ("dd-MM-yyyy hh:mm:ss" ); public CustomDateSerializer () { this (null ); } public CustomDateSerializer (Class<Date> t) { super (t); } @Override public void serialize (Date value, JsonGenerator gen, SerializerProvider arg2) throws IOException, JsonProcessingException { gen.writeString(formatter.format(value)); } }
序列化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public void whenSerializingUsingJsonSerialize_thenCorrect () { SimpleDateFormat df = new SimpleDateFormat ("yyyy/MM/DD hh:mm:ss" ); String toParse = "2019/08/19 16:28:00" ; Date date = null ; try { date = df.parse(toParse); } catch (ParseException e) { e.printStackTrace(); } Event event = new Event (); event.name = "party" ; event.eventDate = date; try { String result = new ObjectMapper ().writeValueAsString(event); System.out.println(result); } catch (JsonProcessingException e) { e.printStackTrace(); } }
序列化结果: {“name”:”party”,”eventDate”:”2019-08-19 04:28:00”} 而如果没有@JsonSerialize注解的序列化结果是: {“name”:”party”,”eventDate”:1566203280000}
反序列化注解 @JsonCreator 该注解可以调整反序列化时构造器/构造工厂的行为 当我们需要反序列化的Json字符串和目标实体类不完全匹配时, 这个注解非常有用 假设我们要反序列化下面的Json字符串:
1 2 3 4 5 { "id" :1 , "theName" :"My bean" }
但是, 我们的目标实体类并没有一个名为theName的属性. 现在, 我们不想改变实体类本身, 我们只需在数据导出时做一些控制, 方法就是在构造器中使用@JsonCreator和@JsonProperty注解:
1 2 3 4 5 6 7 8 9 10 11 12 13 public class BeanWithCreator { public int id; public String name; @JsonCreator public BeanWithCreator ( @JsonProperty("id") int id, @JsonProperty("theName") String name) { this .id = id; this .name = name; } }
反序列化过程:
1 2 3 4 5 6 public void whenDeserializingUsingJsonCreator_thenCorrect () throws IOException { String json = "{\"id\":1,\"theName\":\"My bean\"}" ; BeanWithCreator bean = new ObjectMapper ().readerFor(BeanWithCreator.class).readValue(json); assertEquals("My bean" , bean.name); }
@JacksonInject 该注解指明一个属性的值是通过注入得到而不是从Json字符串反序列得到 下例的实体例属性id的值用注解标明是注入值:
1 2 3 4 5 6 7 public class BeanWithInject { @JacksonInject public int id; public String name; }
反序列化过程:
1 2 3 4 5 6 7 8 public void whenDeserializingUsingJsonInject_thenCorrect () throws IOException { String json = "{\"name\":\"My bean\"}" ; InjectableValues inject = new InjectableValues .Std().addValue(int .class, 1 ); BeanWithInject bean = new ObjectMapper ().reader(inject).forType(BeanWithInject.class).readValue(json); assertEquals("My bean" , bean.name); assertEquals(1 , bean.id); }
@JsonAnySetter 该注解允许我们把一个可变的map属性作为标准属性, 在反序列过程中, 从Json字符串得到的属性值会加入到map属性中 实体例和注解:
1 2 3 4 5 6 7 8 9 10 public class ExtendableBean { public String name; private Map<String, String> properties; @JsonAnySetter public void add (String key, String value) { properties.put(key, value); } }
准备反序列化的Json字符串:
1 2 3 4 5 6 { "name" :"My bean" , "attr2" :"val2" , "attr1" :"val1" }
反序列化过程:
1 2 3 4 5 6 7 public void whenDeserializingUsingJsonAnySetter_thenCorrect () throws IOException { String json = "{\"name\":\"My bean\",\"attr2\":\"val2\",\"attr1\":\"val1\"}" ; ExtendableBean bean = new ObjectMapper ().readerFor(ExtendableBean.class).readValue(json); assertEquals("My bean" , bean.name); assertEquals("val2" , bean.getProperties().get("attr2" )); }
@JsonSetter 该注解是@JsonProperty的另一个作用, 和@JsonGetter相对, 标记一个方法是setter方法 如果目标实体类没有和Json字符串数据完全匹配的方法时, 我们可以通过这个注解做一些调整让他们匹配 下例中指定方法setTheName()作为name属性的setter方法
1 2 3 4 5 6 7 8 9 10 public class MyBean { public int id; private String name; @JsonSetter("name") public void setTheName (String name) { this .name = name; } }
反序列化过程:
1 2 3 4 5 6 public void whenDeserializingUsingJsonSetter_thenCorrect () throws IOException { String json = "{\"id\":1,\"name\":\"My bean\"}" ; MyBean bean = new ObjectMapper ().readerFor(MyBean.class).readValue(json); assertEquals("My bean" , bean.getTheName()); }
@JsonDeserialize 该注解标明使用自定义反序列化器(custom deserializer) 实体类:
1 2 3 4 5 6 7 public class Event { public String name; @JsonDeserialize(using = CustomDateDeserializer.class) public Date eventDate; }
自定义反序列化器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class CustomDateDeserializer extends StdDeserializer <Date> { private static SimpleDateFormat formatter = new SimpleDateFormat ("dd-MM-yyyy hh:mm:ss" ); public CustomDateDeserializer () { this (null ); } public CustomDateDeserializer (Class<?> vc) { super (vc); } @Override public Date deserialize (JsonParser jsonparser, DeserializationContext context) throws IOException { String date = jsonparser.getText(); try { return formatter.parse(date); } catch (ParseException e) { throw new RuntimeException (e); } } }
反序列过程:
1 2 3 4 5 6 7 public void whenDeserializingUsingJsonDeserialize_thenCorrect () throws IOException { String json = "{" name":" party"," eventDate":" 20 -12 -2014 02 :30 :00 "}" ; SimpleDateFormat df = new SimpleDateFormat ("dd-MM-yyyy hh:mm:ss" ); Event event = new ObjectMapper ().readerFor(Event.class).readValue(json); assertEquals("20-12-2014 02:30:00" , df.format(event.eventDate)); }
@JsonAlias 该注解在反序列化过程中为属性定义一个或多个别名 实体类:
1 2 3 4 5 6 public class AliasBean { @JsonAlias({ "fName", "f_name" }) private String firstName; private String lastName; }
Json字符串中fName, f_name或firstName的值都可以被反序列到属性firstName
1 2 3 4 5 6 public void whenDeserializingUsingJsonAlias_thenCorrect () throws IOException { String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}" ; AliasBean aliasBean = new ObjectMapper ().readerFor(AliasBean.class).readValue(json); assertEquals("John" , aliasBean.getFirstName()); }
属性包含注解 @JsonIgnoreProperties 该注解是一个类级别的注解, 标记一个或多个属性被Jackson忽略 实体类:
1 2 3 4 5 6 @JsonIgnoreProperties({ "id" }) public class BeanWithIgnore { public int id; public String name; }
序列化过程:
1 2 3 4 5 6 7 public void whenSerializingUsingJsonIgnoreProperties_thenCorrect () throws JsonProcessingException { BeanWithIgnore bean = new BeanWithIgnore (1 , "My bean" ); String result = new ObjectMapper ().writeValueAsString(bean); assertThat(result, containsString("My bean" )); assertThat(result, not(containsString("id" ))); }
参数ignoreUnknown为true时, Json字符串如果有未知的属性名, 则不会抛出异常
@JsonIgnore 该注解用于属性级别, 用于标明一个属性可以被Jackson忽略 实体类:
1 2 3 4 5 6 7 public class BeanWithIgnore { @JsonIgnore public int id; public String name; }
序列化过程:
1 2 3 4 5 6 7 8 9 10 11 12 public void whenSerializingUsingJsonIgnore_thenCorrect () throws JsonProcessingException { BeanWithIgnore bean = new BeanWithIgnore (1 , "My bean" ); String result = new ObjectMapper () .writeValueAsString(bean); assertThat(result, containsString("My bean" )); assertThat(result, not(containsString("id" ))); }
@JsonIgnoreType 该注解标记类型是注解作用的类型的属性都会被忽略 必须作用于类, 标明以该类为类型的属性都会被Jackson忽略 实体类:
1 2 3 4 5 6 7 8 9 10 11 public class User { public int id; public Name name; @JsonIgnoreType public static class Name { public String firstName; public String lastName; } }
序列化过程:
1 2 3 4 5 6 7 8 9 public void whenSerializingUsingJsonIgnoreType_thenCorrect () throws JsonProcessingException, ParseException { User.Name name = new User .Name("John" , "Doe" ); User user = new User (1 , name); String result = new ObjectMapper ().writeValueAsString(user); assertThat(result, containsString("1" )); assertThat(result, not(containsString("name" ))); assertThat(result, not(containsString("John" ))); }
@JsonInclude 该注解在序列化时会排除属性值是空值(empty或null)、没有默认值的属性。 可作用在类和属性上 实体类:
1 2 3 4 5 6 @JsonInclude(Include.NON_NULL) public class MyBean { public int id; public String name; }
序列化过程:
1 2 3 4 5 6 7 public void whenSerializingUsingJsonInclude_thenCorrect () throws JsonProcessingException { MyBean bean = new MyBean (1 , null ); String result = new ObjectMapper ().writeValueAsString(bean); assertThat(result, containsString("1" )); assertThat(result, not(containsString("name" ))); }
@JsonAutoDetect 该注解可以覆盖属性是否可见的默认语义, 比如对于不可见的private序列化时变成可见的 实体类:
1 2 3 4 5 6 @JsonAutoDetect(fieldVisibility = Visibility.ANY) public class PrivateBean { private int id; private String name; }
序列化过程:
1 2 3 4 5 6 7 public void whenSerializingUsingJsonAutoDetect_thenCorrect () throws JsonProcessingException { PrivateBean bean = new PrivateBean (1 , "My bean" ); String result = new ObjectMapper ().writeValueAsString(bean); assertThat(result, containsString("1" )); assertThat(result, containsString("My bean" )); }
常用注解 @JsonProperty 该注解可以指定属性在Json字符串中的名字 下例中在非标准的setter和getter方法上使用该注解, 可以成功序列化和反序列化 实体类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class MyBean { public int id; private String name; @JsonProperty("name") public void setTheName (String name) { this .name = name; } @JsonProperty("name") public String getTheName () { return name; } }
序列化和反序列化过程:
1 2 3 4 5 6 7 8 9 10 public void whenUsingJsonProperty_thenCorrect () throws IOException { MyBean bean = new MyBean (1 , "My bean" ); String result = new ObjectMapper ().writeValueAsString(bean); assertThat(result, containsString("My bean" )); assertThat(result, containsString("1" )); MyBean resultBean = new ObjectMapper ().readerFor(MyBean.class).readValue(result); assertEquals("My bean" , resultBean.getTheName()); }
该注解指定序列化日期和时间时的格式 修改前面1.7的实体类:
1 2 3 4 5 6 7 public class Event { public String name; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss") public Date eventDate; }
序列化过程:
1 2 3 4 5 6 7 8 9 10 11 public void whenSerializingUsingJsonFormat_thenCorrect () throws JsonProcessingException, ParseException { SimpleDateFormat df = new SimpleDateFormat ("dd-MM-yyyy hh:mm:ss" ); df.setTimeZone(TimeZone.getTimeZone("UTC" )); String toParse = "20-12-2014 02:30:00" ; Date date = df.parse(toParse); Event event = new Event ("party" , date); String result = new ObjectMapper ().writeValueAsString(event); assertThat(result, containsString(toParse)); }
@JsonUnwrapped 该注解指定值在序列化和反序列化时, 去除对应属性的外包装(根节点) 实体类:
1 2 3 4 5 6 7 8 9 10 11 12 public class UnwrappedUser { public int id; @JsonUnwrapped public Name name; public static class Name { public String firstName; public String lastName; } }
序列化过程:
1 2 3 4 5 6 7 8 public void whenSerializingUsingJsonUnwrapped_thenCorrect () throws JsonProcessingException, ParseException { UnwrappedUser.Name name = new UnwrappedUser .Name("John" , "Doe" ); UnwrappedUser user = new UnwrappedUser (1 , name); String result = new ObjectMapper ().writeValueAsString(user); assertThat(result, containsString("John" )); assertThat(result, not(containsString("name" ))); }
序列化结果:
1 2 3 4 5 6 { "id" :1 , "firstName" :"John" , "lastName" :"Doe" }
@JsonView 该注解指明属性序列化和反序列时的视图级别(View) 视图类: 主要用于表明哪一级的实体类的属性会被序列化或反序列化
1 2 3 4 5 public class Views { public static class Public {} public static class Internal extends Public {} }
实体类:
1 2 3 4 5 6 7 8 9 class UserWithRoot { @JsonView(Views.Public.class) public int id; @JsonView(Views.Public.class) public String name; @JsonView(Views.Internal.class) public String school; }
实例化过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 public void whenSerializingUsingJsonView_thenCorrect () throws JsonProcessingException { UserWithRoot user = new UserWithRoot (); user.id = 1 ; user.name = "bl" ; user.school = "suide" ; try { System.out.println(new ObjectMapper ().writerWithView(Views.Internal.class).writeValueAsString(user)); } catch (JsonProcessingException e) { e.printStackTrace(); } }
本例中, school的视图级别是View.Internal类, 而序列化的映射器设定的视图显示级别是Views.Public类, 比school的类型高了一级, 所以序列化结果中没有school, {“id”:1,”name”:”bl”} 而如果修改映射器的视图级别是Views.Internal类, 则序列化结果中包含school {“id”:1,”name”:”bl”,”school”:”suide”}
@JsonManagedReference, @JsonBackReference 这两个注解配合使用, 可以解决两个不同类的属性的父子关系(parent/child relationships)和循环引用(work around loops) 使用@JsonBackReference可以在序列化时阻断循环引用, 原理是忽略被注解的属性, 否则会导致异常 本例中, 我们用这组注解来序列化ItemWithRef实体类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class ItemWithRef { public int id; public String itemName; @JsonManagedReference public UserWithRef owner; } public class UserWithRef { public int id; public String name; @JsonBackReference public List<ItemWithRef> userItems; }
序列化过程:
1 2 3 4 5 6 7 public void whenSerializingUsingJacksonReferenceAnnotation_thenCorrect () throws JsonProcessingException { UserWithRef user = new UserWithRef (1 , "John" ); ItemWithRef item = new ItemWithRef (2 , "book" , user); user.addItem(item); String result = new ObjectMapper ().writeValueAsString(item); }
序列化结果: {“id”:2,”itemName”:”book”,”owner”:{“id”:1,”name”:”John”}} 如果把注解对调并序列化user结果是: {“id”:1,”name”:”John”,”userItems”:[{“id”:2,”itemName”:”book”}]}
@JsonIdentityInfo 该注解标明在序列化和反序列化一个值时, 该属性是否作为对象的唯一标识 该特性可以有效的解除循环引用, 和@JsonBackReference的区别是循环引用的对象的一个属性, 可以作为该对象的唯一标识被序列化, 而@JsonBackReference的循环引用对象不会二次序列化 两个实体类:
1 2 3 4 5 6 7 8 9 10 11 12 13 @JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") public class ItemWithIdentity { public int id; public String itemName; public UserWithIdentity owner; } public class UserWithIdentity { public int id; public String name; public List<ItemWithIdentity> userItems; }
实例化过程:
1 2 3 4 5 6 7 public void whenSerializingUsingJsonIdentityInfo_thenCorrect () throws JsonProcessingException { UserWithIdentity user = new UserWithIdentity (1 , "John" ); ItemWithIdentity item = new ItemWithIdentity (2 , "book" , user); user.addItem(item); String result = new ObjectMapper ().writeValueAsString(item); }
序列化结果:{“id”:2,”itemName”:”book”,”owner”:{“id”:1,”name”:”John”,”userItems”:[2]}} 这里循环引用对象是ItemWithIdentity, 当它作为UserWithIdentity的属性时, 指定它的id属性为其唯一标识序列化到UserWithIdentity当中
@JsonFilter 该注解可以在序列化时指定一个过滤器 下面为一个实体类指定一个过滤器:
1 2 3 4 5 6 @JsonFilter("myFilter") public class BeanWithFilter { public int id; public String name; }
定义过滤器并进行序列化
1 2 3 4 5 6 7 public void whenSerializingUsingJsonFilter_thenCorrect () throws JsonProcessingException { BeanWithFilter bean = new BeanWithFilter (1 , "My bean" ); FilterProvider filters = new SimpleFilterProvider ().addFilter("myFilter" , SimpleBeanPropertyFilter.filterOutAllExcept("name" )); String result = new ObjectMapper ().writer(filters).writeValueAsString(bean); }
序列化结果:{“name”:”My bean”} 这里添加了一个SimpleBeanPropertyFilter.filterOutAllExcept过滤器, 该过滤器的含义是除name属性外, 其他属性都被过滤掉(不序列化)
其他注解 @JsonAppend 该注解用来给一个被序列化的对象添加一个虚拟属性. 这个功能非常有用, 尤其是当我们想直接在Json字符串中添加额外的信息时, 不再需要修改类的定义. 举例来说, 它可以很方便的在Json文档中插入bean的版本信息, 而不需要bean提供对应的属性. 使用@JsonAppend注解的实体类:
1 2 3 4 5 6 7 @JsonAppend(attrs = {@JsonAppend.Attr(value = "version")}) public class BeanWithAppend { private int id; private String name; }
序列化过程:
1 2 3 4 BeanWithAppend bean = new BeanWithAppend (2 , "Bean With Append Annotation" );ObjectWriter writer = mapper.writerFor(BeanWithAppend.class).withAttribute("version" , "1.0" );String jsonString = writer.writeValueAsString(bean);
序列化结果: { “id”: 2, “name”: “Bean With Append Annotation”, “version”: “1.0” }
@JsonNaming 该注解用来在序列化时选择一个属性命名习惯来代替默认属性名. 注解参数value用来指定已有命名习惯, 或用户定义的命名习惯 除默认值(value=LOWER_CAMEL_CASE, 即驼峰命名法)外, Jackson库同时提供了4种内置的属性命名习惯:
1 2 3 4 KEBAB_CASE: 属性名单词用短线分隔连接, 比如hello-world LOWER_CASE: 属性名用小写字母而且没有分隔符, 比如helloworld SNAKE_CASE: 属性名用小写字母而且用下划线做分隔符, 比如hello_world UPPER_CAMEL_CASE: 属性名所有单词用大写开头而且没有分隔符, 比如HelloWorld
下例中用SNAKE_CASE命名法, 将属性beanName名序列化为bean_name
1 2 3 4 5 6 7 @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) public class NamingBean { private int id; private String beanName; }
序列化过程:
1 2 3 NamingBean bean = new NamingBean (3 , "Naming Bean" );String jsonString = mapper.writeValueAsString(bean);
序列化结果: { “id”: 3, “bean_name”: “Naming Bean” }
@JsonPropertyDescription Jackson的独立模块JSON Schema提供了创建Json信息表(Json schemas)来描述Java的类型信息. 信息表可用于输出我们期望的序列化Java对象, 或者在反序列化前验证Json文档(document) 注解@JsonPropertyDescription允许把人类可读的描述信息, 附加在要创建的Json信息表的description属性 实体类:
1 2 3 4 5 6 7 public class PropertyDescriptionBean { private int id; @JsonPropertyDescription("This is a description of the name property") private String name; }
序列化过程: 这里生成Json信息表的同时为它附加了description属性
1 2 3 4 5 SchemaFactoryWrapper wrapper = new SchemaFactoryWrapper ();mapper.acceptJsonFormatVisitor(PropertyDescriptionBean.class, wrapper); JsonSchema jsonSchema = wrapper.finalSchema();String jsonString = mapper.writeValueAsString(jsonSchema);
序列化结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 { "type" : "object" , "id" : "urn:jsonschema:com:baeldung:jackson:annotation:extra:PropertyDescriptionBean" , "properties" : { "name" : { "type" : "string" , "description" : "This is a description of the name property" }, "id" : { "type" : "integer" } } }
@JsonPOJOBuilder 该注解用来配置一个builder类用于定制反序列化过程, 尤其是当Json文档中属性命名习惯和POJO类对象的属性不同 准备反序列化的Json字符串: { “id”: 5, “name”: “POJO Builder Bean”} 反序列化的目标类:
1 2 3 4 5 6 7 @JsonDeserialize(builder = BeanBuilder.class) public class POJOBuilderBean { private int identity; private String beanName; }
注意:BeanBuilder是自定义bulider类, 参见下文. 可以看到, bean属性的名称和Json字符串中对应属性的名称不同. 这就是@JsonPOJOBuilder发挥作用的地方. @JsonPOJOBuilder有两个参数:
buildMethodName: 一个无参方法, 用来在绑定Json属性和bean属性后, 创建bean的实例 withPrefix: 方法名前缀, 有该前缀的方法是用来匹配Json属性和bean的属性. 默认前缀是with 下面是BeanBuilder类定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @JsonPOJOBuilder(buildMethodName = "createBean", withPrefix = "construct") public class BeanBuilder { private int idValue; private String nameValue; public BeanBuilder constructId (int id) { idValue = id; return this ; } public BeanBuilder constructName (String name) { nameValue = name; return this ; } public POJOBuilderBean createBean () { return new POJOBuilderBean (idValue, nameValue); } }
上面的代码中, 我们配置了注解@JsonPOJOBuilder的参数, 用createBean方法作为build方法, 用construct前缀来匹配属性名 反序列化过程:
1 2 3 String jsonString = "{\"id\":5,\"name\":\"POJO Builder Bean\"}" ;POJOBuilderBean bean = mapper.readValue(jsonString, POJOBuilderBean.class);
@JsonTypeId 该注解作用于属性, 使得该属性不再是普通属性, 其值代表bean类的类型ID(`TypeId), 可以用它来描述多态时实体类对象的实际类型 实体类:
1 2 3 4 5 6 7 8 public class TypeIdBean { private int id; @JsonTypeId private String name; }
序列化过程:
1 2 3 4 mapper.enableDefaultTyping(DefaultTyping.NON_FINAL); TypeIdBean bean = new TypeIdBean (6 , "Type Id Bean" );String jsonString = mapper.writeValueAsString(bean);
序列化结果:[“Type Id Bean”,{“id”:6}]
mapper.enableDefaultTyping(DefaultTyping.NON_FINAL)的作用是在序列化结果中显示实体类类型属性 结果是一个Json对象, 其中”Type Id Bean”是实体类ID的描述, {“id”:6}是类的属性值
禁用Jackson注解 通过设置MapperFeature.USE_ANNOTATIONS可以禁用实体类上的Jackson注解 实体类:
1 2 3 4 5 6 7 @JsonInclude(Include.NON_NULL) @JsonPropertyOrder({ "name", "id" }) public class MyBean { public int id; public String name; }
序列化过程:
1 2 3 4 5 6 7 public void whenDisablingAllAnnotations_thenAllDisabled () throws IOException { MyBean bean = new MyBean (1 , null ); ObjectMapper mapper = new ObjectMapper (); mapper.disable(MapperFeature.USE_ANNOTATIONS); String result = mapper.writeValueAsString(bean); }
序列化结果:{ “id”:1, “name”:null} 如果注释掉mapper.disable(MapperFeature.USE_ANNOTATIONS);, 则序列化结果是: {“id”:1}
注解混合 多个实体类的注解可以混合在一起使用 下例中把类MyMixInForIgnoreType的注解@@JsonIgnoreType作用到了类Item的属性User:
1 2 3 4 5 6 7 8 9 public class Item { public int id; public String itemName; public User owner; } @JsonIgnoreType public class MyMixInForIgnoreType {}
序列化过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 public void whenSerializingUsingMixInAnnotation_thenCorrect () throws JsonProcessingException { Item item = new Item (1 , "book" , null ); String result = new ObjectMapper ().writeValueAsString(item); ObjectMapper mapper = new ObjectMapper (); mapper.addMixIn(User.class, MyMixInForIgnoreType.class); result = mapper.writeValueAsString(item); }