Files
happy-life-star/backend-single/后端代码规范.md
T

727 lines
20 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.
# Java代码规范
## 1. 命名规范
### 1.1 包命名
- 包名全部小写,使用点分隔
- 示例:`com.emotionmuseum.user.controller`
### 1.2 类命名
- 使用大驼峰命名法(PascalCase
- 示例:`UserController``UserService`
### 1.3 方法命名
- 使用小驼峰命名法(camelCase)
- 示例:`getUserById``createUser`
### 1.4 变量命名
- 使用小驼峰命名法(camelCase)
- 常量使用全大写+下划线(UPPER_SNAKE_CASE
- 示例:`userName``MAX_RETRY_COUNT`
## 2. 导入包规范
### 2.1 导入方式规范
**重要原则:必须使用常规的import方式导入类,严禁在代码中使用全路径限定名方式导入类。**
#### 2.1.1 正确的导入方式
```java
// ✅ 正确示例:使用import语句导入类
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.emotionmuseum.dto.request.CreateUserRequest;
import com.emotionmuseum.dto.response.UserResponse;
import com.emotionmuseum.service.UserService;
import com.emotionmuseum.common.result.Result;
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
@Slf4j
public class UserController {
private final UserService userService;
@PostMapping
public Result<UserResponse> createUser(@RequestBody CreateUserRequest request) {
UserResponse response = userService.createUser(request);
return Result.success(response);
}
}
```
#### 2.1.2 错误的导入方式
```java
// ❌ 错误示例:在代码中使用全路径限定名
public class UserController {
@org.springframework.beans.factory.annotation.Autowired
private com.emotionmuseum.service.UserService userService;
@org.springframework.web.bind.annotation.PostMapping
public com.emotionmuseum.common.result.Result<com.emotionmuseum.dto.response.UserResponse>
createUser(@org.springframework.web.bind.annotation.RequestBody
com.emotionmuseum.dto.request.CreateUserRequest request) {
com.emotionmuseum.dto.response.UserResponse response = userService.createUser(request);
return com.emotionmuseum.common.result.Result.success(response);
}
}
```
### 2.2 导入顺序规范
```java
// 1. Java标准库导入
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
// 2. 第三方库导入(按字母顺序)
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
// 3. 项目内部导入(按包层次顺序)
import com.emotionmuseum.common.result.Result;
import com.emotionmuseum.dto.request.CreateUserRequest;
import com.emotionmuseum.dto.response.UserResponse;
import com.emotionmuseum.service.UserService;
```
### 2.3 导入优化规范
```java
// ✅ 推荐:使用通配符导入相关的类
import org.springframework.web.bind.annotation.*;
// ✅ 推荐:分别导入不同包的类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
// ❌ 不推荐:过度使用通配符导入
import org.springframework.*;
// ❌ 不推荐:导入未使用的类
import java.util.ArrayList; // 如果代码中没有使用ArrayList
```
### 2.4 静态导入规范
```java
// ✅ 正确:静态导入常用的静态方法
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
// ✅ 正确:静态导入项目中的工具类方法
import static com.emotionmuseum.common.util.DateUtil.formatDateTime;
import static com.emotionmuseum.common.util.StringUtil.isBlank;
// ❌ 错误:避免过度使用静态导入
import static java.lang.Math.*;
import static java.util.Collections.*;
```
### 2.5 导入冲突处理
```java
// 当出现类名冲突时,使用import别名或明确指定包名
import com.emotionmuseum.dto.response.Result;
import org.springframework.http.ResponseEntity;
public class UserController {
// 使用别名避免冲突
public com.emotionmuseum.dto.response.Result<UserResponse> createUser() {
// 业务逻辑
}
// 或者使用import别名(如果IDE支持)
// import com.emotionmuseum.dto.response.Result as EmotionResult;
}
```
## 3. 代码结构规范
### 3.1 类结构顺序
```java
public class ExampleClass {
// 1. 静态常量
public static final String CONSTANT = "value";
// 2. 实例变量
private String instanceVariable;
// 3. 构造方法
public ExampleClass() {}
// 4. 公共方法
public void publicMethod() {}
// 5. 私有方法
private void privateMethod() {}
}
```
### 3.2 方法结构
```java
public Result<UserResponse> getUserById(Long userId) {
// 1. 参数校验
if (userId == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
// 2. 业务逻辑
User user = userService.getById(userId);
// 3. 数据转换
UserResponse response = UserConverter.toResponse(user);
// 4. 返回结果
return Result.success(response);
}
```
## 4. 注释规范
### 4.1 类注释
```java
/**
* 用户控制器
*
* @author 作者名
* @since 1.0.0
*/
@RestController
public class UserController {
}
```
### 4.2 方法注释
```java
/**
* 根据用户ID获取用户信息
*
* @param userId 用户ID
* @return 用户信息响应对象
* @throws UserNotFoundException 当用户不存在时抛出
*/
public Result<UserResponse> getUserById(Long userId) {
}
```
## 5. 异常处理规范
### 5.1 异常定义
```java
public class UserNotFoundException extends BusinessException {
public UserNotFoundException(String message) {
super(message);
}
}
```
### 5.2 异常抛出
```java
if (user == null) {
throw new UserNotFoundException("用户不存在,ID: " + userId);
}
```
## 6. Log4j2日志规范
### 6.1 日志级别使用
```java
// FATAL: 致命错误,系统无法继续运行
logger.fatal("系统严重错误,无法继续运行", e);
// ERROR: 系统错误
logger.error("数据库连接失败", e);
// WARN: 警告信息
logger.warn("用户{}尝试访问未授权资源", userId);
// INFO: 重要业务信息
logger.info("用户{}登录成功", username);
// DEBUG: 调试信息
logger.debug("查询用户参数: {}", queryParams);
// TRACE: 详细调试信息
logger.trace("进入方法: {}", methodName);
```
### 6.2 日志记录规范
```java
// 使用占位符,避免字符串拼接
logger.info("用户{}在{}登录成功", username, LocalDateTime.now());
// 异常日志记录
try {
// 业务逻辑
} catch (Exception e) {
logger.error("处理用户请求失败,用户ID: {}, 错误信息: {}", userId, e.getMessage(), e);
throw new BusinessException("处理失败");
}
// 性能日志记录
long startTime = System.currentTimeMillis();
// 业务逻辑
long endTime = System.currentTimeMillis();
logger.info("查询用户信息耗时: {}ms", endTime - startTime);
```
### 6.3 MDC日志追踪
```java
// 设置MDC信息
MDC.put("userId", userId.toString());
MDC.put("requestId", UUID.randomUUID().toString());
try {
// 业务逻辑
} finally {
// 清理MDC
MDC.clear();
}
```
## 7. 数据库操作规范
### 7.1 MyBatis-Plus使用
```java
// 查询单个
User user = userMapper.selectById(userId);
// 条件查询
List<User> users = userMapper.selectList(
new LambdaQueryWrapper<User>()
.eq(User::getStatus, UserStatus.ACTIVE)
.orderByDesc(User::getCreateTime)
);
```
## 8. 接口设计规范
### 8.1 Controller层规范
**重要原则:Controller层只负责接收请求、参数校验、调用Service层、返回结果,严禁在Controller层编写任何业务逻辑代码。**
```java
@RestController
@RequestMapping("/api/users")
@Validated
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public Result<UserResponse> createUser(@Valid @RequestBody CreateUserRequest request) {
// Controller层只做:参数校验(通过@Valid)、调用Service、返回结果
UserResponse response = userService.createUser(request);
return Result.success(response);
}
@GetMapping("/{id}")
public Result<UserResponse> getUserById(@PathVariable Long id) {
// Controller层只做:调用Service、返回结果
UserResponse response = userService.getUserById(id);
return Result.success(response);
}
@PutMapping("/{id}")
public Result<UserResponse> updateUser(@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
// Controller层只做:参数校验、调用Service、返回结果
UserResponse response = userService.updateUser(id, request);
return Result.success(response);
}
@DeleteMapping("/{id}")
public Result<Void> deleteUser(@PathVariable Long id) {
// Controller层只做:调用Service、返回结果
userService.deleteUser(id);
return Result.success(null);
}
}
```
### 8.2 Controller层禁止事项
```java
// ❌ 错误示例:在Controller层编写业务逻辑
@PostMapping("/users")
public Result<UserResponse> createUser(@Valid @RequestBody CreateUserRequest request) {
// 错误:在Controller层进行业务判断
if (userMapper.selectByUsername(request.getUsername()) != null) {
throw new BusinessException("用户名已存在");
}
// 错误:在Controller层进行数据转换
User user = new User();
user.setUsername(request.getUsername());
user.setPassword(passwordEncoder.encode(request.getPassword()));
// 错误:在Controller层直接操作数据库
userMapper.insert(user);
// 错误:在Controller层进行复杂的数据处理
UserResponse response = new UserResponse();
response.setId(user.getId());
response.setUsername(user.getUsername());
return Result.success(response);
}
// ✅ 正确示例:Controller层只负责调用Service
@PostMapping("/users")
public Result<UserResponse> createUser(@Valid @RequestBody CreateUserRequest request) {
UserResponse response = userService.createUser(request);
return Result.success(response);
}
```
### 8.3 请求响应对象规范
```java
@Data
public class CreateUserRequest {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
}
@Data
public class UserResponse {
private Long id;
private String username;
private LocalDateTime createTime;
}
```
### 8.4 Service层业务逻辑规范
**重要原则:所有业务逻辑必须在Service层完成,包括数据校验、业务规则判断、数据处理、事务管理等。**
```java
@Service
@Transactional
@Slf4j
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserResponse createUser(CreateUserRequest request) {
// 1. 业务参数校验
validateCreateUserRequest(request);
// 2. 业务规则判断
checkUserExists(request.getUsername());
// 3. 数据转换和业务处理
User user = convertToUser(request);
user.setPassword(passwordEncoder.encode(request.getPassword()));
// 4. 数据持久化
userMapper.insert(user);
// 5. 返回结果转换
return convertToResponse(user);
}
@Override
public UserResponse getUserById(Long id) {
// 1. 参数校验
if (id == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
// 2. 业务逻辑:查询用户
User user = userMapper.selectById(id);
if (user == null) {
throw new UserNotFoundException("用户不存在,ID: " + id);
}
// 3. 返回结果转换
return convertToResponse(user);
}
@Override
public UserResponse updateUser(Long id, UpdateUserRequest request) {
// 1. 参数校验
validateUpdateUserRequest(id, request);
// 2. 业务逻辑:检查用户是否存在
User existingUser = userMapper.selectById(id);
if (existingUser == null) {
throw new UserNotFoundException("用户不存在,ID: " + id);
}
// 3. 业务规则判断
if (StringUtils.hasText(request.getUsername())) {
checkUserExists(request.getUsername(), id);
}
// 4. 数据更新
updateUserFields(existingUser, request);
userMapper.updateById(existingUser);
// 5. 返回结果转换
return convertToResponse(existingUser);
}
@Override
public void deleteUser(Long id) {
// 1. 参数校验
if (id == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
// 2. 业务逻辑:检查用户是否存在
User user = userMapper.selectById(id);
if (user == null) {
throw new UserNotFoundException("用户不存在,ID: " + id);
}
// 3. 业务规则判断:检查是否可以删除
checkUserCanBeDeleted(user);
// 4. 执行删除
userMapper.deleteById(id);
log.info("用户删除成功,ID: {}", id);
}
// 私有方法:业务校验
private void validateCreateUserRequest(CreateUserRequest request) {
if (request == null) {
throw new IllegalArgumentException("请求参数不能为空");
}
// 其他业务校验逻辑
}
private void checkUserExists(String username) {
User existingUser = userMapper.selectByUsername(username);
if (existingUser != null) {
throw new BusinessException("用户名已存在: " + username);
}
}
private void checkUserExists(String username, Long excludeId) {
User existingUser = userMapper.selectByUsernameAndIdNot(username, excludeId);
if (existingUser != null) {
throw new BusinessException("用户名已存在: " + username);
}
}
private void checkUserCanBeDeleted(User user) {
// 检查用户是否可以删除的业务逻辑
if (user.getStatus() == UserStatus.ACTIVE) {
// 检查是否有未完成的订单等
if (hasUnfinishedOrders(user.getId())) {
throw new BusinessException("用户有未完成的订单,无法删除");
}
}
}
// 私有方法:数据转换
private User convertToUser(CreateUserRequest request) {
User user = new User();
user.setUsername(request.getUsername());
user.setEmail(request.getEmail());
user.setStatus(UserStatus.ACTIVE);
return user;
}
private UserResponse convertToResponse(User user) {
UserResponse response = new UserResponse();
response.setId(user.getId());
response.setUsername(user.getUsername());
response.setEmail(user.getEmail());
response.setStatus(user.getStatus());
response.setCreateTime(user.getCreateTime());
return response;
}
}
```
## 9. 缓存使用规范
### 9.1 Redis缓存注解
```java
@Cacheable(value = "user", key = "#userId")
public UserResponse getUserById(Long userId) {
// 业务逻辑
}
@CacheEvict(value = "user", key = "#userId")
public void updateUser(Long userId, UpdateUserRequest request) {
// 更新逻辑
}
```
## 10. 异步处理规范
### 10.1 异步方法定义
```java
@Async("notificationExecutor")
public CompletableFuture<Void> sendNotificationAsync(Long userId, String message) {
try {
sendNotification(userId, message);
return CompletableFuture.completedFuture(null);
} catch (Exception e) {
logger.error("发送通知失败", e);
return CompletableFuture.failedFuture(e);
}
}
```
## 11. 单元测试规范
### 11.1 测试类结构
```java
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserMapper userMapper;
@InjectMocks
private UserServiceImpl userService;
@Test
@DisplayName("根据ID获取用户 - 成功")
void getUserById_Success() {
// Given
Long userId = 1L;
User user = new User();
user.setId(userId);
when(userMapper.selectById(userId)).thenReturn(user);
// When
UserResponse result = userService.getUserById(userId);
// Then
assertThat(result).isNotNull();
assertThat(result.getId()).isEqualTo(userId);
}
}
```
## 12. Spring Security安全规范
### 12.1 安全注解使用
```java
@RestController
@RequestMapping("/api/users")
public class UserController {
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin")
public Result<List<UserResponse>> getAllUsers() {
// 只有ADMIN角色可以访问
}
@PreAuthorize("hasRole('USER') and #userId == authentication.principal.id")
@GetMapping("/{userId}")
public Result<UserResponse> getUserById(@PathVariable Long userId) {
// 只有USER角色且只能访问自己的信息
}
@PreAuthorize("permitAll()")
@PostMapping("/register")
public Result<UserResponse> register(@Valid @RequestBody CreateUserRequest request) {
// 允许所有人访问
}
}
```
### 12.2 输入验证
```java
@PostMapping("/users")
public Result<UserResponse> createUser(@Valid @RequestBody CreateUserRequest request) {
return userService.createUser(request);
}
```
### 12.3 敏感信息处理
```java
// 日志中脱敏
logger.info("用户{}登录成功", maskUsername(username));
private String maskUsername(String username) {
if (username == null || username.length() <= 2) {
return username;
}
return username.substring(0, 1) + "***" + username.substring(username.length() - 1);
}
```
### 12.4 密码处理规范
```java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private PasswordEncoder passwordEncoder;
public void createUser(CreateUserRequest request) {
// 密码加密存储
String encodedPassword = passwordEncoder.encode(request.getPassword());
user.setPassword(encodedPassword);
// 密码验证
if (passwordEncoder.matches(rawPassword, encodedPassword)) {
// 密码正确
}
}
}
```
### 12.5 JWT Token处理
```java
@Component
public class JwtTokenProvider {
public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + jwtExpirationMs))
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
public String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
```
## 13. 版本控制规范
### 13.1 Git提交规范
```bash
feat(user): 添加用户注册功能
fix(auth): 修复登录验证bug
docs(api): 更新API文档
style(code): 格式化代码
refactor(service): 重构用户服务
```
## 总结
本代码规范涵盖了Java开发中的主要方面,包括命名规范、代码结构、注释规范、异常处理、日志记录、数据库操作、接口设计、缓存使用、异步处理、单元测试、安全规范和版本控制等。遵循这些规范可以确保代码的质量、可维护性和可扩展性。
遵循这些规范可以确保代码的质量、可维护性和可扩展性,提高团队开发效率。