手把手教你如何玩转Dubbo(入门到项目实践)

导读:本篇文章讲解 手把手教你如何玩转Dubbo(入门到项目实践),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

小蜗牛,今天爬了多远?不急,继续爬总会到达终点。
朋友们,今天学习了多久?别慌,保持学习才会看到更好的自己。
觉得我的文章还不错的,欢迎大家还可以关注我的微信公众号:Java菜鸟进阶之路
最近会写一个系列的文章进行推出,值得期待和持续关注哦!

文章目录

情景引入

小白:呜呜,呜呜,呜呜,呜呜
我:谁呀,这么早就闹个不停,好好的周末还让不让人休息了
小白:呜呜,呜呜———-(声音越来越大)
我:不甘心的爬起来,想一看究竟。
小白:你,你,你,怎么就起来了呢?
我:你这么大声,猪都要被你叫醒来了。怎么了,你这是,谁欺负你了吗?
小白:是的,公司老大让我重构公司的系统项目,因为原来业务量不大,用的架构都比较简单,而且还是跑单机模式,但是现在业务量来了,前期埋的坑,现在都暴露出来了,所以,公司让我好好重构下项目。
我:那这不是挺好的吗?可以从大局思考,提升自己的能力的机会来了。
小白:可是,之前公司一个项目就是一个服务,其中存在不同项目重复的写轮子的情况,现在公司要求拆分,而且将基础常用的做成中台,服务与服务之间又要能相互调用。这可怎么办呢?
我:emmm,你的意思是说,现在需要按服务拆分项目,然后服务与服务之间能够互相调用,减少重复代码和代码的冗余以及提升整体架构性能是吗?
小白:对呀,就是,现在不知道服务与服务之间该怎么调用才好。总不能,有一个调用请求就发一个Http请求去调用吧。这效率该多慢。
我:是的,这样的情况就不该采取单一的Http了,不过我可以教你另外的一种方法哦。
小白:你知道其他的方法吗?快告诉我快告诉我。。。(立马不哭)
我:哎,起来都起来了,那就容我教你一个新知识吧。
PS:引文中出现了一个名词:中台。如果不明白的,建议百度一下,这个在公司还是很常见的。

问题引入

分布式架构是现在越来越主流的模式,并且采取的也是服务与服务之间的调用,而将许多常用的服务就可以作为中台,方便多个服务去根据需求自由获得理想的结果。其中服务可以简单的理解为一个功能模块,比如,淘宝其中最为主要的就有订单模块和商品模块。试想,如果采取单一项目架构的方式,将商品模块和订单模块都放一起,如何能撑得住双11的购物狂潮,如果一个模块接口挂了,那么后续将会损失多少金钱,所以,为了增加项目的性能,开始采取前后端分离,服务拆分,分布式部署等等的技术。
我们来分析一个问题:
假设公司存在:A,B两个服务,其中都有权限校验,另外,A还会调用B服务的接口查询某些数据库的信息(A和B的数据库表结构不一样)。那么,你此时会想到如何去处理呢?
提示:将权限校验作为一个C服务,谁需要谁去请求C服务的权限接口即完成权限校验。
我们可以发现,其中关键的在于服务与服务之间的调度,那么如何更好的实现这功能,Dubbo给我们提供了一个好的解决办法。

简介

Dubbo官网

英文官网:http://dubbo.apache.org/en-us/
中文官网:http://dubbo.apache.org/zh-cn/

Dubbo作用

Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。(不懂?没关系,跟着我一步步来,你就明白了)

RPC

RPC(Remote Procedure Call):远程过程调用
什么叫远程?
地方A有台电脑服务,地方B有台电脑服务,B调用A的服务,就叫远程。B调用自己的服务就叫本地。
更详细的解析,大家可以百度多了解了解。就好比我们常说的TCP/UDP/HTTP。

最简单的Dubbo架构关系

在这里插入图片描述
生产者:提供服务;
消费者:消费(使用)服务;
注册中心:服务注册与发现,连接生产者与消费者,一般使用Zookeeper;
监控管理:对生产者与消费者的“健康”管理;

搭建项目的前置知识

开发工具

  • IDEA(代码编辑,Eclipse也可以,看心情即可)
  • Mysql(数据库,你喜欢Oracle也可以)
  • Navicat(mysql数据库可视化工具)
  • Postman(模拟访问请求工具)
  • JDK,Maven,Tomcat,Zookeeper这些基本的还是安装安装

项目基本结构解析

在这里插入图片描述

正式搭建”生产者角色”环境的工程

创建父模块

  1. 打开Idea编辑器
  2. 点击创建一个新工程
    在这里插入图片描述
  3. 选择Maven
    在这里插入图片描述
  4. 填写项目工程基本信息
    在这里插入图片描述
    在这里插入图片描述
  5. 大功告成
    在这里插入图片描述

创建Client子模块

  1. 选中父模块中的项目名,然后右击,选择new和model
    在这里插入图片描述
  2. 同理,选择Maven
  3. 然后填写信息
    在这里插入图片描述
  4. 创建完成
    在这里插入图片描述

创建Model子模块

同创建Client子模块

创建Service子模块

同创建Client子模块

父模块和子模块创建完成的结构

在这里插入图片描述

导入相关的依赖

  1. client模块导入内容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>dubbofirst</artifactId>
        <groupId>com.scw.dubbo.first</groupId>
        <version>1.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>client</artifactId>
    <properties>
        <mybatis-pagehelper.version>4.1.2</mybatis-pagehelper.version>
        <lombok.version>1.16.10</lombok.version>
    </properties>

    <dependencies>
        <!--java校验 跟 hibernate校验-->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.3.5.Final</version>
        </dependency>

        <!--for page-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>${mybatis-pagehelper.version}</version>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>

    </dependencies>

</project>
  1. model模块导入内容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>dubbofirst</artifactId>
        <groupId>com.scw.dubbo.first</groupId>
        <version>1.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>model</artifactId>
    <properties>
        <mybatis-spring-boot.version>1.1.1</mybatis-spring-boot.version>
        <mybatis-pagehelper.version>4.1.2</mybatis-pagehelper.version>
    </properties>

    <dependencies>
        <!--api-->
        <dependency>
            <groupId>com.scw.dubbo.first</groupId>
            <artifactId>client</artifactId>
            <version>${project.parent.version}</version>
        </dependency>

        <!--spring-mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis-spring-boot.version}</version>
        </dependency>

    </dependencies>

</project>
  1. service模块导入内容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>dubbofirst</artifactId>
        <groupId>com.scw.dubbo.first</groupId>
        <version>1.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service</artifactId>
    <packaging>jar</packaging>

    <properties>
        <start-class>com.debug.mooc.dubbo.one.server.BootMoreApplication</start-class>

        <!--<spring-boot.version>1.3.3.RELEASE</spring-boot.version>-->
        <spring-boot.version>2.0.5.RELEASE</spring-boot.version>

        <spring-session.version>1.2.0.RELEASE</spring-session.version>
        <slf4j.version>1.7.13</slf4j.version>
        <log4j.version>1.2.17</log4j.version>
        <mysql.version>5.1.37</mysql.version>
        <druid.version>1.0.16</druid.version>
        <guava.version>19.0</guava.version>
        <joda-time.version>2.9.2</joda-time.version>
        <cglib.version>3.1</cglib.version>

        <zookeeper.version>3.4.10</zookeeper.version>
        <curator.version>2.12.0</curator.version>
        <dubbo.version>2.6.4</dubbo.version>

        <resteasy.version>3.0.7.Final</resteasy.version>
        <okhttp.version>3.1.2</okhttp.version>
        <gson.version>2.6.1</gson.version>
        <httpclient.version>4.3.6</httpclient.version>

    </properties>

    <!-- 依赖管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>

        <!--model-->
        <dependency>
            <groupId>com.scw.dubbo.first</groupId>
            <artifactId>model</artifactId>
            <version>${project.parent.version}</version>
        </dependency>

        <!--log-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <!--guava-->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>${guava.version}</version>
        </dependency>

        <!-- time -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>${joda-time.version}</version>
        </dependency>

        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>

        <!--spring-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring-boot.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-classic</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>log4j-over-slf4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- jsp 支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <!--<scope>provided</scope>-->
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <!--<scope>provided</scope>-->
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

        <!-- dubbo -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>${dubbo.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>curator-framework</artifactId>
                    <groupId>org.apache.curator</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>curator-client</artifactId>
                    <groupId>org.apache.curator</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>guava</artifactId>
                    <groupId>com.google.guava</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>spring-web</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>${cglib.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>asm</artifactId>
                    <groupId>org.ow2.asm</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- zookeeper start -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>${zookeeper.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>${curator.version}</version>
        </dependency>

        <!--dubbo rest-->
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jaxrs</artifactId>
            <version>${resteasy.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>httpclient</artifactId>
                    <groupId>org.apache.httpcomponents</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-netty</artifactId>
            <version>${resteasy.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-client</artifactId>
            <version>${resteasy.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jackson-provider</artifactId>
            <version>${resteasy.version}</version>
        </dependency>


        <!--for test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>${gson.version}</version>
        </dependency>

        <!-- okhttp -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>${okhttp.version}</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>dubboOne-${project.parent.version}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>

        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

</project>
  1. 父模块导入内容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.scw.dubbo.first</groupId>
    <artifactId>dubbofirst</artifactId>
    <packaging>pom</packaging>
    <version>1.0.1</version>
    <modules>
        <module>client</module>
        <module>model</module>
        <module>service</module>
    </modules>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    </properties>

</project>

service模块创建需要的配置文件

结构如下:
在这里插入图片描述

  • applicaion.properties
# dubbo提供服务的端口
server.port=8093
#server.context-path=/dubbofirst
# dubbo上下文路径
server.servlet.context-path=/dubbofirst
#logging
logging.path=E:\\logs\\mooc\\dubboOne\\logs
logging.file=dubboOne
logging.level.org.springframework = INFO
logging.level.com.fasterxml.jackson = INFO
logging.level.com.debug.mooc.dubbo.one = debug
#json时间解析配置
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#spring.datasource.initialize=false
spring.datasource.initialization-mode=never
spring.jmx.enabled=false
#数据库配置
datasource.url=jdbc:mysql://127.0.0.1:3306/dubbofirst?useUnicode=true&amp;characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
datasource.username=root
datasource.password=xxxxxxx
#mybatis
mybatis.config-location=classpath:mybatis-config.xml
mybatis.checkConfigLocation = true
mybatis.mapper-locations=classpath:mappers/*.xml
#dubbo zookeeper本地配置
dubbo.registry.address=zookeeper://127.0.0.1:2181
  • dubbo.properties
dubbo.container=log4j,spring
dubbo.reference.check=false
dubbo.registry.client=curator
dubbo.application.name=dubboFirst-provider
dubbo.application.owner=debug
#dubbo提供rpc服务接口
dubbo.protocol.name=dubbo
dubbo.protocol.dubbo.port=20903
#dubbo提供rest服务接口
dubbo.protocol.name=rest
dubbo.protocol.rest.port=9013
dubbo.protocol.rest.server=tomcat
dubbo.service.loadbalance=roundrobin
  • log4j.propertis
#Console Log
log4j.rootLogger=INFO,console,debug,info,warn,error

LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - %5p [%t] --- %c{1}: %m%n

#A1--Print log to Console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=${LOG_PATTERN}

log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
log4j.appender.info.Threshold=INFO
log4j.appender.info.File=${LOG_PATH}/${LOG_FILE}_info.log
log4j.appender.info.DatePattern='.'yyyy-MM-dd
log4j.appender.info.layout = org.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern=${LOG_PATTERN}

log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.Threshold=ERROR
log4j.appender.error.File=${LOG_PATH}/${LOG_FILE}_error.log
log4j.appender.error.DatePattern='.'yyyy-MM-dd
log4j.appender.error.layout = org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=${LOG_PATTERN}


log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
log4j.appender.debug.Threshold=DEBUG
log4j.appender.debug.File=${LOG_PATH}/${LOG_FILE}_debug.log
log4j.appender.debug.DatePattern='.'yyyy-MM-dd
log4j.appender.debug.layout = org.apache.log4j.PatternLayout
log4j.appender.debug.layout.ConversionPattern=${LOG_PATTERN}

log4j.appender.warn=org.apache.log4j.DailyRollingFileAppender
log4j.appender.warn.Threshold=WARN
log4j.appender.warn.File=${LOG_PATH}/${LOG_FILE}_warn.log
log4j.appender.warn.DatePattern='.'yyyy-MM-dd
log4j.appender.warn.layout = org.apache.log4j.PatternLayout
log4j.appender.warn.layout.ConversionPattern=${LOG_PATTERN}
  • mybatis-config.xml
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <settings>
        <!-- Globally enables or disables any caches configured in any mapper under this configuration -->
        <setting name="cacheEnabled" value="true"/>
        <!-- Sets the number of seconds the driver will wait for a response from the database -->
        <setting name="defaultStatementTimeout" value="3000"/>
        <!-- Enables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names aColumn -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- Allows JDBC support for generated keys. A compatible driver is required.
        This setting forces generated keys to be used if set to true,
         as some drivers deny compatibility but still work -->
        <setting name="useGeneratedKeys" value="true"/>
        <!-- 设置控制台打印sql -->
        <!--<setting name="logImpl" value="stdout_logging" />-->
    </settings>

    <!-- Continue going here -->

    <!--<typeAliases>-->
        <!--<package name="cn.com.countrygarden.ucenter.entity"/>-->
    <!--</typeAliases>-->
    <plugins>
        <!-- com.github.pagehelper为PageHelper类所在包名 -->
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <!-- 4.0.0以后版本可以不设置该参数 -->
            <property name="dialect" value="mysql"/>
            <!-- 该参数默认为false -->
            <!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 -->
            <!-- 和startPage中的pageNum效果一样-->
            <property name="offsetAsPageNum" value="true"/>
            <!-- 该参数默认为false -->
            <!-- 设置为true时,使用RowBounds分页会进行count查询 -->
            <property name="rowBoundsWithCount" value="true"/>
            <!-- 设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 -->
            <!-- (相当于没有执行分页查询,但是返回结果仍然是Page类型)-->
            <property name="pageSizeZero" value="true"/>
            <!-- 3.3.0版本可用 - 分页参数合理化,默认false禁用 -->
            <!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 -->
            <!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 -->
            <property name="reasonable" value="false"/>
            <!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 -->
            <!-- 增加了一个`params`参数来配置参数映射,用于从Map或ServletRequest中取值 -->
            <!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,orderBy,不配置映射的用默认值 -->
            <!-- 不理解该含义的前提下,不要随便复制该配置 -->
            <!--<property name="params" value="pageNum=pageHelperStart;pageSize=pageHelperRows;"/>-->
            <!-- 支持通过Mapper接口参数来传递分页参数 -->
            <property name="supportMethodsArguments" value="false"/>
            <!-- always总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page -->
            <property name="returnPageInfo" value="none"/>
        </plugin>
    </plugins>
</configuration>
  • spring-jdbc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       " >

    <!--dubbofirst -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close" primary="true" >
        <!-- 基本属性 url、user、password -->
        <property name="url" value="${datasource.url}" />
        <property name="username" value="${datasource.username}" />
        <property name="password" value="${datasource.password}" />

        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="10" />
        <property name="minIdle" value="10" />
        <property name="maxActive" value="20" />

        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="60000" />

        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />

        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />

        <property name="validationQuery" value="SELECT 1 " />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />

        <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
        <property name="poolPreparedStatements" value="true" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />

        <!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->
        <property name="filters" value="stat" />
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>
  • spring-dubbo.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!--发布出去的dubbo服务类所在包的注解-->
    <dubbo:annotation package="com.scw.dubbo.first.service.dubbo" />

    <!--注册中心zookeeper配置信息-->
    <dubbo:registry address="${dubbo.registry.address}" />

    <!--支持两种协议的调用:rpc-dubbo协议;http协议-rest api-url调用-->
    <dubbo:protocol name="rest" threads="500" contextpath="v1" server="tomcat" accepts="500"/>
    <dubbo:protocol name="dubbo" />

    <!--消费方信息配置-->
	<dubbo:application name="dubboFirst-consume" owner="debug" organization="dubbox"/>


</beans>

本地创建Zookeeper环境

下载链接:https://zookeeper.apache.org/releases.html
或者
https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/

安装步骤:

  1. 解压文件
  2. 在conf目录复制一份zoo_sample.cfg文件,并命名为zoo.cfg
  3. 在zoo.cfg修改data的目录,并且创建log存放的目录,如图所示:其中的data和log目录需要自己创建的哦!!!!
    在这里插入图片描述
  4. 运行bin目录下面的zkServicer,cmd,查看是否运行成功即可。(zookeeper默认的端口是:2181)

本地创建数据库

创建一个数据库,其名字要与配置文件中的配的一样(比如我配置的是:dubbofirst)

service模块创建项目的启动类

BootMoreApplication:

package com.scw.dubbo.first.service;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@ImportResource(value = {"classpath:spring/spring-jdbc.xml", "classpath:spring/spring-dubbo.xml"})
@MapperScan(basePackages = "com.scw.dubbo.first.model.mapper")
public class BootMoreApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(BootMoreApplication.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(BootMoreApplication.class, args);
    }

}

Client模块编写统一接口返回类

统一消息返回的枚举类

package com.scw.dubbo.first.client.enums;

/**
 * 统一接口的返回信息枚举类
 */
public enum  StatusCode {

    Success(0,"成功"),
    Fail(-1,"失败"),
    InvalidParams(200,"无效的参数"),
    ItemNotExist(201,"商品不存在!");

    private Integer code;
    private String msg;

    StatusCode(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

统一返回类:

package com.scw.dubbo.first.client.response;
import com.scw.dubbo.first.client.enums.StatusCode;
import java.io.Serializable;

/**
 * 统一返回类(便于统一返回信息)
 * @param <T>
 */
public class BaseResponse<T> implements Serializable{

    private Integer code;
    private String msg;
    private T data;

    public BaseResponse() {
    }

    public BaseResponse(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public BaseResponse(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public BaseResponse(StatusCode statusCode) {
        this.code = statusCode.getCode();
        this.msg = statusCode.getMsg();
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

Service模块编写项目环境搭建是否成功的Controller测试类

BaseController类

package com.scw.dubbo.first.service.controller;
import com.scw.dubbo.first.client.enums.StatusCode;
import com.scw.dubbo.first.client.response.BaseResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BaseController {

    private static final Logger log= LoggerFactory.getLogger(BaseController.class);

    private static final String prefix="base";

    /**
     * 测试环境搭建是否成功
     * @param param
     * @return
     */
    @RequestMapping(value = prefix+"/test",method = RequestMethod.GET)
    public BaseResponse one(@RequestParam String param){
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            response.setData(param);

        }catch (Exception e){
            e.printStackTrace();
            response=new BaseResponse(StatusCode.Fail);
        }
        return response;
    }
}

启动BootMoreApplication类,启动项目

如果启动项目发生错误,那么就根据错误进行提示修改哦。。。如果认真的按照我的步骤来的话,肯定是没问题的哈。

通过URL进行请求,判断环境搭建是否OK

情况一:URL

在这里插入图片描述
原因:因为我们在application.properties配置文件中,将端口改为了8093,所以现在还在用原来的8080当然是不可以的啦。!!!!

情况二:URL

在这里插入图片描述
What,怎么还不行,说好的是8093的呢?这是因为我们在application.properties文件中配置了dubbo的上下文是dubbofirst,所以这个链接当然不行了,继续往下面看~~~

情况三:URL

在这里插入图片描述

哇塞,,,,终于可以了,历经千辛万苦~~~~感动

备注:请大家一定要认真的研读配置文件的内容,一定要知道是干嘛的,是在哪里进行使用的,因为后续会非常多的使用到这些内容。基础扎实才决定我们能走多远~!

正式搭建”消费者角色”环境的工程

这个搭建与“生产者角色”的搭建过程一样,只是在配置文件中需要修改部分内容。

  1. 数据库的连接信息(与生产者的不一样即可)
  2. dubbo的相关端口(与生产者的不一样即可,因为现在搭建的都是在本地进行配置和部署,所以防止端口冲突)
    因此,这个搭建就不多说了。请返回上面进行重新搭建。

项目实践

一:商城系统调用商品系统(RPC接口)

场景描述

该场景分为两个角色:生产者(商品系统)和消费者(商城系统),而商城系统就通过调用商品系统而查询到对应的商品信息而进行显示。(备注:简单演示消费者调用生产者的服务)

项目实战开发

生产者代码(不分先后,根据自己的习惯来即可)
  1. 在client模块编写生产者服务的接口,命名IDubboItemService
package com.scw.dubbo.first.client.service;

import com.scw.dubbo.first.client.response.BaseResponse;

public interface IDubboItemService {

    /**
     * 查询商品
     * @return
     */
    BaseResponse listItems();
}
  1. 在service模块编写代码,命名为DubboItemServiceImpl
package com.scw.dubbo.first.service.dubbo;
import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.scw.dubbo.first.client.enums.StatusCode;
import com.scw.dubbo.first.client.response.BaseResponse;
import com.scw.dubbo.first.client.service.IDubboItemService;
import com.scw.dubbo.first.model.entity.ItemInfo;
import com.scw.dubbo.first.model.mapper.ItemInfoMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import java.util.List;

/**
 * 通过注解将其进行发布到注册中心
 */
@Service(protocol = {"dubbo","rest"},validation = "true",version = "1.0",timeout = 3000)
@Path("goods/")
public class DubboItemServiceImpl implements IDubboItemService {

    private static final Logger log= LoggerFactory.getLogger(DubboItemService.class);

    @Autowired
    private ItemInfoMapper itemInfoMapper;

    /**
     * 列表查询服务-实际的业务实现逻辑
     * @return
     */
    @Path("item/list")
    public BaseResponse listItems() {
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            List<ItemInfo> infos=itemInfoMapper.selectAll();
            log.info("查询到的商品列表数据:{} ",infos);
            response.setData(infos);

        }catch (Exception e){
            log.error("列表查询服务-实际的业务实现逻辑-发生异常:",e.fillInStackTrace());
            response=new BaseResponse(StatusCode.Fail);
        }
        return response;
    }
}
  1. 编写数据处理层Mapper映射类
package com.scw.dubbo.first.model.mapper;
import com.scw.dubbo.first.model.entity.ItemInfo;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface ItemInfoMapper {

    List<ItemInfo> selectAll();
}
  1. 编写对应Mapper类的xml文件

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.scw.dubbo.first.model.mapper.ItemInfoMapper" >
  <resultMap id="BaseResultMap" type="com.scw.dubbo.first.model.entity.ItemInfo" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="code" property="code" jdbcType="VARCHAR" />
    <result column="name" property="name" jdbcType="VARCHAR" />
    <result column="price" property="price" jdbcType="DECIMAL" />
    <result column="is_active" property="isActive" jdbcType="INTEGER" />
    <result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
    <result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, code, name, price, is_active, create_time, update_time
  </sql>
  <!--查询列表-->
  <select id="selectAll" resultType="com.scw.dubbo.first.model.entity.ItemInfo">
    SELECT <include refid="Base_Column_List"/>
    FROM item_info
    WHERE is_active = 1
    ORDER BY create_time DESC
  </select>
  1. ItemInfo商品对应的实体类
package com.scw.dubbo.first.model.entity;

import lombok.ToString;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

@ToString
public class ItemInfo implements Serializable{
    private Integer id;

    private String code;

    private String name;

    private BigDecimal price;

    private Integer isActive;

    private Date createTime;

    private Date updateTime;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code == null ? null : code.trim();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public Integer getIsActive() {
        return isActive;
    }

    public void setIsActive(Integer isActive) {
        this.isActive = isActive;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
}
  1. 将对应的生产者代码通过maven打成jar包生成依赖,便于消费者使用
    在这里插入图片描述
  2. 初始化数据库的数据
/*
Navicat MySQL Data Transfer

Source Server         : mylocal
Source Server Version : 50717
Source Host           : localhost:3306
Source Database       : dubbofirst

Target Server Type    : MYSQL
Target Server Version : 50717
File Encoding         : 65001

Date: 2019-10-07 18:38:48
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `item_info`
-- ----------------------------
DROP TABLE IF EXISTS `item_info`;
CREATE TABLE `item_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `code` varchar(255) DEFAULT NULL COMMENT '商品编码',
  `name` varchar(255) DEFAULT NULL COMMENT '名称',
  `price` decimal(15,2) DEFAULT NULL COMMENT '销售价',
  `is_active` int(11) DEFAULT '1' COMMENT '是否有效(1=是;0=否)',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_code` (`code`) USING BTREE COMMENT '商品编码唯一'
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='商品信息表';

-- ----------------------------
-- Records of item_info
-- ----------------------------
INSERT INTO `item_info` VALUES ('1', '10010', 'Java编程思想', '58.50', '1', '2019-01-13 14:07:58', null);
INSERT INTO `item_info` VALUES ('2', '10011', '由浅入深实战分布式中间件', '45.50', '1', '2019-01-13 14:07:59', null);
INSERT INTO `item_info` VALUES ('3', '10012', 'Dubbo实战教程', '68.00', '1', '2019-01-13 14:07:59', null);
INSERT INTO `item_info` VALUES ('4', '10013', 'JVM深入实战指南', '38.50', '1', '2019-01-13 14:07:59', null);
INSERT INTO `item_info` VALUES ('5', '10014', 'SpringBoot实战', '56.50', '1', '2019-01-13 14:07:59', null);
INSERT INTO `item_info` VALUES ('6', '10015', 'SpringCloud实战', '64.00', '1', '2019-01-13 14:07:59', null);
INSERT INTO `item_info` VALUES ('7', '10017', 'Mysql实战指南', '75.50', '1', '2019-01-13 14:07:59', null);

消费者代码
  1. service模块的pom.xml文件添加对生产者的依赖配置
<dependency>
            <groupId>com.scw.dubbo.first</groupId>
            <artifactId>client</artifactId>
            <version>1.0.1</version>
        </dependency>
  1. 在service模块中的spring-dubbo.xml文件添加生产者服务的配置
  <!--引入服务提供方提供的dubbo服务-url="dubbo://127.0.0.1:20903" -->
    <dubbo:reference interface="com.scw.dubbo.first.client.service.IDubboItemService" id="dubboItemService"
                     url="dubbo://127.0.0.1:20903" protocol="dubbo" version="1.0" timeout="20000">
    </dubbo:reference>

备注:其中的url如果是本地的话可以不写,因为在自测的时候都是在本的,而如果以后在实际项目后,我们可以设置生产者服务对应的服务器的IP地址和端口;

  1. 消费者编写调用生产者接口的业务代码
package com.scw.dubbo.second.service.controller;
import com.google.common.collect.Maps;
import com.scw.dubbo.first.client.response.BaseResponse;
import com.scw.dubbo.first.client.service.IDubboItemService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;

@RestController
public class ItemController {

    private static final Logger log= LoggerFactory.getLogger(ItemController.class);

    private static final String prefix="item";
	//之所以能够引入生产者中的类,就是因为我们在pom.xml文件引入了生产者的依赖
    @Autowired
    private IDubboItemService dubboItemService;



    /**
     * 用户商城列表查询
     * @return
     */
    @RequestMapping(value = prefix+"/list",method = RequestMethod.GET)
    public Map<String,Object> list(){
        Map<String,Object> resMap= Maps.newHashMap();
        resMap.put("code","0");
        resMap.put("msg","成功");

        //TODO:调用服务提供方dubboFirst提供的列表查询功能
        try {
            BaseResponse response = dubboItemService.listItems();
            if (response!=null && response.getCode().equals(0)){
                resMap.put("data",response.getData());
            }
        }catch (Exception e){
            e.printStackTrace();
            resMap.put("code","-1");
            resMap.put("msg","失败");
        }
        return resMap;
    }

  1. 启动服务,查看结果
    当消费者要使用生产者的接口服务的时候,一定要保证生产者的服务是处于可用状态,否则会提示无法调用连接生产者的接口。
    因此,别忘记启动笨的的zookeeper服务哦,然后再启动生产者服务,最后再启动消费者服务即可;
  2. 通过URL请求,查看调用结果
    在这里插入图片描述
    备注:我们可以看到通过消费者确实调用到了生产者的接口,并且也达到了我们预想的结果。

二:商品系统调用订单系统(Rest接口调用)

描述:在商品系统中,用户可以通过商品系统进行对应商品的下单(如:淘宝商城买东西),而实际的商品订单系统又是属于另外一个模块,而并非在商品系统中,所以这时候就出现一个系统调用另外一个系统的接口来完成功能。

PS:其实这个接口可以像上面的例子一样采取RPC的调用方式,但是为了让大家了解不同的调用方式,所以这个实例就采取Rest的调用方式。大家有兴趣的话,也可以将下面这个例子改成用RPC的形式哟。!

实践流程

**备注:**下面的生产者和消费者,我就默认和上面的实例保持一样了,所以基本的环境搭建就不重复说,就只是说如何完成这个功能,如果环境还没搭好的,那么就认真看看上面的例子哟。

生产者(订单系统)

  1. 数据库设计
    MysqlDDL语句:
CREATE TABLE `order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `item_id` int(11) NOT NULL,
  `customer_name` varchar(255) NOT NULL,
  `total` int(11) NOT NULL,
  `order_time` datetime NOT NULL,
  `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

数据库内容:
在这里插入图片描述
备注:大家主要是理解这个过程,而不是在于看数据库的结构设计,仅仅是一个示例;

  1. 订单order实体类
package com.scw.dubbo.first.client.model;

import lombok.Data;
import lombok.ToString;

import java.io.Serializable;
import java.util.Date;

/**
 * @ Author     :scw
 * @ Date       :Created in 下午 4:55 2019/11/24 0024
 * @ Description:订单实体
 * @ Modified By:
 * @Version: $version$
 */
@Data
@ToString
public class Order implements Serializable{
    //主键
    private Integer id;
    //商品ID
    private Integer itemId;
    //用户名
    private String customerName;
    //商品总数量
    private Integer total;
    //下单时间
    private Date orderTime;
    //更新时间
    private Date updateTime;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getItemId() {
        return itemId;
    }

    public void setItemId(Integer itemId) {
        this.itemId = itemId;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public Integer getTotal() {
        return total;
    }

    public void setTotal(Integer total) {
        this.total = total;
    }

    public Date getOrderTime() {
        return orderTime;
    }

    public void setOrderTime(Date orderTime) {
        this.orderTime = orderTime;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
}

  1. Rest接口
package com.scw.dubbo.first.client.service;

import com.scw.dubbo.first.client.model.Order;
import com.scw.dubbo.first.client.response.BaseResponse;

/**
 * @ Author     :scw
 * @ Date       :Created in 下午 4:53 2019/11/24 0024
 * @ Description:订单Rest接口
 * @ Modified By:
 * @Version: $version$
 */
public interface OrderService {

    /**
     * 客户商品下单
     * @param order
     * @return
     */
    BaseResponse addCustomerProductOrder(Order order);

}

  1. Rest接口实现类(真正提供服务的接口)
package com.scw.dubbo.first.service.rest;

import com.alibaba.dubbo.config.annotation.Service;
import com.scw.dubbo.first.client.enums.StatusCode;
import com.scw.dubbo.first.client.model.Order;
import com.scw.dubbo.first.client.response.BaseResponse;
import com.scw.dubbo.first.client.service.OrderService;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.Date;

/**
 * @ Author     :scw
 * @ Date       :Created in 下午 4:59 2019/11/24 0024
 * @ Description:客户商品下单rest接口实现类
 * @ Modified By:
 * @Version: $version$
 */
@Path("order")
@Service(protocol = {"dubbo","rest"},validation = "true",version = "1.0",timeout = 3000)
public class OrderServiceImpl implements OrderService {

    /**
     * 客户商品下单的POST请求的接口
     * 备注:consumes和produces注解就是将其接口设置的接受类型(还有很多比如XML,都可以)
     * @param order
     * @return
     */
    @Path("/add")
    @POST
    @Consumes(value = MediaType.APPLICATION_JSON)
    @Produces(value = MediaType.APPLICATION_JSON)
    @Override
    public BaseResponse addCustomerProductOrder(Order order) {
        BaseResponse baseResponse = new BaseResponse(StatusCode.Success);
        //TODO 随便写一些处理逻辑,这个一般还有数据层的操作,这里就不演示了
        if(order == null){
            baseResponse.setCode(StatusCode.Fail.getCode());
            baseResponse.setMsg("订单数据不能为空");
            return baseResponse;
        }
        //TODO 一些逻辑处理,这里就不多写了
        order.setUpdateTime(new Date());
        return baseResponse;
    }

}

  1. 启动服务,自测是否接口成功
    备注:
    大家可以下一个Postman的软件用于发出请求,或者采取IDEA自带的插件也是可以的。
    (1)情景如下
    在这里插入图片描述
    原因解析: 很多人都不知道到底请求的时候是采取服务的上下文前缀(如:dubbofirst)还是dubbo暴露出去的上下前缀(如:v1,这个是在上面的例子配的,大家根据自己需求配置即可,我这是为了方便),大家可以理解为:如果当前的接口是dubbo或者rest接口那么我们就要采取dubbo的上下文;如果是用的controller层的请求,那么自然就是用的项目服务的上下文;
    application.properties配置文件:
    在这里插入图片描述
    spring.dubbo.xml配置文件:
    在这里插入图片描述
    (2)情景如下:
    在这里插入图片描述
    备注: 很明显,咱们写的rest接口没有问题,那么如何给另外一个服务进行调用呢?那么继续往下看,let‘s go

消费者(商品系统)

  1. Controller类(功能:用于本服务对外提供请求接口)
package com.scw.dubbo.second.service.controller;

import com.google.common.collect.Maps;
import com.scw.dubbo.second.client.model.OrderDto;
import com.scw.dubbo.second.service.rest.OrderServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.ws.rs.core.MediaType;
import java.util.Map;

/**
 * @ Author     :scw
 * @ Date       :Created in 下午 5:37 2019/11/24 0024
 * @ Description:商城系统的客户下单请求controller
 *
 * @ Modified By:
 * @Version: $version$
 */
@RestController
public class OrderController {

    private static final Logger log= LoggerFactory.getLogger(OrderController.class);

    @Autowired
    private OrderServiceImpl orderService;

    /**
     * 客户下订单接口
     * 备注:consumes就是限制了前端是传Json格式的参数,如果不加,那么就以post请求的方式传Key 和 value即可(原始的方式)
     * @param order
     * @return
     */
    @RequestMapping(value = "/add", method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON)
    public Map<String, Object> addCustomerOrder(@RequestBody OrderDto order){
        Map<String,Object> resMap= Maps.newHashMap();
        resMap.put("code","0");
        resMap.put("msg","成功");
        try {
            //将调用另外一个系统的接口写在service层便于逻辑处理
            orderService.addOrder(order);
        }catch (Exception e){
            log.error("客户下单发生异常:" + e);
        }

        return resMap ;
    }

}

  1. 采用Rest调用生产者的下单服务接口OrderServiceImpl
    备注:其中示例采用的post请求是使用OKhttp对象,大家也可以采取其他的对象都是可以的哦!!
package com.scw.dubbo.second.service.rest;

import com.scw.dubbo.second.client.model.OrderDto;
import com.scw.dubbo.second.service.controller.ItemController;
import okhttp3.*;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * @ Author     :scw
 * @ Date       :Created in 下午 5:50 2019/11/24 0024
 * @ Description:调用其他服务rest接口的实现类
 * @ Modified By:
 * @Version: $version$
 */
@Service
public class OrderServiceImpl {

    //调用其他服务rest接口的请求URL
    private static final String ORDER_URL = "http:127.0.0.1:9013/v1/order/add";

    //将对象序列化的对象
    private ObjectMapper objectMapper = new ObjectMapper();

    //采取okhttp的对象来实现post请求
    private OkHttpClient okHttpClient = new OkHttpClient();

    private static final Logger log= LoggerFactory.getLogger(OrderServiceImpl.class);


    /**
     * 处理用户下单的逻辑
     * @param orderDto
     */
    public void addOrder(OrderDto orderDto) {
        try {
            //(1)构造builder对象
            Request.Builder builder = new Request.Builder().url(ORDER_URL).header("Content-Type", "application/json");
            //(2)构造消息体
            RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), objectMapper.writeValueAsString(orderDto));
            //(3)构造请求
            Request request = builder.post(requestBody).build();
            //(4)发送请求
            Response response = okHttpClient.newCall(request).execute();
            //(5)打印响应内容
            log.info("响应结果为:" + response.body().toString());
        } catch (Exception e) {

        }
    }

}

  1. 启动服务,测试结果
    (1)场景如下:
    在这里插入图片描述
    原因分析: 这是因为当前的服务是调用方,并且调用的是controller层的请求,那么URL对应的上下文应该是系统服务,而不是dubbo的上下文。因此,应该将v2改为dubboSecond即可(具体可以对比下面的一种场景)。
    (2)场景如下:
    在这里插入图片描述
    是否会怀疑到底是不是另外一个服务提供的服务呢?那我们回到IDEA则可以看到提供服务系统成功的打印了如下的信息,所以成功调用另外服务的rest接口啦!
    在这里插入图片描述
    哇塞。。。。。调用成功,基本流程已经打通,是不是觉得其实就和调用自己系统的方法一样呢?so easy!!!

  2. 调用post方法的优化
    备注:上面调用的方式其实很简单,但是不够通用,为了系统能够更好的调用Post和Get类型的请求,我们应该封装一下,达到更好的优化效果!
    (后续再补啦,一下接受太多不太好,大家赶紧先去试试感觉!!!!!!!!!!)

未完待续

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/12379.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!