自制笔记 | JavaWeb——分层解耦(持续更新...)

文章目录

三层架构

三层架构

controller:控制层,接收前端发送的请求,对请求进行处理,并相应数据
service:业务逻辑层,处理具体的业务逻辑
dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查

示例:

拆分前:(将所有的处理都写在Controller程序中)

public class EmpController {
    @RequestMapping("/listEmp")
    public Result list() {
        // 1.加载并解析emp.xml
        String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
        System.out.println(file);
        List<Emp> empList = XmlParserUtils.parse(file, Emp.class);

        //2.对数据进行转换处理
        empList.stream().forEach(emp -> {
            //处理gender
            String gender = emp.getGender();
            if("1".equals(gender))
                emp.setGender("男");
            else if("2".equals(gender))
                emp.setGender("女");

            //处理job
            String job = emp.getJob();
            if("1".equals(job))
                emp.setJob("讲师");
            else if("2".equals(job))
                emp.setJob("班主任");
            else if("3".equals(job))
                emp.setJob("就业指导");
        });

        //3.响应数据
        return Result.success(empList);
    }
}

拆分后:

Controller:

@RestController
public class EmpController {
    private EmpService empService = new EmpServiceA();

    @RequestMapping("/listEmp")
    public Result list() {
        //1.调用service,获取数据
        List<Emp> empList = empService.listEmp();

        //2.响应数据
        return Result.success(empList);
    }
}

Service:

接口:

public interface EmpService {
    public List<Emp> listEmp();
}

实现类:

public class EmpServiceA implements EmpService {
    private EmpDao empDao = new EmpDaoA();

    @Override
    public List<Emp> listEmp() {
        //1.调用dao,获取数据
        List<Emp> empList = empDao.listEmp();

        //2.对数据进行转换处理
        empList.stream().forEach(emp -> {
            //处理gender
            String gender = emp.getGender();
            if("1".equals(gender))
                emp.setGender("男");
            else if("2".equals(gender))
                emp.setGender("女");

            //处理job
            String job = emp.getJob();
            if("1".equals(job))
                emp.setJob("讲师");
            else if("2".equals(job))
                emp.setJob("班主任");
            else if("3".equals(job))
                emp.setJob("就业指导");
        });

        //3.返回处理结果
        return empList;
    }
}

Dao:

接口:

public interface EmpDao {
    //获取员工列表数据
    public List<Emp> listEmp();
}

实现类:

public class EmpDaoA implements EmpDao {
    @Override
    public List<Emp> listEmp() {
        //加载并解析emp.xml
        String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
        System.out.println(file);
        List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
        return empList;
    }
}

以上的Service层和Dao层均采用了面向接口的形式,这样做的目的是使得程序更加灵活。比如Dao层获取数据的方式可能来源于文件、数据库、接口等形式,此时使用面向接口的方式会更加灵活

采用三层架构的好处是:复用性强、便于维护、利于拓展

分层解耦:

内聚:软件中各个功能模块内部的功能联系

耦合:衡量软件中各个层 / 模块之间的依赖、关联的程度

软件设计原则:高内聚低耦合

分层解耦

之前的代码中,Controller层在调用service层时,是new了一个对象EmpServiceA,而如果要切换Service的实现,将EmpServiceA切换为EmpServiceB,此时Controller层需要将EmpServiceA改成EmpServiceB,即Service层的代码发生改动,Controller层的代码也要发生改动,即这两个层之间的代码是耦合的

解耦方式:

解耦

控制反转:Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转

依赖注入:Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入

Bean对象:IOC容器中创建、管理的对象,称之为bean

IOC & DI

入门:

① Service层及Dao层的实现类,交给IOC容器管理

在类前加上@Conponent

② 为Controller及Service注入运行时,依赖的对象

在成员变量前加上@Autowired

修改之前的代码如下:

Controller:

@RestController
public class EmpController {
    @Autowired //运行时,IOC容器会提供该类型的bean对象,并赋值给该变量 - 依赖注入
    private EmpService empService;

    @RequestMapping("/listEmp")
    public Result list() {
        //1.调用service,获取数据
        List<Emp> empList = empService.listEmp();

        //2.响应数据
        return Result.success(empList);
    }
}

EmpServiceA:

@Component //将当前类交给IOC容器管理,成为IOC容器中的bean
public class EmpServiceA implements EmpService {
    @Autowired //运行时,IOC容器会提供该类型的bean对象,并赋值给该变量 - 依赖注入
    private EmpDao empDao;

    @Override
    public List<Emp> listEmp() {
        //1.调用dao,获取数据
        List<Emp> empList = empDao.listEmp();
        //...
    }
}

EmpDaoA:

@Component //将当前类交给IOC容器管理,成为IOC容器中的bean
public class EmpDaoA implements EmpDao {
    @Override
    public List<Emp> listEmp() {
        //加载并解析emp.xml
        String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
        System.out.println(file);
        List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
        return empList;
    }
}

若在之后需要切换Service或者Dao,只需要在对应的实现类前加上@Component,删去之前实现类的@Component即可

Bean的声明:

要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一:

注解说明位置
@Component声明bean的基础注解不属于以下三类时,用此注解
@Controller@Component的衍生注解标注在控制器类上
@Service@Component的衍生注解标注在业务类上
@Repository@Component的衍生注解标注在数据访问类上(由于与mybatis整合,用的少)

注意事项:

① 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写

@Repository(value = "daoA")
//也可以写成@Repository("daoA")

② 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能@Controller

Bean组件扫描:

前面声明bean的四大注解,想要生效,还需要被组件扫描注解@ComponentScan扫描,@Component注解虽然没有显式配置,但是实际上已经包含在启动类声明注解@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包

因此推荐按照springboot的规范,将所写的代码全部写在启动类所在包及其子包下

image-20240310193408587

Bean注入:

@Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会报出如下错误:

Bean注入报错

通过以下几种方案来解决:

@Primary

在哪个类前加上@Primary,即表示当前类注入的优先级更高,会优先注入

@Primary
@Service
public class EmpServiceA implements EmpService {
}

@Qualifier

通过@Autowired + @Qualifier("bean的名称"),可以指定注入对应名字的Bean

@RestController
public class EmpController {
    @Autowired
    @Qualifier("empServiceA")
    private EmpService empService;
}

@Resource

通过@Resource(name = "bean的名称")可以按照Bean的名称来进行注入

@RestController
public class EmpController {
    @Resource(name = "empServiceB")
    private EmpService empService;
}

@Resource@Autowired区别:

@Autowiredspring框架提供的注解,而@ResourceJDK提供的注解
@Autowired默认是按照类型注入,而@Resource默认是按照名称注入

  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值