Spring Boot 项目中部门查询功能实现与依赖注入优化

工程搭建

项目初始包结构

  • com.tlias

    • .TliasWebManagementApplication:启动类
    • .controller:Controller控制层代码,负责接收请求、处理参数、响应数据
    • .service:Service业务逻辑层代码,负责业务逻辑的处理
    • .mapper:数据访问层代码,负责对数据库进行CRUD的操作
    • .config:配置代码
    • .common:通用代码,例如工具类、全局常量、枚举、异常等
    • .dto:数据传递代码,负责在 Controller ↔ Service 或 Service ↔ Service 之间传递数据
    • .vo:用于 Controller 返回给前端的最终数据结构
    • .po:与数据库表字段严格对应

Controller、Service、Mapper 核心职责

  • Controller:作为前端与后端的 "接口人",接收前端请求,协调调用对应 Service,最终返回处理结果。
  • Service:专注业务逻辑处理,如数据校验、规则计算等,是核心业务的 "执行者",需时调用 Mapper 操作数据。
  • Mapper:仅负责与数据库交互,执行增删改查,是数据存取的 "专属通道",不处理复杂业务。

三者协作流程:前端请求 → Controller → Service → Mapper → 数据库,再逆向返回结果,形成完整数据处理链路。

我们现在来完成基础的查询部门功能

DeptController

java 复制代码
package com.tlias.tliaswebmanagement.controller;

import com.tlias.tliaswebmanagement.common.Result;
import com.tlias.po.Dept;
import com.tlias.service.DeptService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 部门控制器
 */
@RestController
@RequiredArgsConstructor
public class DeptController {

    /**
     * 依赖注入部门业务逻辑层对象到当前类中,方便后续使用
     * SpringBoot官方不推荐@Autowired注解,而是推荐使用@RequiredArgsConstructor注解
     */
    private final DeptService deptService;


    /**
     * 1. 查询部门列表
     * 根据接口文档可知,是GET请求,需要使用@GetMapping注解处理,并补全路径 "/depts"
     * 根据接口文档可知,返回的是统一响应结果Result,并且结果封装的是Dept部门对象集合
     */
    @GetMapping("/depts")
    public Result<List<Dept>> list() {
        //1.1 调用部门业务逻辑层,获取部门列表数据
        List<Dept> deptList = deptService.list();

        //1.2 将部门列表数据,封装到Result统一响应结果对象中返回
        return Result.success(deptList);
    }
}

DeptService

java 复制代码
package com.tlias.tliaswebmanagement.service;

import com.tlias.po.Dept;

import java.util.List;

/**
 * 部门业务逻辑层
 */
public interface DeptService {
    /**
     * 查询所有部门
     */
    List<Dept> list();
}

DeptServiceImpl

java 复制代码
package com.tlias.tliaswebmanagement.service.impl;

import com.tlias.po.Dept;
import com.tlias.tliaswebmanagement.mapper.DeptMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 部门业务逻辑层实现类,需要加@Service注解
 */
@Service
public class DeptServiceImpl implements com.tlias.service.DeptService {

    @Autowired
    private DeptMapper deptMapper;

    /**
     * 1.查询部门列表
     */
    @Override
    public List<Dept> list() {
        //1.1 由于获取部门列表数据的逻辑及其简单,这里就只需要调用数据访问层对象,让其拿到结果即可
        List<Dept> deptList =deptMapper.selectAll();
        //1.2 获取到的部门集合返回给Controller控制层
        return deptList;
    }
}

DeptMapper

java 复制代码
package com.tlias.tliaswebmanagement.mapper;

import com.tlias.po.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * 部门映射器
 * 对于Mabatis框架,数据访问层代码需要加@Mapper注解
 */
@Mapper
public interface DeptMapper {

    /**
     * 1.查询tb_dept表,查询所有数据,使用@Select注解
     */

    @Select("select * from tb_dept")
    List<Dept> selectAll();
}

"依赖注入优化" 主要指的是通过 lombok.RequiredArgsConstructor 注解替代传统的 @Autowired 注解来实现依赖注入,这种方式是 Spring Boot 官方更推荐的做法,核心优势如下:

1. 为什么不推荐 @Autowired

  • 潜在问题@Autowired 可以直接标注在字段上实现注入,但这种方式会导致:

    • 依赖关系不明显,从代码上难以直观看出类依赖了哪些对象(需要翻找注解位置)。
    • 可能引发空指针风险(若注入失败,编译期无法发现,运行时才报错)。
    • 不利于单元测试(难以手动构造依赖对象进行模拟测试)。

2. @RequiredArgsConstructor 优化在哪里?

  • 原理 :这是 Lombok 提供的注解,作用是自动生成包含所有 final 修饰的成员变量的构造方法 。Spring 会通过这个构造方法,将依赖的对象(如 DeptServiceDeptMapper)自动传入并赋值,实现依赖注入。

  • 优势

    • 依赖关系更清晰 :被注入的对象必须用 final 修饰(如 private final DeptService deptService),一眼就能看出类依赖了哪些组件。
    • 避免空指针final 变量必须初始化,若忘记注入或注入失败,编译期就会报错,提前暴露问题。
    • 便于测试:可以通过构造方法手动传入模拟对象(如 Mock 测试),更符合面向对象的设计原则。

总结

简单说,@RequiredArgsConstructor 替代 @Autowired 的本质是:用 "构造方法注入" 替代 "字段注入" ,通过强制 final 修饰和自动生成构造方法,让依赖关系更明确、代码更健壮,同时规避了 @Autowired 的潜在风险,这也是 Spring 官方推荐的依赖注入最佳实践。

删除部门功能:

  • DeptController部分代码

    kotlin 复制代码
       /**
      * 2. 根据ID删除部门
      * 根据接口文档可知,请求是DELETE类型,使用 @DeleteMapping 注解处理,并补全路径 "/depts"
      */
      @DeleteMapping( "/depts" )
      public Result delete(Integer id) {
          //2.1 利用部门业务逻辑层对象deptService,传入id,让其执行删除部门的逻辑代码
       deptService.deleteById(id);
          //2.2 返回一个默认的成功结果
       return Result.success();
      }
    1. Service

  • 思路:利用deptMapper数据访问层对象,根据传入的id删除数据表中的对应部门数据

  • DeptService接口

    java 复制代码
      package com.tlias.service;
    
      import com.tlias.po.Dept;
    
      import java.util.List;
    
      /**
      * 部门业务逻辑层
      */
      public  interface DeptService {
          /**
      * 查询所有部门
      */
      List<Dept> list();
    
          /**
      * 根据ID删除部门
      */
       void deleteById(Integer id);
      }
    • DeptServiceImpl部分代码

    typescript 复制代码
       /**
      * 2. 根据ID删除部门
      */
      @Override
      public  void deleteById(Integer id) {
          //2.1 利用deptMapper数据访问层对象,根据传入的id删除数据表中的对应部门数据
       deptMapper.deleteById(id);
      }

Mapper

  • 思路

    • sql语句:delete from tb_dept where id = 指定的ID值;
    • 定义deleteById方法,处理删除功能
    • 在方法上使用@Delete注解,放入对应sql语句,需要传入的值,使用#{...}占位符填充
  • DeptMapper部分代码

    java 复制代码
       /**
      * 2.根据ID删除部门
      * 删除操作,使用 @Delete 注解
      */
      @Delete( "delete from tb_dept where id = #{id}" )
      void deleteById(Integer id);
相关推荐
鬼火儿8 小时前
15.<Spring Boot 日志>
java·后端
Mos_x8 小时前
SpringBoot】Spring Boot 项目的打包配置
java·后端
qianbailiulimeng8 小时前
【Spring Boot】Spring Boot解决循环依赖
java·后端
何中应8 小时前
Spring Boot解决循环依赖的几种办法
java·spring boot·后端
江湖人称小鱼哥8 小时前
Redisson 与 Spring Boot 3.4 整合指南
spring boot·redis·后端·redission
donotshow8 小时前
SpringBoot】Spring Boot 项目的打包配置
java·后端
鬼火儿8 小时前
Spring Boot 整合 ShedLock 处理定时任务重复
java·后端
王元_SmallA8 小时前
【Spring Boot】Spring Boot解决循环依赖
java·后端
洛卡卡了9 小时前
一次上线事故,我干脆写了套灰度发布系统
后端·面试·架构