《web应用技术》第四次课后练习

1.分层解耦-三层架构

上节课案例中,全部都写在一个类empController中,而在设计和开发的时候需要尽量让每一个接口、类或者是方法它的职责更加单一,只管一块儿功能,即单一职责原则,才会使可读性更强、复杂度更低、拓展性更好以及利于后期维护,基于此才有了三层架构。

controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。

service:业务逻辑层,处理具体的业务逻辑。

dao:数据访问层(Data Access Object持久层),负责数据访问操作,包括数据的增删改查。

过程:前端发起请求后,先会到达controller,controller接收到请求后要去调用service进行逻辑处理;逻辑处理的前提是先拿到数据,此时service层先去调用dao层,dao层再去操作文件当中的数据;数据拿到之后再将数据返回给service,service再进行逻辑处理并将结果返回给controller,controller再响应数据给前端。

(总之就是controller->service->dao->数据文件->dao->service->controller->前端)

面向接口的方式进行编程:(灵活切换各种实现)

dao:

创建包dao,编写接口EmpDao:

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

在dao下创建包impl,编写类EmpDaoA:

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);
        //引用工具类当中的一个方法parse方法解析xml文件,file代表要解析哪一份文件,targetClass表示解析的xml文件要往哪个对象里去封装
        List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
        return empList;
    }
}

service:

创建包service,编写接口EmpService:

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

在service下创建包impl,编写类EmpServiceA:

public class EmpServiceA implements EmpService {
    //1.创建dao层对象,接收dao层的数据
    private EmpDao empDao = new EmpDaoA();

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

        //3.对数据进行转换处理gender job
        //基于stream流遍历一下,拿到里面的每一个元素
        empList.stream().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:

编写EmpController:

@RestController
public class EmpController {
        //1.创建service对象,接收service处理过的数据
    private EmpServiceA empServiceA = new EmpServiceA();
    @RequestMapping("/listEmp")
    public Result list(){
        //2.调用service获取数据
        List<Emp> empList = empServiceA.listEmp();
        //3.响应数据(统一结果)
        return Result.success(empList);
        //传递了响应回去的数据经过@Responsebody注解处理就会转换成json响应到客户端
    }
}

2.分层解耦-分层解耦和IOC-DI

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

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

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

如何解耦?控制反转和依赖注入。

Bean对象:IOC容器中创建、管理的对象。

控制反转(IOC):对象的创建控制权由程序自身转移到外部容器。

service层和dao层的实现类,交给IOC容器管理:

在EmpDao和EmpService中方法前添加@component注解,表示将当前类交给IOC容器管理,成为IOC容器中的bean。

依赖注入(DI):容器为应用程序提供运行时,所依赖的资源。

为Controller及service注入运行时依赖的对象:

1)在EmpController和EmpService的成员变量前添加@Autowired注解表示运行时,IOC容器会提供该类型的bean对象,并赋值给该变量,即依赖注入。

形象来说就是有一个池子,@Component将当前类添加进去,@Autowired表示使用池子里的类对象,这个池子就叫IOC容器,类对象叫做bean对象.

*如果要切换实现类,比如想要实现EmpServiceB,只需将A的@Component注释掉,在B中添加@Component注释即可。

3.分层解耦-IOC详解

bean的声明:

@Component包括三个衍生注解:@Controller(标注在控制器类上*在springboot集成web开发中,声明控制器bean只能用@Controller),@Service(标注在业务类上),@Repository(标注在数据访问类上,由于与mybatis整合,用的少);不属于三类时用@Component.

即上述EmpDaoA中可以改为@Repository,EmpServiceA中可以改为@Service,而EmpController中不必添加,因为@RestController中包含两个注解,@ResponseBody和@Controller.

*如果要修改bean对象的名字,在注解后添加(value = “xxx”)即可,默认是首字母小写的类名。

bean的组件扫描:

四大注解要想生效,还需要被组件扫描注解@ComponentScan(没有显示配置)扫描,默认扫描的范围是启动类(com.example.xxxx)所在包及其子包。

4.分层解耦-DI详解

bean注入:

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

解决:

1)在开头加上注解@primary表示优先选择哪一个bean

2)在@Autowired前加上注解@Qualifier("bean的名字")表示选择哪一个bean

3)使用@Resource(“bean的名字”)不使用@Autowired——区别:@Autowired是spring框架提供的注解,而@Resource是jdk提供的注解;@Autowired默认时按照类型注入,而@Resource默认是按照名称注入。

5.要求:读取xml文件并在页面中显示出来。

1)常规方式,controlller控制器不分层

先编写Pojo包下的实体类Writer类,成员变量名要与xml文件中一样:

package com.example.writeremp.Pojo;

public class Writer {
    private String author;
    private String gender;
    private String dynasty;
    private String title;
    private String style;

    //get set方法
    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getDynasty() {
        return dynasty;
    }

    public void setDynasty(String dynasty) {
        this.dynasty = dynasty;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getStyle() {
        return style;
    }

    public void setStyle(String style) {
        this.style = style;
    }

    //有参构造
    public Writer(String author, String gender, String dynasty, String title, String style) {
        this.author = author;
        this.gender = gender;
        this.dynasty = dynasty;
        this.title = title;
        this.style = style;
    }

    //无参构造
    public Writer() {
    }
}

修改工具类XmlParseUtils,导入Result类:

package com.example.writeremp.Utils;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;

public class XmlParserUtils {

    public static <T> List<T> parse(String file , Class<T> targetClass)  {
        ArrayList<T> list = new ArrayList<T>(); //封装解析出来的数据
        try {
            //1.获取一个解析器对象
            SAXReader saxReader = new SAXReader();
            //2.利用解析器把xml文件加载到内存中,并返回一个文档对象
            Document document = saxReader.read(new File(file));
            //3.获取到根标签
            Element rootElement = document.getRootElement();
            //4.通过根标签来获取 user 标签
            List<Element> elements = rootElement.elements("writer");

            //5.遍历集合,得到每一个 user 标签
            for (Element element : elements) {
                //获取 author 属性
                String author = element.element("author").getText();
                //获取 gender 属性
                String gender = element.element("gender").getText();
                //获取 dynasty 属性
                String dynasty = element.element("dynasty").getText();
                //获取 title 属性
                String title = element.element("title").getText();
                //获取 style 属性
                String style = element.element("style").getText();

                //组装数据
                Constructor<T> constructor = targetClass.getDeclaredConstructor(String.class, String.class, String.class, String.class,String.class);
                constructor.setAccessible(true);
                T object = constructor.newInstance(author, gender, dynasty,title,style);

                list.add(object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

}

再编写writer.html,利用插值表达式:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>诗人信息</title>
</head>

<link rel="stylesheet" href="element-ui/index.css">
<script src="./js/vue.js"></script>
<script src="./element-ui/index.js"></script>
<script src="./js/axios-0.18.0.js"></script>

<body>
    <h1 align="center">诗人信息列表展示</h1>
    <div id="app">
    <table border="1" cellspacing="0" width="100%">
        <tr align="center" >
            <td>编号</td>
            <td>姓名</td>
            <td>性别</td>
            <td>朝代</td>
            <td>头衔</td>
            <td>风格</td>
        </tr>
        <tr v-for="(writer,index) in tableData" align="center">
            <td>{{index+1}}</td>
            <td>{{writer.author}}</td>
            <td>{{writer.gender}}</td>
            <td>{{writer.dynasty}}</td>
            <td>{{writer.title}}</td>
            <td>{{writer.style}}</td>
        </tr>
    </table>
</div>
</body>
<style>
    .el-table .warning-row {
        background: oldlace;
    }
    .el-table .success-row {
        background: #f0f9eb;
    }
</style>

<script>
    new Vue({
        el: "#app",
        data() {
            return {
                tableData: []
            }
        },
        mounted(){//vue的钩子方法发起异步请求请求数据
            axios.get('/listWriter').then(result =>{
                if(result.data.code){//回调函数中判断返回code的值
                    this.tableData = result.data.data;
                }
            });
        },
        methods: {
        }
    });
</script>
</html>

最后编写controller包下的WriterController:

package com.example.writeremp.Controller;

import com.example.writeremp.Pojo.Result;
import com.example.writeremp.Pojo.Writer;
import com.example.writeremp.Utils.XmlParserUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class WriterController {
    @RequestMapping("/listWriter")
    public Result list(){

        String file = this.getClass().getClassLoader().getResource("writer.xml").getFile();
        System.out.println(file);
        //1.引用工具类当中的一个方法parse方法解析xml文件,file代表要解析哪一份文件,targetClass表示解析的xml文件要往哪个对象里去封装
        List<Writer> writerList = XmlParserUtils.parse(file, Writer.class);

        //2.对数据进行转换处理gender job
        //基于stream流遍历一下,拿到里面的每一个元素
        writerList.stream().forEach(writer -> {
            String gender = writer.getGender();
            if("1".equals(gender)){
                writer.setGender("男");
            }else if("2".equals(gender)){
                writer.setGender("女");
            }
        });
        //3.响应数据(统一结果)
        return Result.success(writerList);
        //传递了响应回去的数据经过@Responsebody注解处理就会转换成json响应到客户端
    }
}

在浏览器中输入/writer.html运行:

2)按照MVC的分层方式实现,常规java代码方式

创建两个包,Dao和Service;

在包下分别创建两个接口WriterDao和WriterService,编写抽象方法listWriter():

package com.example.writeremp.Dao;

import com.example.writeremp.Pojo.Writer;
import java.util.List;

public interface WriterDao {
    public List<Writer> listWriter();
}
package com.example.writeremp.Service;

import java.util.List;
import com.example.writeremp.Pojo.Writer;

public interface WriterService {
    public List<Writer> listWriter();
}

在Dao和Service包下分别再创建包impl,创建WriterDaoA和WriterServiceA实现类,并实现接口,重写接口中的抽象方法listWriter()来分别处理数据和逻辑(WriterServiceA中要先创建Dao对象,并使用对象的listWriter()方法接收dao处理后的数据):

package com.example.writeremp.Dao.impl;

import com.example.writeremp.Dao.WriterDao;
import com.example.writeremp.Pojo.Writer;
import com.example.writeremp.Utils.XmlParserUtils;
import java.util.List;

public class WriterDaoA implements WriterDao {
    @Override
    public List<Writer> listWriter() {

        //数据层,处理数据
        String file = this.getClass().getClassLoader().getResource("writer.xml").getFile();
        System.out.println(file);
        List<Writer> writerList = XmlParserUtils.parse(file, Writer.class);
        return writerList;
    }
}
package com.example.writeremp.Service.impl;

import com.example.writeremp.Dao.WriterDao;
import com.example.writeremp.Dao.impl.WriterDaoA;
import com.example.writeremp.Pojo.Writer;
import com.example.writeremp.Service.WriterService;

import java.util.List;

public class WriterServiceA implements WriterService {
    //创建Dao对象
    private WriterDao writerDao = new WriterDaoA();
    @Override
    public List<Writer> listWriter() {
        //逻辑层,处理数据的逻辑
        List<Writer> writerList = writerDao.listWriter();
        writerList.stream().forEach(writer -> {
            String gender = writer.getGender();
            if("1".equals(gender)){
                writer.setGender("男");
            }else if("2".equals(gender)){
                writer.setGender("女");
            }
        });

        return writerList;
    }
}

最后在WriterController中修改代码:

package com.example.writeremp.Controller;

import com.example.writeremp.Pojo.Result;
import com.example.writeremp.Pojo.Writer;
import com.example.writeremp.Service.impl.WriterServiceA;
import com.example.writeremp.Utils.XmlParserUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class WriterController {
    //创建service对象
    private WriterServiceA writerServiceA = new WriterServiceA();

    @RequestMapping("/listWriter")
    public Result list(){
/*        String file = this.getClass().getClassLoader().getResource("writer.xml").getFile();
        System.out.println(file);
        //1.引用工具类当中的一个方法parse方法解析xml文件,file代表要解析哪一份文件,targetClass表示解析的xml文件要往哪个对象里去封装
        List<Writer> writerList = XmlParserUtils.parse(file, Writer.class);

        //2.对数据进行转换处理gender job
        //基于stream流遍历一下,拿到里面的每一个元素
        writerList.stream().forEach(writer -> {
            String gender = writer.getGender();
            if("1".equals(gender)){
                writer.setGender("男");
            }else if("2".equals(gender)){
                writer.setGender("女");
            }
        });*/

        //响应数据(统一结果)
        List<Writer> writerList = writerServiceA.listWriter();
        return Result.success(writerList);
    }
}

实现:

3)采用控制反转和依赖注入的MVC方式实现。

首先在WriterDaoA中添加注解@Component表示将当前类交给IOC容器管理,成为IOC容器中的bean。

package com.example.writeremp.Dao.impl;

import com.example.writeremp.Dao.WriterDao;
import com.example.writeremp.Pojo.Writer;
import com.example.writeremp.Utils.XmlParserUtils;
import org.springframework.stereotype.Component;

import java.util.List;

@Component//将当前类交给IOC容器管理,成为IOC容器中的bean
public class WriterDaoA implements WriterDao {
    @Override
    public List<Writer> listWriter() {

        //数据层,处理数据
        String file = this.getClass().getClassLoader().getResource("writer.xml").getFile();
        System.out.println(file);
        List<Writer> writerList = XmlParserUtils.parse(file, Writer.class);
        return writerList;
    }
}

在WriterServiceA中添加@Component将当前类交给IOC容器管理同时,使用注解@Autowired读取IOC容器中的bean对象,并赋值给该变量,即依赖注入。

package com.example.writeremp.Service.impl;

import com.example.writeremp.Dao.WriterDao;
import com.example.writeremp.Dao.impl.WriterDaoA;
import com.example.writeremp.Pojo.Writer;
import com.example.writeremp.Service.WriterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class WriterServiceA implements WriterService {
    //使用注解@Autowired读取IOC容器中的对象WriterDao
    @Autowired
    private WriterDao writerDao;
    
    @Override
    public List<Writer> listWriter() {
        //逻辑层,处理数据的逻辑
        List<Writer> writerList = writerDao.listWriter();
        writerList.stream().forEach(writer -> {
            String gender = writer.getGender();
            if("1".equals(gender)){
                writer.setGender("男");
            }else if("2".equals(gender)){
                writer.setGender("女");
            }
        });

        return writerList;
    }
}

最后在WriterController中也使用注解@Autowired读取IOC容器中的bean对象WriterService。

package com.example.writeremp.Controller;

import com.example.writeremp.Pojo.Result;
import com.example.writeremp.Pojo.Writer;
import com.example.writeremp.Service.WriterService;
import com.example.writeremp.Service.impl.WriterServiceA;
import com.example.writeremp.Utils.XmlParserUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class WriterController {
    //使用注解@Autowired读取IOC容器中的对象WriterService
    @Autowired
    private WriterService writerService;

    @RequestMapping("/listWriter")
    public Result list(){
/*        String file = this.getClass().getClassLoader().getResource("writer.xml").getFile();
        System.out.println(file);
        //1.引用工具类当中的一个方法parse方法解析xml文件,file代表要解析哪一份文件,targetClass表示解析的xml文件要往哪个对象里去封装
        List<Writer> writerList = XmlParserUtils.parse(file, Writer.class);

        //2.对数据进行转换处理gender job
        //基于stream流遍历一下,拿到里面的每一个元素
        writerList.stream().forEach(writer -> {
            String gender = writer.getGender();
            if("1".equals(gender)){
                writer.setGender("男");
            }else if("2".equals(gender)){
                writer.setGender("女");
            }
        });*/

        //响应数据(统一结果)
        List<Writer> writerList = writerService.listWriter();
        return Result.success(writerList);
    }
}

实现:

或者将WriterDaoA中的@Component注解改为@Repository,把WriterServiceA中的@Component注解改为@Service,WriterController中不必添加。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值