SpringWeb请求与响应

本文介绍了SpringBoot中HTTP请求与响应的工作原理,包括Controller、Service、Dao的角色,以及B/S和C/S架构的区别。重点讲解了如何使用ApiPost进行接口测试和ControllerServiceDao的解耦,通过Spring的依赖注入(DI)和控制反转(IoC)实现代码的组织和管理。
摘要由CSDN通过智能技术生成

请求与响应

        上一章我们做了一个简单的程序,当我们在浏览器的地址栏中输入一个访问路径,就能访问我们部署在tomcat中的应用程序,后端接收到请求后,进行处理,再把处理完毕的结果传回给浏览器,浏览器响应对应的结果。

        而浏览器在和数据库唧唧我我的时候,是基于HTTP协议的。 这个HTTP协议就规定了两个人唧唧我我的规范,或者说规则。

        上一章我们写的controller程序,tomcat其实是不认的,这个程序他没有实现接口,也没有继承类。 但是有解决办法的。他不认我们写的controller即这样的:

@RestController
public class JoneyController{
    @RequestMapping("/joney");
    public String hiJoney(String name){
        sout(name);
        return "hi";
    }
}

        解决办法:他认的是Java的规范技术,即servlet,也叫servlet容器。

        springboot的底层给我们提供了一个核心的程序,即DispatcherServlet。DispatcherServlet有一个复杂的集成体系。 servlet就是继承与他。

        由浏览器发起的请求都会先到DispatcherServlet的手上过一遍,再从他开始,分到下面的子类。

        在springboot中,我们成DispatcherServlet为核心控制器或者前端控制器。

下面介绍一下响应和请求对象:

        请求对象:HttpServletRequest

        响应对象:HttpServletResponse

        其作用就和他们的名字一样。

网络架构

原谅我如此突兀给个名词大家,这个仅当做了解。

B/S架构和 C/S架构

BS架构就是浏览器,客户端架构,应用程序所有逻辑和数据存在服务器中,用户只需要浏览器就能获取服务。

CS架构就是用户要安装一个应用才能获取服务。即要下载客户端。

ApiPost

        前面说了,我们主流开发都是前后端分开进行开发的。而我们开发的后端要测试一下接口行不行得通,到时候给前端对接时能不能顺利发送数据过去,该怎么办? 我们的前端还在开发,我们前后端期望的是,像建设桥梁一般,从河岸的两端同时建设,最后在河的中间进行没有差错的拼接。

        这时候就要用到后端的接口测试工具了,我这里使用的是ApiPost。大家在官网下载最新版本就好了,他的操作是比较简单的。下面我带大家简单的走一遍使用流程。

1.

先建立一个controller包,放下我们的RequestController,里面写上如图所示的代码。

解释一下部分代码的含义:

@RequestMapping 指定controller的访问路径 

开启运行springboot后,去到Apipost操作。

返回数据Ok。

控制台返回前端发过来的数据。

不单单是传两个参数,他还能传对象,时间,json格式的数据

还有一个比较特殊的,路径参数。

这个参数刚好是controller映射的路径的一部分,就叫做路径参数。

这个路径是动态更新的,浏览器传什么参数过来,我们就给他跳到哪个controller。

所以跟别的参数有点不同。

Controller Service Dao 解耦

        目前为止,我们所有的代码都写在了controller方法中。当然,我们的代码逻辑都是简单的。

        但是如果我们要开发一个比较复杂的功能,那就会出现很多问题,举个例子。

如图所示这部分代码,他能从网页中获取请求,来到list()方法中进行处理。

首先去Resource目录下拿了emp.xml文件。 存入empList列表中。

然后对列表中的数据进行处理进行,详细地,我们能看到,对数据中的gender进行判断,如果是1则给对象的性别属性赋值为男,为2则赋值为女。

最后把数据返回给浏览器。

这三步操作在这时候是比较清晰的。那现在我们可能就会问了。

就算业务再复杂,不也就取数据,做处理,返回数据吗?

这会出现几个问题。

  1. 代码复用型差
  2. 拓展性差

我们到公司中去工作。公司追求的是高效率。前面的代码中,每次都要去取数据,以及最后的数据返回,非常明显都是每次操作都要的。如果我们能把两个操作做到通用化,即每次用到,我们只要调用一个函数就完事了,这就能增加工作效率。现实是,我们已经这么做了。

再者,在后面如果需要增加功能,在原来杂糅的代码基础上进行修改,需要先看懂这部分的代码,才能进行修改,不知道大家有没有改过自己面向过程的代码? 改起来真是久久难以平息……

所以就有了把这些东西分开做的想法,这就叫做分层。

分层解耦

        分层,就是把web程序分为三层。分别是Controller控制层、service逻辑业务层、Dao数据访问层。

controller控制层 就是我们接收浏览器的请求,和最后的return 处理好的响应数据。

Dao数据访问层  谁来要数据,就给他想要的数据。

service逻辑处理层 这一层需要拿到数据才能做逻辑处理嘛,所以要先去到Dao层拿数据,数据return给service层,进行完毕逻辑处理,就返回给controller。

分层之后就是解耦。

解释之前要先知道两个概念,一个是內聚,一个是耦合。

內聚:是针对同一层的某一个对象的。 比如service层的empService,就只进行emp的逻辑操作,而dept的操作放到deptService中去。这就叫做类的內聚程度比较高。

耦合:是用来衡量各个层或者各个模块之间的依赖关联程度的。依赖程度越高,耦合越高。

比如,service层要调用dao才能获取数据进行逻辑处理吧?不然可要巧妇难为无米之炊了。

那controller层要调用service层才能获得逻辑处理完的数据进行返回给浏览器把?这两个例子就是各层之间的耦合情况。

我们软件设计,怎么样才能说一个软件设计得好呢? 就是要高內聚,低耦合。就是要尽量自给自足地搞内循环为主体,外循环为辅的政策,防止别人卡脖子。


好了。现在我们层与层之间就是有耦合,有什么办法呢?

遇到问题 记得拨打金牌导师 JonyB的电话。

下面将教给大家。

        代码这里,如果我的Service要增加点功能,我把EmpServiceB的代码复制一份,写一个EmpServiceD的Service层,那么在这里,我是不是也要该这个controller层啊?   这就是耦合的存在。 那怎么该才能做到: 我改了Service层的东西,其他东西也不用动呢?

可能会有人这么改: 我删掉粉红色的部分,让他只要是EmpService的子类就给我用。

可以吗?

当然是不行的,首先遇到的问题就是报错,因为使用了empService对象而不给他赋值,他指向的就是空指针。

下面是官方的解决思路

首先,我准备一个容器,你不是说你有好几个EmpService的子类吗?我都把他们的实例对象放到这个容器中去。

当controller需要用到EmpService的对象时,去这个罐子里面找,找到就赋值给在controller声明的对象empService,就可以使用了。

这样做的好处是,可以不用管EmpService的子类具体哪个能用。你给我什么我就用什么。


大家发现了吗? 这样的话,我们就要多管理一个东西了,就是这个罐子(上面说的容器),一个EmpService的子类都放进去是可以的,但是取的时候我该给哪个?  

这时候有两个思路,要么在EmpService的子类中表明,EmpService的儿子里面只能放一个,要么就是放了一堆子类对象进去,只让一个能用。

当然,官方认为的难点跟我认为的难点有不小的差距……毕竟人家才是真正要做实现的那群人。

官方认为哪些实现是难点呢?

  1. EmpService的子类对象怎么放进去这个容器?
  2. 容器里面的对象怎么给到Controller? 怎么给到它要的那个对象?毕竟罐子里面这么多对象呢,你怎么知道他要的是哪个?

        面对1.他们搞了一个概念,依赖反转(inversion of control)IOC,乍一看莫名其妙,但他的地位不容小(xiao,第三声)觑,是spring框架的第一大核心。

        他的含义是指:对象创建的控制权由应用程序转移到了外部容器。

原来在程序中,我要用什么对象,new就行了。 现在用了IOC,就是把new的权限给了罐子(容器)。解释就是这么短。 反转之前,程序自身控制对象的创建,反转之后,容器控制。

        面对2 又搞了一个概念,叫依赖注入(dependency injection) DI

        他的含义是指:容器为应用程序提供运行时所需要依赖的资源。

比如controller运行时需要依赖EmpService资源,就可以让容器给他这个资源,这个过程就是依赖注入。

        bean对象:就是容器里面的对象。

        在容器的外面,这些对象还归我们管的时候,叫做实例对象。不归我们管之后,由容器来管,叫做Bean对象。看到了吗?其实都是一个东西。只是谁管他们的区别。

        大家会有疑惑,我一直说的容器,或者这个罐子(我容器和罐子混起来说了,只是为了好理解,容器就是罐子,罐子就是容器),应该有个名字吧? 毕竟容器里面的东西都有名字了。没错,当然有名字。这个容器,官方的名字叫做IOC容器。

进行实际的解耦操作

有两个步骤:

①.Service层及Dao层的实现类,交给IOC容器管理。
②.为Controller及Service注入运行时,依赖的对象。
 



①的实现:

        我想把EmpServiceA这个类,他的new对象管理权交给IOC容器管理,该怎么做?

加上@Component   注解。

②的实现:

        我的Controller需要IOC容器提供一个EmpService的对象,该怎么做?

        

在声明变量上面加上@Autowired  注解

更进一步的解释

首先是IOC。

上面说了,我们给IOC容器权限的时候,用的是Component注释,但我们看到别人的项目里面,有时候也不是Compoent注释啊?

这是因为Component注释是IOC容器管理的基本注解,当我们给Service层注解时,可以用@Service,一般也是用的@Service。 当我们给Controller层注解时,一般用的是@Controller。

Dao层用的是@Repository。

这些额外的注解都是Component的衍生注解,就是说他们的实现代码其实是带了@Component的。

如果你的包放在了整个结构的外面,会出问题。这是因为@ComPonentScan找不到你的这个包,具体大家可以去查一下怎么解决。 这里不详细说怎么改的原因是,官方提倡包都放同一个地方,如果放错了,放到对的地方就好了,不必去改这个属性。

最后说一下DI。

        DI是什么大家还记得吗?就是去IOC容器拿取Bean对象的过程。

这个拿取过程上面也提到过。有两种情况,一是一个类的子类放了一堆进容器中,我叫容器给的时候,他只给指定的一个我。二是一个类只放了一个子类,那就是给我那个类咯。

这里的实现也是这样的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值