同学们好!打开《我家租房网》的首页,我们会看到登录注册按钮和搜索栏。事实上在登录注册按钮和搜索栏之间还有一个轮播图组件,以轮播的方式,显示几幅房屋的图片。这节课我们将实现获取轮播的功能。


我们将首先实现支持获取轮播的后端微服务,再在前端服务器中添加路由处理函数并远程调用后端微服务,最后再将前后端连在一起做完整的功能测试。


首先我们来实现后端服务器。


第一步是创建特定的微服务。


创建微服务的过程还是和先前一样,直接在back-end工程目录下执行go-micro命令,子命令为new,参数为service,微服务名为GetIndex。


接着,需要修改一下go-micro为我们自动生成的接口描述。在back-end工程目录下的GetIndex微服务目录中,有一个名为proto的子目录,这就是存放接口描述脚本及其Go代码文件的地方。现阶段里面只有一个名为GetIndex.proto的ProtoBuf脚本文件。我们需要对该文件做一些修改:

这段代码描述的是,前端服务器和后端微服务之间的数据交换格式。CallRequest表示前端提供给后端的请求数据,这里为空。CallResponse表示后端返回给前端的响应数据,其中包含错误代码、错误描述和房屋列表。房屋列表中包含若干套房屋的信息,比如房屋ID、标题、价格、归属地区名、主图片URL、房间数、预定订单数、地址、房主用户头像URL、创建时间等等。


有了用ProtoBuf语言描述的远程调用接口,我们还需要把它编译成基于Go语言的程序代码。在GetIndex微服务目录中执行make命令,并携带四个目标参数,它们是init、proto、update和tidy。


在GetIndex微服务目录下,创建一个名为model的子目录,表示该微服务的模型层。在该子目录中创建mysql.go文件,封装所有与操作MySQL数据库有关的代码。在实际编写数据库访问代码之前,我们可以先把之前为前端服务器编写的mysql.go文件中的内容原封不动地复制到这里:


修改GetIndex微服务目录中的main.go文件,添加对InitDB函数的调用,将服务发现改为Consul,绑定IP地址和端口:

程序启动伊始,即完成对数据库的初始化。其中包括两个动作,其一是连接ihomedb数据库并获得连接池对象,其二是在该数据库中创建表。当然,如果这些表已经存在,则不再创建。接着,在服务器对象的初始化部分,指示其注册到Consul服务器,同时绑定本机的9014端口。


接下来,我们为GetIndex微服务编写与数据持久化有关的代码。


打开GetIndex微服务目录下,model子目录中的mysql.go文件,在其中添加有关从MySQL数据库中读取房源、城区和用户信息的代码:

定义名为ReadHouses的函数,用于从MySQL数据库中读取房源信息。该函数从房屋表中读取如参数给定数量的记录,得到表示房屋表中多条记录的房屋结构体切片。最后将特定数量的房源信息,连同错误对象,返回给函数的调用者。

定义名为ReadArea的函数,用于从MySQL数据库中读取城区信息。该函数以从参数传入的房屋结构体变量为依据,基于房屋表的归属地区ID外键,和城区表的城区ID主键,在房屋表和城区表之间做一对一的关联查询,得到表示城区表中特定记录的城区结构体变量。最后将参数房屋的所在城区信息,连同错误对象,返回给函数的调用者。

定义名为ReadUser的函数,用于从MySQL数据库中读取用户信息。该函数以从参数传入的房屋结构体变量为依据,基于房屋表的房主用户ID外键,和用户表的用户ID主键,在房屋表和用户表之间做一对一的关联查询,得到表示用户表中特定记录的用户结构体变量。最后将参数房屋的房主用户信息,连同错误对象,返回给函数的调用者。


在完成GetIndex微服务模型层的所有开发工作之后,我们将着手编写用于处理获取轮播业务的代码。


打开GetIndex微服务目录下,handler子目录中的GetIndex.go文件,在其中的Call方法里,添加与获取轮播有关的操作:

这里首先调用模型层的ReadHouses函数,读取五套房屋的房源信息。遍历其中的每一套房屋,调用模型层的ReadArea函数,获取该房屋所在的城区,调用模型层的ReadUser函数,获取该房屋的房主用户。根据这些信息,将包含该套房屋ID、标题、价格、归属地区名、拼接了Nginx服务器地址和端口的主图片URL、房间数、预定订单数、地址、拼接了Nginx服务器地址和端口的房主用户头像URL和创建时间等内容的房屋信息,添加到响应对象的房屋列表中。


在完成GetIndex后端服务器的开发后,我们需要为前端服务器添加一条路由,并在路由处理函数中完成对后端微服务远程方法的调用。


前端和后端共用同一套接口描述。


因此,这里我们将GetIndex微服务目录下proto子目录中的所有文件,原封不动地复制到front-end工程目录proto子目录下的GetIndex目录中。


这里我们要为获取轮播添加一条路由,GET方法结合/api/v1.0/house/index路径,处理函数名为GetIndex。


在front-end工程目录下的main.go文件中添加一条路由:

这里我们调用了路由对象的GET方法,为获取轮播添加了一条路由,将GET方法结合/house/index路径,路由到controller包的GetIndex函数。将GetIndex函数定义在controller包里是因为该函数的主要任务是执行业务逻辑,属于MVC中的C,即控制器层的部分。另外,请注意,获取轮播并不需要验证用户是否登录,故将该控制器放在登录验证中间件之前。


当然,在controller包里真的得有GetIndex函数。为此,我们打开front-end工程目录下controller子目录中的house.go文件。在该文件的import部分增加一行,同时定义GetIndex函数:

这段代码首先通过Consul服务发现,获取有关名为getindex的微服务的信息,远程调用其中的GetIndex对象的Call方法。该方法的请求对象为空,返回包含错误代码、错误描述和房屋列表的响应对象。最后将该响应对象序列化为一个JSON字符串,编码到HTTP响应中,回传给浏览器。


当获取城区列表和获取轮播两个控制器方法以非常接近的时间被调用时,获取远程微服务的过程会变得异常缓慢。究其原因可能与Consul的并发实现有关。为此,在前端页面脚本中增加必要的延时处理。


打开front-end工程视图层的index.js文件,为获取城区信息添加延时:

这里为获取城区信息添加了一秒钟的延时。


至此,我们已经完成获取轮播的全部开发工作。下面我们将对这部分功能进行测试。


在虚拟机中启动FastDFS和Nginx。启动Consul服务器、GetAreas、GetIndex后端微服务和前端服务器。用浏览器访问localhost:8080/home,可以看到房屋轮播图已经显示在《我家租房网》的首页中。


谢谢大家,我们下节课再见!