一个系统业务量很小的时候所有的代码都放在一个项目中就好了,然后这个项目部署在一台服务器上,整个项目所有的服务都由这台服务器提供。
缺点:
- 服务性能存在瓶颈
- 代码量庞大,系统臃肿,牵一发动全身
- 单点故障问题
单机处理到达瓶颈的时候,你就把单机复制几份,这样就构成了一个集群。
集群存在的问题:
当你的业务发展到一定程度的时候,你会发现一个问题无论怎么增加节点,貌似整个集群性能的提升效果并不明显了。这时候,你就需要使用分布式架构了。
分布式架构就是将一个完整的系统,按照业务功能,拆分成一个个独立的子系统,在分布式结构中,每个子系统就被称为“服务”。这些子系统能够独立运行在web容器中,它们之间通过RPC方式通信。
分布式的优势:
- 系统之间的耦合度大大降低,可以独立开发、独立部署、独立测试,系统与系统之间的边界非常明确,排错也变得相当容易,开发效率大大提升。
- 系统之间的耦合度降低,从而系统更易于扩展。我们可以针对性地扩展某些服务。
- 服务的复用性更高。比如,当我们将用户系统作为单独的服务后,该公司所有的产品都可以使用该系统作为用户系统,无需重复开发。
总结:
将一套系统拆分成不同子系统部署在不同服务器上(这叫分布式),然后部署多个相同的子系统在不同的服务器上(这叫集群)。
集群:多个人在一起作同样的事 。
分布式 :多个人在一起作不同的事 。
RPC(Remote Procedure Call)远程过程调用,它是一种通过网络从远程计算机程序上请求服务。RPC是一种技术思想而非一种规范或协议。
大白话理解就是:RPC让你用别人家的东西就像自己家的一样。
Apache Dubbo是一款高性能、轻量级的开源服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
注意:
Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可。
协议是两个网络实体进行通信的基础,数据在网络上从一个实体传输到另一个实体,以字节流的形式传递到对端。在这个字节流的世界里,如果没有协议,就无法将这个一维的字节流重塑成为二维或者多维的数据结构以及领域对象。
推荐:
使用Dubbo协议。
在Dubbo微服务体系中,注册中心是其核心组件之一。Dubbo通过注册中心实现了分布式环境中各服务之间的注册与发现,是各个分布式节点之间的纽带。
其主要作用如下:
- 动态加入:一个服务提供者通过注册中心可以动态地把自己暴露给其他消费者,无须消费者逐个去更新配置文件。
- 动态发现:一个消费者可以动态地感知新的配置、路由规则和新的服务提供者,无须重启服务使之生效。
- 动态调整:注册中心支持参数的动态调整,新参数自动更新到所有相关服务节点。
- 统一配置:避免了本地配置导致每个服务的配置不一致问题。
常见的注册中心有zookeeper 、eureka、consul、etcd。
服务的提供方
调用远程服务的服务消费方,包租婆就是生产者,中介就是注册中心,租客就是消费者。
主要负责监控统计调用次数和调用时间等。
docker pull zookeeper:3.5.9
docker run --name zk -d -p 2181:2181 zookeeper:3.5.9
参数:
- --name zk:镜像名称zk
- -d:守护进程运行
- -p:映射端口号
docker exec -it zk /bin/bash
参数:
- exec:在运行的容器中执行命令
- -it:交互式
Dubbo-admin管理平台,图形化的服务管理页面,安装时需要指定注册中心地址,即可从注册中心中获取到所有的提供者/消费者进行配置管理。
docker pull docker.io/apache/dubbo-admin
docker run -d \
--name dubbo-admin \
-p 9600:8080 \
-e admin.registry.address=zookeeper://192.168.66.100:2181 \
-e admin.config-center=zookeeper://192.168.66.100:2181 \
-e admin.metadata-report.address=zookeeper://192.168.66.100:2181 \
--restart=always \
docker.io/apache/dubbo-admin
参数:
- --restart:always 容器退出时总是重启
- admin.registry.address:注册中心
- admin.config-center:配置中心
- admin.metadata-report.address:元数据中心
浏览器输入http://192.168.66.100:9600,用户名root 密码 root
需要注意的是需要将docker下的zookeeper和dubbo-admin服务都开启。
订单服务
功能如下:
- 创建订单
- 根据用户id查询订单详情
用户服务
- 创建订单
- 根据用户id查询订单详情
通过创建多模块项目实现不同的模块。
jdk-1.8
true
1.8
1.8
1.8
1.8
maven默认的jdk是1.5版本
pom
只需要将项目的打包方式设置为pom即可。此时父项目的src可删除。
File->Settings->Editor->File Encodings
File->Editor->File Types->Ignore Files and Folders
*.md;*.gitignore;.mvn;.idea;
alimaven
aliyun maven
http://maven.aliyun.com/nexus/content/groups/public/
true
false
com.zj
Dubbo-demo
1.0-SNAPSHOT
修改子模块的父项目。
加入下面配置
org.springframework.boot
spring-boot-starter-parent
2.7.0
在pom.xml文件中加入
dubbo-producer
io.dubbo.springboot
spring-boot-starter-dubbo
1.0.0
com.101tec
zkclient
0.7
org.projectlombok
lombok
package com.zj.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 订单模型
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order implements Serializable {
// 订单id
private Long id;
// 用户id
private Long userId;
// 订单总价格
private Double prict;
// 收货人手机号
private String mobile;
// 收货人地址
private String address;
// 支付类型 1:微信 2:支付宝
private Integer pay_method;
}
网络中对象的传递是字节流因此需要实现序列化接口。
package com.zj.service;
import com.zj.pojo.CommonResult;
import com.zj.pojo.Order;
public interface IOrderService {
//创建订单
CommonResult createOrders(Order order);
//根据用户id查询订单详情
CommonResult findByUserId(Long userId);
}
/**
* 统一返回结果集
* @param
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult implements Serializable {
// 返回结果编码
private Integer code;
// 返回结果描述
private String message;
// 数据
private T data;
private CommonResult(Integer code,String message){
this(code,message,null);
}
}
package com.zj.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.zj.pojo.CommonResult;
import com.zj.pojo.Order;
@Service
public class OrderServiceImpl implements IOrderService {
/**
* 创建订单
* @param order
*/
@Override
public CommonResult createOrders(Order order) {
//TODO 模拟数据库操作
CommonResult result = new CommonResult();
result.setCode(200);
result.setMessage("订单创建成功!");
result.setData(null);
return result;
}
/**
* 根据用户id查询订单
* @param userId
* @return
*/
@Override
public CommonResult findByUserId(Long userId) {
//TODO 模拟数据库操作
CommonResult commonResult = new CommonResult();
// 返回结果编码
commonResult.setCode(200);
// 返回结果描述信息
commonResult.setMessage("查询成功");
// 返回结果集
Order order = new Order();
order.setId(1L);
order.setUserId(1L);
order.setPrict(121.1);
order.setMobile("18588888888");
order.setAddress("北京市海淀区中关村");
order.setPay_method(1);
commonResult.setData(order);
return commonResult;
}
}
注意:
@Service注解的作用:将这个类提供的方法对外发布,将访问该方法的地址IP,端口路径注册到注册中心zookeeper
该注解不是spring的注解而是dubbo的注解:
com.alibaba.dubbo.config.annotation.Service;
#配置项目名称
spring.dubbo.application.name = order-producer
#配置注册中心(告诉项目注册中心在哪)
spring.dubbo.registry.address=zookeeper://192.168.66.100
spring.dubbo.registry.port=2181
#指定Dubbo使用的协议和端口号
spring.dubbo.protocol.name=dubbo
spring.dubbo.protocol.port=20880
#指定注册到zookeeper上的超时时间
spring.dubbo.registry.timeout=10000
#配置Dubbo包扫描
spring.dubbo.scan=com.zj.service
com.zj
dubbo-demo
1.0-SNAPSHOT
dubbo-producer
dubbo-consumer
org.springframework.boot
spring-boot-starter-web
io.dubbo.springboot
spring-boot-starter-dubbo
1.0.0
com.101tec
zkclient
0.7
org.projectlombok
lombok
>
因为消费者需要调用生产者的接口.
/**
* 用户模型
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
//用户id
private Long id;
// 用户名字
private String name;
}
/**
* 用户接口
*/
public interface IUserService {
//根据用户id查询订单详情
CommonResult findByUserId(Long id);
}
package com.zj.service;
import com.alibaba.dubbo.config.annotation.Reference;
import com.zj.pojo.CommonResult;
import com.zj.pojo.Order;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements IUserService {
//引入订单服务(远程调用)
@Reference //从zookeeper注册中心获取访问IOrderService的url,通过rpc协议远程调用,将结果封装为代理对象赋给变量
private IOrderService iOrderService;
/**
* 根据用户id查询订单
* @param id 用户id
* @return
*/
@Override
public CommonResult findByUserId(Long id) {
return iOrderService.findByUserId(id);
}
}
这里的service注解是spring注解因为需要controller调用service层.
package com.zj.controller;
import com.zj.pojo.CommonResult;
import com.zj.pojo.Order;
import com.zj.service.IUserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 用户控制层
*/
@RestController
public class UserController {
@Resource
private IUserService iUserService;
/**
* 根据用户ID查询用户订单详情
* @param userId 用户id
* @return
*/
@GetMapping("findByUserId")
public CommonResult findByUserId(Long userId){
return iUserService.findByUserId(userId);
}
}
#配置项目名称
spring.dubbo.application.name = order-consumer
#配置注册中心(告诉项目注册中心在哪)
spring.dubbo.registry.address=zookeeper://192.168.66.100
spring.dubbo.registry.port=2181
#指定Dubbo使用的协议和端口号
spring.dubbo.protocol.name=dubbo
spring.dubbo.protocol.port=20881
#指定注册到zookeeper上的超时时间
spring.dubbo.registry.timeout=10000
#配置Dubbo包扫描
spring.dubbo.scan=com.zj.service
#端口
server.port=8081
在.idea/workspace.xml 文件中添加
网络传输的数据必须是二进制数据,但调用方请求的出入参数都是对象。
总结:
序列化就是将对象转换成二进制数据的过程,而反序列就是反过来将二进制转换为对象的过程。
流程:
不妨借用个例子帮助你理解,比如发快递,我们要发一个需要自行组装的物件。发件人发之前,会把物件拆开装箱,这就好比序列化;这时候快递员来了,不能磕碰呀,那就要打包,这就好比将序列化后的数据进行编码,封装成一个固定格式的协议;过了两天,收件人收到包裹了,就会拆箱将物件拼接好,这就好比是协议解码和反序列化。
(面试)注册中心挂了,服务是否可以正常访问?
答案:
可以.因为dubbo服务消费者在
第一次调用时
,会将服务提供方地址缓存到本地
,以后在调用则不会访问注册中心。服务提供者地址发生变化时,注册中心会通服务消费者。
问题:
- 服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一直等待下去。
- 在某个峰值时刻,大呈的请求都在同时请求服务消费者,会造成线程的大呈堆积,势必会造成雪崩。
- dubbo利用超时机制来解决这个问题,设置一个超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
使用timeout属性配置超时时间,默认值1000,单位毫秒。
@Service(timeout = 3000) //当前服务3秒超时
public class OrderServiceImpl implements IOrderService {}
@Reference(timeout = 2000)// 远程注入
private IOrderService iOrderService;
超时问题:
如果出现网络抖动,则会出现请求失败。
Dubbo提供重试机制来避免类似问题的发生。
@Service(timeout = 3000,retries = 2)
注意:
Dubbo在调用服务不成功时,默认会重试2次。
Dubbo提供多版本的配置,方便我们做服务的灰度发布,或者是解决不兼容的问题。
当出现新功能时,会让一部分用户先使用新功能,用户反馈没问题时,再将所有用户迁移到新功能。就是王者的体验服!!
@Service(version = "1.0.0")
@Service(version = "2.0.0")
@Reference(version = "2.0.0")
private IOrderService iOrderService;// 订单服务
@Reference(version = "*")
private IOrderService iOrderService;// 订单服务
Dubbo是一个分布式服务框架,能避免单点故障和支持服务的横向扩容。一个服务通常会部署多个实例。
问题:
如果服务B的请求量很大导致服务器宕机,则订单服务生产者会出现单点故障。如何从多个服务 Provider 组成的集群中挑选出一个进行调用,就涉及到一个负载均衡的策略。
如果增加服务,搭建服务的集群的话,消费者E到底调用的是哪一个服务器的服务呢?Dubbo为解决该问题提供了一个方案,也就是负载均衡.
@Service(timeout = 3000,retries = 3,loadbalance = "roundrobin")
@Reference(timeout = 2000,loadbalance = "roundrobin")
private IOrderService iOrderService;
参数:
- random:随机负载均衡
- leastactive:最少活跃调用数,相同活跃数的随机
- roundrobin:轮询负载均衡
- consistenthash:一致性哈希负载均衡
Dubbo框架为服务集群容错提供了一系列好的解决方案,在此称为dubbo服务集群容错模式。
在消费者服务配置
@Reference(cluster = "failover")
private IOrderService iOrderService;
服务降级,当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,关闭除了核心业务之外的服务以此释放服务器资源以保证核心任务的正常运行。
两种场景:
- 当下游的服务因为某种原因响应过慢,下游服务主动停掉一些不太重要的业务,释放出服务器资源,增加响应速度!
- 当下游的服务因为某种原因不可用,上游主动调用本地的一些降级逻辑,避免卡顿,迅速返回给用户!
当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。
@Reference(timeout = 2000,mock = "force:return null")
private IOrderService iOrderService;
含义:
表示消费方对该服务的方法调用都直接返回null值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
第二种 :mock = "mock=fail:return null"
@Reference(timeout = 2000,mock = "mock=fail:return null")
private IOrderService iOrderService;
含义:
表示消费方对该服务的方法调用在失败后,再返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
春运,一项全人类历史上最大规模的迁移活动,抢火车票一直是每年跨年以后的热点话题。例如,通过一系列复杂的验证手段来实现用户的限流。
原理:
漏桶算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。
原理:
令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。
漏桶的天然特性决定了它不会发生突发流量,就算每秒1000个请求到来,那么它对后台服务输出的访问速率永远恒定。而令牌桶则不同,其特性可以“预存”一定量的令牌,因此在应对突发流量的时候可以在短时间消耗所有令牌,其突发流量处理效率会比漏桶高,但是导向后台系统的压力也会相应增多。
为了防止某个消费者的QPS或是所有消费者的QPS总和突然飙升而导致的重要服务的失效,系统可以对访问流量进行控制,这种对集群的保护措施称为服务限流。
服务生产者添加如下注解
@Service(executes = 10)
注意:
服务端并发执行(或占用线程池线程数)不能超过10个
@Service(actives= 10)
注意:
占用连接的请求的数不能超过10个。
结果缓存,用于加速热门数据的访问速度,Dubbo提供声明式缓 存,以减少用户加缓存的工作量。
Dubbo提供了三种结果缓存机制:
@Reference(cache="lru")
完成用户表的CRUD操作。
本项目采用maven分模块开发方式,即对整个项目拆分为几个maven工程,每个maven工程存放特定的一类代码。
解释:
- user_api:公共接口
- user_consumer:服务消费者
- user_provider:服务生产者
了解分布式项目的构建方式。
修改pom文件,因为是父项目,所有将项目的打包类型设置为pom
pom
4.0.0
com.zj
dubbo_parent
1.0-SNAPSHOT
user_api
user_provider
pom
2.7.6
2.7.6
3.5.0
5.1.49
org.apache.dubbo
dubbo-spring-boot-starter
2.7.6
org.apache.dubbo
dubbo-registry-zookeeper
2.7.6
com.baomidou
mybatis-plus-boot-starter
${mybatisplus.spring.starter.version}
mysql
mysql-connector-java
${mysql.connector.version}
org.projectlombok
lombok
1.18.22
org.apache.maven.plugins
maven-compiler-plugin
3.1
1.8
该工程存放的是公共的接口
设置依赖,在父项目中已经指定了版本因此不需要再子项目设置版本啦。
dubbo_parent
com.zj
1.0-SNAPSHOT
4.0.0
user_api
org.apache.dubbo
dubbo-spring-boot-starter
org.apache.dubbo
dubbo-registry-zookeeper
父项目指定子项目
user_api
引入dubbo_parent父工程
com.zj
dubbo_parent
1.0-SNAPSHOT
pom
因为在该项目中默认的父工程是:spring-boot-starter-parent,但是项目还有一个父工程是dubbo_parent,当一个项目出现两个以及以上的父项目的时候使用dependencyManagement标签引入其他父项目。
因为该项目是个逻辑工程因此也需要i指定项目的打包方式为pom,并删除src
pom
#创建并启动数据库MySQL
docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
参数:
-d:后台运行
--name:数据库名称
-p :端口映射
-e : 设置数据库密码
#如果数据库已经在之前创建好了,只需要启动数据库即可。
ocker start 43(容器ID)
#通过命令行操作mysql
docker exec -it mysql /bin/bash
#登录到mysql容器
mysql -uroot -p123456
create database test;
#选择test数据库
use test;
#创建用户表
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
PRIMARY KEY (id)
);
#查看全部表
show tabloes;
注意分号
pojo项目引入lombok依赖
com.zj
pojo
1.0-SNAPSHOT
package com.zj.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
// 用户id
private Long id;
// 用户名字
private String name;
// 用户年纪
private Integer age;
}
mapper工程引入pojo工程
com.zj
pojo
1.0-SNAPSHOT
com.baomidou
mybatis-plus-boot-starter
mysql
mysql-connector-java
在父工程中定义过版本了。
package com.zj;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zj.pojo.User;
/*持久层*/
public interface UserMapper extends BaseMapper {
}
在provider项目引入mapper项目
com.zj
mapper
1.0-SNAPSHOT
该项目依赖两个父项目,分别是user_provider和springboot
org.springframework.boot
spring-boot-starter-parent
2.7.0
user_provider
com.zj
1.0-SNAPSHOT
pom
import
在该项目中引入springboot核心依赖
org.springframework.boot
spring-boot-starter
在该项目中创建启动类providerApplication,添加 @MapperScan
注解,扫描 Mapper 文件夹
package com.zj;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.zj.mapper")
public class providerApplication {
public static void main(String[] args) {
SpringApplication.run(providerApplication.class);
}
}
创建配置文件application.properties并配置数据源
################ 配置MySQL数据源 ##############
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.66.100:3306/test?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
com.zj
pojo
1.0-SNAPSHOT
package com.zj.api;
import com.zj.pojo.User;
public interface addUserService {
int addUser(User user);
}
com.zj
user_api
1.0-SNAPSHOT
package com.zj.service;
import com.zj.mapper.UserMapper;
import com.zj.api.AddUserService;
import com.zj.pojo.User;
import org.apache.dubbo.config.annotation.Service;
import javax.annotation.Resource;
/*将服务信息注册到zookeeper*/
@Service(timeout = 50000)
public class AddUserServiceImpl implements AddUserService {
@Resource
private UserMapper userMapper;
@Override
public int addUser(User user) {
return userMapper.insert(user);
}
}
################ Dubbo 配置 ####################
#服务的名称
dubbo.application.name=Provider
# 注册中心地址(单机)
dubbo.registry.address=zookeeper://192.168.66.100:2181
# 注册中心地址(集群)
#dubbo.registry.address=zookeeper://192.168.233.130:2181?backup=192.168.233.130:2182,192.168.233.130:2183
dubbo.registry.timeout=50000
#协议
dubbo.protocol.name=dubbo
#dubbo服务端口
dubbo.protocol.port=20880
#包扫描
dubbo.scan.base-packages=com.zj.provider.service
启动provider项目打开即可。
package com.zj.api;
import com.zj.pojo.User;
import java.util.List;
public interface FindUserService {
List findAll();
}
package com.zj.service;
import com.zj.api.FindUserService;
import com.zj.mapper.UserMapper;
import com.zj.pojo.User;
import org.apache.dubbo.config.annotation.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class FindUserServiceImpl implements FindUserService {
@Resource
private UserMapper userMapper;
@Override
public List findAll() {
return userMapper.selectList(null);
}
}
启动项目,查看dubbo控制台。
package com.zj.api;
import com.zj.pojo.User;
public interface UpdateUserService {
/*先查*/
User preUpdateUser(Integer userId);
/*再更新*/
void updateUser(User user);
}
package com.zj.service;
import com.zj.api.UpdateUserService;
import com.zj.mapper.UserMapper;
import com.zj.pojo.User;
import org.apache.dubbo.config.annotation.Service;
import javax.annotation.Resource;
@Service
public class UpdateUserServiceImpl implements UpdateUserService {
@Resource
private UserMapper userMapper;
@Override
public User preUpdateUser(Integer userId) {
return userMapper.selectById(userId);
}
@Override
public void updateUser(User user) {
userMapper.updateById(user);
}
}
启动项目。
package com.zj.api;
public interface DeleteUserService {
int deleteUser(Long userId);
}
package com.zj.service;
import com.zj.api.DeleteUserService;
import com.zj.mapper.UserMapper;
import org.apache.dubbo.config.annotation.Service;
import javax.annotation.Resource;
@Service
public class DeleteUserServiceImpl implements DeleteUserService {
@Resource
private UserMapper userMapper;
@Override
public int deleteUser(Long userId) {
return userMapper.deleteById(userId);
}
}
启动项目。
org.springframework.boot
spring-boot-starter-thymeleaf
spring-boot很多配置都有默认配置,比如默认页面映射路径为
classpath:/templates/*.html
同样静态文件路径为
classpath:/static/
在application.properties(或者application.yml)中可以配置thymeleaf模板解析器属性.就像使用springMVC的JSP解析器配置一样。
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
#开发时关闭缓存,不然没法看到实时页面
spring.thymeleaf.cache=false
首页
添加用户
查询用户
package com.zj.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class PageController {
/**
* 完成页面跳转
*/
@GetMapping("/{page}")
public String showPage(@PathVariable String page){
return page;
}
/*忽略图标*/
@GetMapping("/favicon.ico")
@ResponseBody
public String favicon(){
return " ";
}
}
启动user_cnsumer项目。
################ Dubbo 配置 ####################
#服务的名称
dubbo.application.name=Consumer
# 注册中心地址(单机)
dubbo.registry.address=zookeeper://192.168.66.100:2181
# 注册中心地址(集群)
#dubbo.registry.address=zookeeper://192.168.233.130:2181?backup=192.168.233.130:2182,192.168.233.130:2183
dubbo.registry.timeout=50000
#协议
dubbo.protocol.name=dubbo
#dubbo服务端口
dubbo.protocol.port=20881
#包扫描
dubbo.scan.base-packages=com.zj.service
添加用户
com.zj
user_api
1.0-SNAPSHOT
package com.zj.service;
import com.zj.pojo.User;
public interface UserService {
void addUser(User user);
}
package com.zj.service.Impl;
import com.alibaba.dubbo.config.annotation.Reference;
import com.zj.api.AddUserService;
import com.zj.pojo.User;
import com.zj.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
//远程调用生产者接口
@Reference
private AddUserService addUserService;
@Override
public void addUser(User user) {
addUserService.addUser(user);
}
}
package com.zj.controller;
import com.zj.pojo.User;
import com.zj.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
/**
* 处理用户操作控制器
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
/**
* 处理添加用户请求
*/
@RequestMapping("/addUser")
public String addUser(User user){
this.userService.addUser(user);
return "redirect:/ok";
}
}
运行项目即可。
查看数据库是否存在该数据。
查看、修改、删除和添加同理不再赘述。