Files
blog-press/docs/Web-Backend/SpringBoot/SpringBoot-Skills.md

359 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: SpingBoot技巧
date: 2025-12-12
---
# 一、JsonView
  JsonView 是 Jackson 提供的注解,用于控制对象序列化/反序列化时包含哪些字段。可以实现:
- 不同接口返回不同字段
- 敏感字段过滤
- 前后端数据分离
## 1.1 添加依赖
```xml
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
```
## 1.2 使用
1. 定义视图接口
```java
// JsonView 视图定义
public class Views {
// 基础视图 - 所有接口都包含的字段
public interface Basic {}
// 返回给前端时使用
public interface Response extends Basic {}
// 接收前端数据时使用
public interface Request extends Basic {}
// 管理视图 - 包含所有字段
public interface AdminView extends ReadView {}
}
```
2. Dto对象使用JsonView
```java
@Data
public class UserDTO {
@JsonView(Views.Response.class)
private Long id;
@JsonView(Views.Request.class)
@NotBlank(message = "密码不能为空")
@Size(min = 6, message = "密码至少6位")
private String password;
@JsonView(Views.Basic.class)
@NotBlank(message = "用户名不能为空")
private String username;
@JsonView(Views.Basic.class)
@Email(message = "邮箱格式不正确")
private String email;
@JsonView(Views.Basic.class)
private String nickname;
@JsonView(AdminView.class)
private Boolean isActive;
}
```
3. Controller中使用
```java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
@JsonView(UserDTO.Response.class)
public UserDTO createUser(@RequestBody @JsonView(UserDTO.Request.class) UserDTO userDTO) {
return userService.createUser(userDTO);
}
@PutMapping("/{id}")
@JsonView(UserDTO.Response.class)
public UserDTO updateUser(@PathVariable Long id,
@RequestBody @JsonView(UserDTO.Request.class) UserDTO userDTO) {
return userService.updateUser(id, userDTO);
}
@GetMapping("/{id}")
@JsonView(UserDTO.Response.class)
public UserDTO getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
@GetMapping("/{id}/admin")
@JsonView(UserDTO.AdminView.class)
public UserDTO getAdminUser(@PathVariable Long id) {
return userService.getAdminUserById(id);
}
}
```
# 二、MapStruct
&emsp;&emsp;MapStruct 是一个 Java 注解处理器,用于生成类型安全的 Bean 映射代码:
- 编译时生成映射代码,无运行时性能损失
- 类型安全
- 支持复杂映射
## 2.1 添加依赖
```xml
<properties>
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
```
## 2.2 使用
```java
import org.mapstruct.*;
import java.util.List;
import java.time.format.DateTimeFormatter;
@Mapper
public interface UserMapper {
@Mapping(target = "name", source = "userName") // 字段名不同
@Mapping(target = "phoneNumber", source = "phone") // 字段名不同
@Mapping(target = "description", source = "remark") // 字段名不同
@Mapping(target = "statusDesc", ignore = true) // 需要特殊处理
@Mapping(target = "createTime", ignore = true) // 需要格式化
UserDTO toDTO(User user);
@Mapping(target = "userName", source = "name")
@Mapping(target = "phone", source = "phoneNumber")
@Mapping(target = "remark", source = "description")
@Mapping(target = "password", ignore = true) // 密码不映射
User toEntity(UserDTO dto);
// 列表映射
List<UserDTO> toDTOList(List<User> users);
// 带默认值的映射
@Mapping(target = "name", source = "userName")
@Mapping(target = "phoneNumber", source = "phone")
@Mapping(target = "description", source = "remark", defaultValue = "暂无描述")
@Mapping(target = "statusDesc", expression = "java(convertStatus(user.getStatus()))")
@Mapping(target = "createTime", expression = "java(formatTime(user.getCreateTime()))")
UserDTO toDTOWithDefault(User user);
// 自定义转换方法
default String convertStatus(Integer status) {
if (status == null) return "未知";
switch (status) {
case 0: return "禁用";
case 1: return "正常";
case 2: return "锁定";
default: return "未知";
}
}
// 时间格式化方法
default String formatTime(LocalDateTime time) {
if (time == null) return "";
return time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
}
```
&emsp;&emsp;需要执行`mvn compile`后检查`target/generated-sources`文件夹下是否存在生成的转换代码。
# 三、Bean Validation
&emsp;&emsp;Spring Boot的数据校验基于JSR-303/JSR-380规范Bean Validation通常使用Hibernate Validator作为实现。
## 3.1 添加依赖
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
```
## 3.2 常用检验注解
&emsp;&emsp;Java Bean Validation 常用注解
| 注解 | 适用类型 | 说明 |
|------|----------|------|
| `@NotNull` | 任意类型 | 值不能为 null |
| `@NotBlank` | CharSequence | 字符串不能为 null且必须包含至少一个非空白字符 |
| `@NotEmpty` | CharSequence, Collection, Map, Array | 字符串/集合/数组不能为 null 且不能为空(长度/大小大于 0 |
| `@Size(min=, max=)` | 字符串、集合、数组 | 限制长度或大小在 min 和 max 之间 |
| `@Min(value)` | 数值类型 | 数值必须大于或等于指定值 |
| `@Max(value)` | 数值类型 | 数值必须小于或等于指定值 |
| `@Email` | 字符串 | 字符串必须是合法的电子邮件地址格式 |
| `@Pattern(regexp=)` | 字符串 | 字符串必须匹配指定的正则表达式 |
| `@Future` / `@Past` | 日期时间类型 | 日期必须在当前时间的未来 / 过去 |
## 3.3 使用方法
```java
public class UserDTO {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度必须在3到20个字符之间")
private String username;
@NotBlank(message = "密码不能为空")
@Size(min = 8, message = "密码长度至少为8个字符")
private String password;
@Email(message = "邮箱格式不正确")
private String email;
}
```
&emsp;&emsp;在Controller的方法参数前使用@Valid或@Validated注解来触发校验
```java
@RestController
public class UserController {
@PostMapping("/users")
public String createUser(@Valid @RequestBody UserDTO userDTO) {
return "用户创建成功";
}
}
```
## 3.4 处理校验错误
```java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return errors;
}
}
```
## 3.5 自定义注解
```java
@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PhoneNumber {
String message() default "手机号码格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
```
&emsp;&emsp;校验规则:
```java
public class PhoneValidator implements ConstraintValidator<PhoneNumber, String> {
private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null || value.isEmpty()) {
return true; // 使用@NotBlank等注解处理空值
}
return PHONE_PATTERN.matcher(value).matches();
}
}
```
&emsp;&emsp;使用自定义校验:
```java
public class UserDTO {
@PhoneNumber
private String mobile;
}
```
# 四、ConfigurationProperties注解
&emsp;&emsp;@ConfigurationProperties 是 Spring Boot 提供的核心注解,用于将配置文件(如 application.yml/application.properties中的属性批量绑定到 Java 类的字段上,相比 @Value 注解,它更适合管理一组有层级、有前缀的配置,代码更整洁、可维护性更高。
## 4.1 配置文件
```yml
app:
name: SpringBootDemo
version: 1.0.0
author:
name: 张三
age: 25
servers:
- 192.168.1.100
- 192.168.1.101
- 192.168.1.102
```
## 4.2 配置属性类
```java
@Component
@ConfigurationProperties(prefix = "app")
@Getter
@Setter
public class AppProperties {
// 对应 app.name
private String name;
// 对应 app.version
private String version;
// 嵌套属性 - 对应 app.author
private Author author;
// 集合属性 - 对应 app.servers
private List<String> servers;
@Getter
@Setter
public static class Author {
private String name;
private Integer age;
}
}
```
&emsp;&emsp;属性类支持嵌套和集合属性。
## 4.3 使用
&emsp;&emsp;在Service或相应地方注入即可
```java
@Autowired
private AppProperties appProperties;
```