后端代码skill入门指南:从零构建高可维护性服务

2次阅读
没有评论

共计 2825 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

糟糕代码的典型问题

最近接手一个老项目的用户注册功能,代码让人头皮发麻:

后端代码 skill 入门指南:从零构建高可维护性服务

  • 200 行的 Controller 方法:注册逻辑、参数校验、数据库操作全堆在一起
  • 重复的密码加密代码:在三个地方看到相同的 MD5 加密逻辑
  • 零文档:前端同事需要不断打电话询问接口字段含义
  • 魔法数字泛滥 :各种if(status == 3) 散落各处

这样的代码每次修改都像走钢丝,稍有不慎就会引发连锁问题。接下来让我们用现代后端开发的最佳实践重构这个功能。

分层架构设计

1. 三层结构划分

  • Controller 层:处理 HTTP 请求 / 响应,不做业务逻辑

    @RestController
    @RequestMapping("/api/user")
    public class UserController {
        @Autowired
        private UserService userService;
    
        @Operation(summary = "用户注册")
        @PostMapping("/register")
        public ResponseEntity<UserVO> register(@Valid @RequestBody RegisterDTO dto) {return ResponseEntity.ok(userService.register(dto));
        }
    }

  • Service 层:核心业务逻辑,保持无状态

    @Service
    public class UserServiceImpl implements UserService {
        @Override
        public UserVO register(RegisterDTO dto) {
            // 业务逻辑组合
            checkDuplicateUsername(dto.getUsername());
            User user = convertToEntity(dto);
            userRepository.save(user);
            return convertToVO(user);
        }
    }

  • DAO 层:纯粹的数据访问,使用 Spring Data JPA 或 MyBatis

2. 使用 Lombok 简化代码

实体类可以简化到极致:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;

    @Column(unique = true, nullable = false)
    private String username;

    @Column(nullable = false)
    private String encryptedPassword;
}

RESTful API 实践

1. 标准响应结构

建议统一响应格式:

public class Result<T> {
    private int code;
    private String message;
    private T data;

    public static <T> Result<T> success(T data) {return new Result<>(200, "成功", data);
    }
}

2. Swagger 集成

pom.xml 添加依赖后:

@Configuration
@OpenAPIDefinition(info = @Info(title = "用户服务 API", version = "1.0"))
public class SwaggerConfig {
    @Bean
    public OpenAPI customOpenAPI() {return new OpenAPI().addSecurityItem(new SecurityRequirement().addList("JWT"));
    }
}

访问 /swagger-ui.html 即可获得交互式文档

避坑指南

1. 解决 N + 1 查询

错误的写法:

// Service 中
List<User> users = userRepository.findAll();
users.forEach(user -> {
    // 每次循环都会查询数据库
    List<Order> orders = orderRepository.findByUserId(user.getId()); 
});

正确方案:

// 使用 JPA 的 @EntityGraph
@EntityGraph(attributePaths = {"orders"})
List<User> findAll();

2. 密码安全存储

永远不要这样做:

// 致命错误!user.setPassword(password);

应该使用 BCrypt:

@Bean
public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();
}

// 使用时
user.setEncryptedPassword(passwordEncoder.encode(rawPassword));

3. 日志规范

推荐使用 SLF4J:

private static final Logger log = LoggerFactory.getLogger(UserService.class);

void someMethod() {log.info("用户注册开始,username={}", username);
    try {// ...} catch (Exception e) {log.error("注册异常", e); // 一定要打印堆栈
    }
}

单元测试示例

使用 MockMvc 测试 Controller:

@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Test
    void registerSuccess() throws Exception {mockMvc.perform(post("/api/user/register")
               .contentType(MediaType.APPLICATION_JSON)
               .content("{\"username\":\"test\",\"password\":\"123456\"}"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.data.username").value("test"));
    }
}

思考与进阶

当 API 需要兼容多版本时,可以考虑:

  1. URL 路径版本:/v1/api/user
  2. 请求头版本:Accept: application/vnd.myapi.v1+json
  3. 参数版本:/api/user?version=1

推荐进一步学习:
领域驱动设计(DDD):通过限界上下文划分复杂系统
CQRS 模式:将读写操作分离以获得更高性能

好的代码不是一蹴而就的,建议每次提交前问自己三个问题:
1. 这段代码半年后还能看懂吗?
2. 别人修改这里是否容易出错?
3. 出现异常时能否快速定位问题?

保持这种习惯,你的代码质量会不断提升。

正文完
 0
评论(没有评论)