SpringBootWeb极速入门-分层解耦(03)

案例分析

我们先看一个spring-boot-web开发的接口

java 复制代码
package com.shixiaoshi.controller;

import com.shixiaoshi.pojo.Emp;
import com.shixiaoshi.pojo.Result;
import com.shixiaoshi.utils.XmlParserUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
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);
        System.out.println(empList.stream());
        //2. 对数据进行转换处理 - gender, job
        empList.forEach(emp -> {
            //处理 gender 1: 男, 2: 女
            String gender = emp.getGender();
            if("1".equals(gender)){
                emp.setGender("男");
            }else if("2".equals(gender)){
                emp.setGender("女");
            }
            //处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
            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);
    }
}

上述代码定义了一个名为listEmp的接口,它对项目中的xml文件进行了解析,然后返回了解析后的数据。

上述代码并没有什么逻辑错误,但如果业务逻辑增加时,所有处理都放在EmpController类中进行处理是愚蠢的。我们需要对这个项目进行优化,让他更适合维护和拓展。

架构优化

什么是三层架构

我们可以将上述代码的功能分成三层结构

我们在设计接口、类或方法时,尽量要让他们的功能单一,只做一件事情,这就是设计模式中的单一职责原则

单一职责的设计模式会让我们的程序更易维护和拓展,因此,在javaweb开发中,有了三层架构的开发原则。

三层架构的内容

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

代码拆分

我们根据三层架构的原则,对原有项目进行拆分优化。首先,和创建dao包service包。

注:项目路径一定不能有中文,否则程序执行会报错

dao数据访问层

数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查,最终被service调用。

其访问的数据类型有很多,如文件中的数据、数据库中的数据 、别人接口中的数据。 我们要想灵活的实现这些方式的切换,可以使用面向接口的方式编程。

所以,我们先在dao包内定义一个EmpDao接口,增强其灵活性和可拓展性。

java 复制代码
package com.shixiaoshi.dao;
import com.shixiaoshi.pojo.Emp;
import java.util.List;

public interface EmpDao {
    //获取员工列表数据  listEmp 是接口中定义的抽象方法,需要子类实现
    public List<Emp> listEmp();
}

现在,我们来实现这个接口。首先,我们创建impl.EmpDaoA类,然后实现 EmpDao这个接口

alt + shift + p快捷实现类中的方法,然后从EmpController中复制其对应的数据处理方法

java 复制代码
package com.shixiaoshi.dao.imp;

import com.shixiaoshi.dao.EmpDao;
import com.shixiaoshi.pojo.Emp;
import com.shixiaoshi.utils.XmlParserUtils;

import java.util.List;

public class EmpDaoA implements EmpDao {
    @Override
    public List<Emp> listEmp() {
        //1. 加载并解析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;
    }
}

现在,我们dao层的数代码逻辑就完成。

service业务逻辑层

service的业务逻辑处理方式和bao层是一致的。我们先在service包内创建一个EmpService接口。

然后,我们创建impl.EmpServiceA这个类实现EmpService接口。同样的,我们从EmpController中复制数据处理逻辑

此时,我们会发现empList及其相关的方法报错了。这很正常,因为empList的值现在在dao层的EmpDaoA类中储存着,我们需要从这个类中获取empList

java 复制代码
private EmpDao empDao = new EmpDaoA();

List<Emp> empList = empDao.listEmp();

完整代码如下

java 复制代码
package com.shixiaoshi.service.impl;

import com.shixiaoshi.dao.EmpDao;
import com.shixiaoshi.dao.impl.EmpDaoA;
import com.shixiaoshi.pojo.Emp;
import com.shixiaoshi.service.EmpService;
import java.util.List;

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

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

        //2. 对数据进行转换处理 - gender, job
        empList.forEach(emp -> {
            //处理 gender 1: 男, 2: 女
            String gender = emp.getGender();
            if("1".equals(gender)){
                emp.setGender("男");
            }else if("2".equals(gender)){
                emp.setGender("女");
            }
            //处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
            String job = emp.getJob();
            if("1".equals(job)){
                emp.setJob("讲师");
            }else if("2".equals(job)){
                emp.setJob("班主任");
            }else if("3".equals(job)){
                emp.setJob("就业指导");
            }
        });
        return empList;
    }
}

现在,我们已经将代码已经改造完毕,我们对接口进行测试

总结

上述教程中,我们通过单一职责原理,将代码封装成了三层结构,每层结构只专注自己的事情。相比一开始所有代码写在一起,优化后的代码结构复用性强,利于拓展,便于维护!

但该项目改造后,还是存在一定的缺陷,比如我们的controller层代码依赖service代码

service层代码又依赖数据层代码

这三层结构数据耦合程度比较高,如果其中一个控制层的类名发生变化,对其耦合的数据层也会造成影响。

因此,该项目还可以进一步的进行解耦优化!

相关推荐
手握风云-3 分钟前
数据结构(Java版)第二期:包装类和泛型
java·开发语言·数据结构
喵叔哟22 分钟前
重构代码中引入外部方法和引入本地扩展的区别
java·开发语言·重构
尘浮生28 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
不是二师兄的八戒1 小时前
本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
java·docker·php
爱编程的小生1 小时前
Easyexcel(2-文件读取)
java·excel
带多刺的玫瑰1 小时前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
计算机毕设指导62 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
Gu Gu Study2 小时前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
Chris _data2 小时前
二叉树oj题解析
java·数据结构
牙牙7052 小时前
Centos7安装Jenkins脚本一键部署
java·servlet·jenkins