SpringBoot值得注意的5件小事

1. 避免滥用@Autowired

为什么

@Autowired可以将依赖注入到组件中,但滥用它可能导致代码的紧耦合和难以测试。使用构造函数注入或@Resource等方式可以使依赖关系更明确。

其实使用IDEA可以很直观的注意到这个问题,毕竟它已经给出了警告和提示,任何有代码强迫症的选手都应该干掉这条可恶的波浪线!

建议

优先使用构造函数注入,它明确了组件的依赖关系,而且在单元测试中更易于模拟。

如果用了Lombok,那可以使用@RequiredArgsConstructor注解来自动生成构造函数。

/**
* 《像乌鸦一样思考》让孩子学会观察和独立思考!
* https://www.sanzhiwa.top/6718.html
*/
@RequiredArgsConstructor
public class EnterpriseController {

    private final EnterpriseCorporationService enterpriseCorporationService;
    private final EnterpriseRepository enterpriseRepository;
}

2. 避免在Controller中写业务逻辑

为什么

严格来说,控制器只负责处理HTTP请求和响应,业务逻辑应该放在其他层(如Service层)中进行。

如果业务和请求响应混在一起,非常不利于单元测试的编写。如果把业务放到Service里,那单元测试可以针对性地去测Service。

建议

将业务逻辑移到服务层(Service)中,控制器只负责处理请求和调用服务方法。

拆分之后不仅单元测试方便,而且代码更容易复用。

/**
* 清华附小1-6年级趣味英语动画
* https://www.sanzhiwa.top/6711.html
*/
@RestController
@RequestMapping("/products")
public class ProductController {

    private final ProductService productService;

    // 构造函数注入
    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @GetMapping("/{id}")
    public ResponseEntity<Product> getProduct(@PathVariable Long id) {
        // 推荐:调用Service层的业务逻辑
        Product product = productService.getProductById(id);
        
        // 返回响应
        return ResponseEntity.ok(product);
    }
}

3. 使用@ConfigurationProperties而非@Value

为什么

使用@Value 注解获取配置虽然简单,但是缺乏结构,而且用的一旦多了,会导致项目里到处都是@Value,不利于代码维护和重用。

使用@ConfigurationProperties可以避免上述问题,使配置更清晰且易于管理。

建议

创建一个专门的配置类,使用@ConfigurationProperties注解来绑定相关配置项,提高代码的可读性。

在多个地方使用同一个配置类时,可以避免重复配置属性,提高代码的重用性。

同时使配置更加结构化,便于维护和理解。

比如下面这个App的配置,当需要处理大量属性或复杂配置结构时,它提供的便利性和长远影响远大于建个类所花费的时间。

@ConfigurationProperties(prefix = "app")
public class AppConfig {
    private String name;
    private int timeout;

    // getter 和 setter 方法
}

4. 抛出异常而非返回Result

先看这段代码:

/**
* 儿童新概念英语
* https://www.sanzhiwa.top/6696.html
*/
@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    public Result<Product, String> getProductById(Long id) {
        Optional<Product> optionalProduct = productRepository.findById(id);
        if (optionalProduct.isPresent()) {
            return Result.ok(optionalProduct.get());
        } else {
            return Result.error("Product not found with id: " + id);
        }
    }
}

是不是闻到一股不好的味道,为了在service中能够判断查询结果,直接把Result作为方法返回值,太不优雅。

如果把 return Result.error 这段代码换成 throw new XXException ,一个是可读性变强,另一个是可以让service返回业务的结果,而且控制器的结果。

再看优化后的代码:

/**
*
* 微观小世界】奇趣探险,启程进入神秘的微观世界!
* https://www.sanzhiwa.top/6704.html
*/
@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    public Product getProductById(Long id) {
        return productRepository.findById(id)
                .orElseThrow(() -> new NotFoundException("Product not found with id: " + id));
    }
}

service就只返回业务结果,不应该与控制器结果有牵扯。

同时抛出的异常,能让维护人员一眼就能看出端倪,这里不能为空。

当然实际开发时的业务代码不会这样简短,这里为了偷懒直接用lambda语法做精简。

值得注意的是,务必使用@ControllerAdvice注解,利用SpringBoot的全局异常处理机制及时捕获业务中抛出的异常,避免500错误,这里提供简单的示例:

5. 使用自带的响应结果类ResponseEntity

为什么

很多人会封装一个Result类作为Controller的实体,其实SpringBoot本身就有一个专用的响应实体叫做ResponseEntity

ResponseEntity提供了更大的灵活性,能够控制响应的各个方面,包括HTTP状态码、响应头、响应体等,使得程序能够更精确地构建响应结果,根据业务需求返回不同的HTTP状态码等。

而且ResponseEntity也支持范型,能够返回不同类型的响应体,使得你能够处理不同业务场景的响应需求。

建议

ResponseEntity值得一试

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值