Files

20 KiB
Raw Permalink Blame History

Java代码规范

1. 命名规范

1.1 包命名

  • 包名全部小写,使用点分隔
  • 示例:com.emotionmuseum.user.controller

1.2 类命名

  • 使用大驼峰命名法(PascalCase)
  • 示例:UserControllerUserService

1.3 方法命名

  • 使用小驼峰命名法(camelCase
  • 示例:getUserByIdcreateUser

1.4 变量命名

  • 使用小驼峰命名法(camelCase
  • 常量使用全大写+下划线(UPPER_SNAKE_CASE
  • 示例:userNameMAX_RETRY_COUNT

2. 导入包规范

2.1 导入方式规范

重要原则:必须使用常规的import方式导入类,严禁在代码中使用全路径限定名方式导入类。

2.1.1 正确的导入方式

// ✅ 正确示例:使用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 错误的导入方式

// ❌ 错误示例:在代码中使用全路径限定名
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 导入顺序规范

// 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 导入优化规范

// ✅ 推荐:使用通配符导入相关的类
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 静态导入规范

// ✅ 正确:静态导入常用的静态方法
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 导入冲突处理

// 当出现类名冲突时,使用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 类结构顺序

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 方法结构

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 类注释

/**
 * 用户控制器
 * 
 * @author 作者名
 * @since 1.0.0
 */
@RestController
public class UserController {
}

4.2 方法注释

/**
 * 根据用户ID获取用户信息
 * 
 * @param userId 用户ID
 * @return 用户信息响应对象
 * @throws UserNotFoundException 当用户不存在时抛出
 */
public Result<UserResponse> getUserById(Long userId) {
}

5. 异常处理规范

5.1 异常定义

public class UserNotFoundException extends BusinessException {
    public UserNotFoundException(String message) {
        super(message);
    }
}

5.2 异常抛出

if (user == null) {
    throw new UserNotFoundException("用户不存在,ID: " + userId);
}

6. Log4j2日志规范

6.1 日志级别使用

// 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 日志记录规范

// 使用占位符,避免字符串拼接
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日志追踪

// 设置MDC信息
MDC.put("userId", userId.toString());
MDC.put("requestId", UUID.randomUUID().toString());

try {
    // 业务逻辑
} finally {
    // 清理MDC
    MDC.clear();
}

7. 数据库操作规范

7.1 MyBatis-Plus使用

// 查询单个
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层编写任何业务逻辑代码。

@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层禁止事项

// ❌ 错误示例:在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 请求响应对象规范

@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层完成,包括数据校验、业务规则判断、数据处理、事务管理等。

@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缓存注解

@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 异步方法定义

@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 测试类结构

@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 安全注解使用

@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 输入验证

@PostMapping("/users")
public Result<UserResponse> createUser(@Valid @RequestBody CreateUserRequest request) {
    return userService.createUser(request);
}

12.3 敏感信息处理

// 日志中脱敏
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 密码处理规范

@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处理

@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提交规范

feat(user): 添加用户注册功能
fix(auth): 修复登录验证bug
docs(api): 更新API文档
style(code): 格式化代码
refactor(service): 重构用户服务

总结

本代码规范涵盖了Java开发中的主要方面,包括命名规范、代码结构、注释规范、异常处理、日志记录、数据库操作、接口设计、缓存使用、异步处理、单元测试、安全规范和版本控制等。遵循这些规范可以确保代码的质量、可维护性和可扩展性。 遵循这些规范可以确保代码的质量、可维护性和可扩展性,提高团队开发效率。