Java开发中的"非代码能力"

学习Java更多要了解知识的广度,除了技术栈,还包括开发流程、工程规范和协作意识。很多新手能写功能,但代码难以维护、协作困难。

版本控制:Git不只是备份工具

初级理解:用Git备份代码、提交到GitHub

专业理解:Git是团队协作的"时间机器"和"沟通工具"

必须掌握的工作流

# 标准Git分支策略(Git Flow简化版)
main/master     # 生产环境代码(永远稳定)
develop         # 开发分支(集成分支)
feature/xxx     # 功能分支(每个新功能一个分支)
hotfix/xxx      # 热修复分支(紧急bug修复)

# 正确提交流程
git checkout -b feature/user-login  # 创建功能分支
git add .
git commit -m "feat: 添加用户登录功能 #JIRA-123"  # 规范的提交信息
git push origin feature/user-login
# 然后在GitHub/GitLab创建Pull Request,请同事Review

关键点

  • 提交信息规范:使用Conventional Commits
    • feat:新功能
    • fix:修复bug
    • docs:文档变更
    • style:代码格式调整
    • refactor:重构
    • test:测试相关
  • 分支管理:一个功能一个分支,便于代码Review和回滚
  • Code Review文化:通过PR/MR让同事检查代码,互相学习

工程结构:项目不只是代码堆砌

新手项目结构

src/
  Main.java
  User.java
  Order.java
  ...

专业Spring Boot项目结构

src/main/java/com/example/demo/
├── DemoApplication.java          # 启动类
├── config/                       # 配置类
│   ├── WebConfig.java           # Web配置
│   └── RedisConfig.java         # Redis配置
├── controller/                   # 控制器层
│   └── UserController.java      # 接收HTTP请求
├── service/                      # 业务逻辑层
│   ├── UserService.java         # 业务接口
│   └── impl/                    # 实现类
│       └── UserServiceImpl.java
├── repository/                   # 数据访问层
│   └── UserRepository.java      # JPA Repository
├── entity/                       # 实体类
│   └── User.java                # 对应数据库表
├── dto/                          # 数据传输对象
│   └── UserDTO.java             # 前后端交互对象
├── vo/                           # 视图对象
│   └── UserVO.java              # 返回给前端的对象
└── exception/                    # 异常处理
    ├── BusinessException.java    # 业务异常
    └── GlobalExceptionHandler.java # 全局异常处理

为什么分层重要

  • 单一职责:每层只做一件事(Controller只处理请求/响应,Service只处理业务逻辑)
  • 便于测试:可以单独测试Service层,不用启动Web服务
  • 团队协作:前端只关心Controller接口,数据库人员只关心Entity

API设计:RESTful不只是URL格式

初级做法

@GetMapping("/getUsers")          // ❌ 动词冗余
@PostMapping("/addUser")          // ❌ 动词冗余
@PostMapping("/updateUser")       // ❌ 动词+名词混乱

专业RESTful设计

@RestController
@RequestMapping("/api/v1/users")  // 统一前缀+版本号
public class UserController {
    
    @GetMapping                   // GET /api/v1/users
    public List<UserVO> getUsers() { ... }
    
    @GetMapping("/{id}")          // GET /api/v1/users/1
    public UserVO getUser(@PathVariable Long id) { ... }
    
    @PostMapping                  // POST /api/v1/users
    public Result addUser(@RequestBody UserDTO dto) { ... }
    
    @PutMapping("/{id}")          // PUT /api/v1/users/1
    public Result updateUser(@PathVariable Long id, @RequestBody UserDTO dto) { ... }
    
    @DeleteMapping("/{id}")       // DELETE /api/v1/users/1
    public Result deleteUser(@PathVariable Long id) { ... }
}

专业细节

  1. 版本控制/api/v1/为后续版本升级留空间

  2. 统一响应体:所有接口返回统一格式

    {
      "code": 200,
      "message": "成功",
      "data": { ... },  // 成功时返回数据
      "timestamp": "2024-02-06T10:30:00"
    }
    
  3. 分页查询GET /api/v1/users?page=1&size=10&sort=id,desc

  4. 状态码正确使用

    • 200: 成功
    • 201: 创建成功
    • 400: 客户端错误(参数验证失败)
    • 401: 未授权
    • 403: 禁止访问
    • 404: 资源不存在
    • 500: 服务器内部错误

异常处理:不要让异常直接抛给用户

新手代码

@GetMapping("/{id}")
public UserVO getUser(@PathVariable Long id) {
    User user = userRepository.findById(id);
    return convertToVO(user);  // ❌ 如果id不存在,会返回null或抛异常
}

专业异常处理

// 1. 定义业务异常
public class BusinessException extends RuntimeException {
    private final int code;
    public BusinessException(int code, String message) {
        super(message);
        this.code = code;
    }
}

// 2. 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(BusinessException.class)
    public Result handleBusinessException(BusinessException e) {
        return Result.error(e.getCode(), e.getMessage());
    }
    
    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e) {
        log.error("系统异常", e);
        return Result.error(500, "系统繁忙,请稍后重试");
    }
}

// 3. Service层使用
public UserVO getUser(Long id) {
    return userRepository.findById(id)
           .map(this::convertToVO)
           .orElseThrow(() -> new BusinessException(404, "用户不存在"));
}

日志规范:不只是System.out.println

专业日志要求

@Slf4j  // Lombok注解,自动生成log对象
@Service
public class UserServiceImpl implements UserService {
    
    public UserVO login(String username, String password) {
        log.info("用户登录尝试: username={}", username);  // 使用占位符,不要字符串拼接
        
        if (StringUtils.isEmpty(username)) {
            log.warn("用户名不能为空");
            throw new BusinessException(400, "用户名不能为空");
        }
        
        try {
            // 业务逻辑
            log.debug("查询用户信息: username={}", username);  // debug级别日志
            return user;
        } catch (Exception e) {
            log.error("用户登录失败: username={}", username, e);  // 记录异常栈
            throw new BusinessException(500, "登录失败");
        }
    }
}

日志级别

  • ERROR:系统异常,需要立即处理
  • WARN:警告,可能有问题但不影响运行
  • INFO:关键业务流程日志
  • DEBUG:调试信息,开发时用
  • TRACE:最详细信息

推荐工具/库

  1. Lombok:减少样板代码(getter/setter/构造函数等)
  2. MapStruct:对象转换工具(Entity转DTO/VO)
  3. Validation:参数校验(@NotNull, @Email, @Size等)
  4. Swagger/OpenAPI:自动生成API文档

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐