分佈式電商項目(九)--Dubbo&Zookeeper&項目重構

SOA思想

SOA思想介紹

面向服務的架構(SOA)是一個組件模型,它將應用程序的不一樣功能單元(稱爲服務)進行拆分,並經過這些服務之間定義良好的接口和協議聯繫起來。接口是採用中立的方式進行定義的,它應該獨立於實現服務的硬件平臺、操做系統和編程語言。這使得構建在各類各樣的系統中的服務能夠以一種統一和通用的方式進行交互。
在這裏插入圖片描述html

RPC介紹(調用形式的統稱)

RPC介紹

RPC(Remote Procedure Call)遠程過程調用,簡單的理解是一個節點請求另外一個節點提供的服務
本地過程調用:若是須要將本地student對象的age+1,能夠實現一個addAge()方法,將student對象傳入,對年齡進行更新以後返回便可,本地方法調用的函數體經過函數指針來指定。
遠程過程調用:addAge方法在其餘的服務器中,若是須要調用則必須經過遠程的方式通知其餘服務器幫我完成業務調用.java

總結: 利用第三方的服務器,幫我完成業務調用的過程.
理解: 分佈式環境中 業務調用幾乎都是RPC的.mysql

微服務

什麼是微服務

說明:nginx

  1. 爲了下降代碼的耦合性,將項目進行了拆分.按照功能模塊拆分爲若干個項目.該項目稱之爲服務.(分佈式思想).
  2. 若是採用微服務的結構,要求服務器若是出現了故障應該實現自動化的故障的遷移(高可用HA)

現有服務分析

說明:因爲nginx負載均衡/反向代理都須要人爲的配置,而且出現了問題不能及時的實現故障的遷移,因此須要升級爲微服務的架構的設計.
在這裏插入圖片描述web

微服務架構設計

在這裏插入圖片描述
實現步驟:redis

  1. 服務提供者啓動時,.將本身的信息註冊到註冊中心中.
  2. 註冊中心接受到了用戶的請求以後,更新服務列表信息.
  3. 當消費者啓動時,首先會連接註冊中心,獲取服務列表數據.
  4. 註冊中心將本身的服務列表信息同步給客戶端(消費者)
  5. 消費者接收到服務列表數據以後,將信息保存到本身的本地.方便下次調用
  6. 當消費者接收到用戶的請求時,根據本身服務列表的信息進行負載均衡的操做,選擇其中一個服務的提供者,根據IP:PORT 進行RPC調用.
  7. 當服務提供者宕機時,註冊中心會有心跳檢測機制,若是檢查宕機,則更新本地的服務列表數據,而且全網廣播通知全部的消費者更新服務列表.

Zookeeper

Zookeeper介紹

ZooKeeper是一個分佈式的,開放源碼的分佈式應用程序協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要組件。它是一個爲分佈式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分佈式同步、組服務等。
ZooKeeper的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。
ZooKeeper包含一個簡單的原語集,提供Java和C的接口。
ZooKeeper代碼版本中,提供了分佈式獨享鎖、選舉、隊列的接口,代碼在zookeeper-3.4.3srcrecipes。其中分佈鎖和隊列有Java和C兩個版本,選舉只有Java版本。算法

總結:Zookeeper負責服務的協調調度.當客戶端發起請求時,返回正確的服務器地址.spring

Zookeeper下載

網址: http://zookeeper.apache.org/releases.html.sql

ZK安裝

先安裝JDK(jdk1.8)

1.上傳安裝文件

1.png
解壓目錄:apache

tar -xvf zookeeper-3.4.8.tar.gz

2.修改配置文件

在zk根目錄下建立文件夾data/log

mkdir data log

2.png

3.跳入conf目錄中修改配置文件

複製配置文件而且修更名稱

cp zoo_sample.cfg zoo.cfg

3.png

4.啓動zk

跳轉到bin目錄中 zk啓動關閉命令以下.

sh zkServer.sh start 或者 ./zkServer.sh start
sh zkServer.sh stop
sh zkServer.sh status

4.png

Zookeeper集羣安裝

1.準備文件夾

在zookeeper根目錄中建立新的文件夾zkCluster.
1.png
建立zk1/zk2/zk3文件夾.
2.png
在每一個文件夾裏建立data/log文件夾.

mkdir {zk1,zk2,zk3}/{data,log}

3.png

2.在每一個文件夾裏建立data/log文件夾.

mkdir {zk1,zk2,zk3}/{data,log}

4.png

3.分別在zk1/zk2/zk3中的data文件夾中建立新的文件myid.其中的內容依次爲1/2/3,與zk節點號對應.

2020-11-18_195924.png

4.在config目錄中將zoo_sample.cfg 複製爲zoo1.cfg以後修改配置文件.

將zoo_sample.cfg 複製爲zoo1.cfg以後修改配置文件.
6.png

5.修改zoo1.cfg

2020-11-18_200155.png

配置完成後將zoo1.cfg複製2份.以後須要修改對應的文件夾目錄.和不一樣的端口便可.

6.ZK集羣測試

經過下面的命令啓動zk集羣.

sh zkServer.sh start zoo1.cfg
sh zkServer.sh stop  zoo1.cfg
sh zkServer.sh status zoo1.cfg

檢查主從關係,從機狀況說明
8.png
檢查主從關係,主機狀況說明
9.png

關於zookeeper集羣說明

Zookeeper集羣中leader負責監控集羣狀態,follower主要負責客戶端連接獲取服務列表信息.同時參與投票.

爲何集羣通常都是奇數個?

公式: 存活的節點 > N/2

公式解讀:(zookeeper集羣服務器數 - 宕機的服務器數量)>集羣數/2
集羣的概念即實現高可用,若是宕機一臺就失效也不能稱爲集羣,因此判斷集羣的依據是當有一臺服務器宕機 公式依然成當即爲集羣
容許最大宕機數:保持公式成立的集羣數與宕機數,不然集羣崩潰

常識: 最小的集羣的單位3臺.
例子:
1個節點可否搭建集羣? 1-1 > 1/2 假的 1個節點不能搭建集羣
2個節點可否搭建集羣? 2-1 > 2/2 假的 2個節點不能搭建集羣
3個節點可否搭建集羣? 3-1 > 3/2 真的 3個節點能搭建集羣
4個節點可否搭建集羣? 4-1 > 4/2 真的 4個節點能搭建集羣

3個節點最多容許宕機1臺,不然集羣崩潰.
4個節點最多容許宕機1臺,不然集羣崩潰.

搭建奇數臺和偶數臺其實均可以,可是從容災性的角度考慮,發現奇數和偶數的效果相同,.因此搭建奇數臺.

ZK集羣選舉規則

說明: zk集羣選舉採用最大值(myid)優先的算法實現,若是集羣中沒有主機,則開始選舉(超半數便可),若是有主機,則選舉結束.
考題: 1 2 3 4 5 6 7 依次啓動時
問題1:誰當主機? 4當主機
問題2:誰永遠不能當選主機? 1,2,3

Dubbo框架

Dubbo介紹

Apache Dubbo |ˈdʌbəʊ| 提供了六大核心能力:面向接口代理的高性能RPC調用,智能容錯和負載均衡,服務自動註冊和發現,高度可擴展能力,運行期流量調度,可視化的服務治理與運維。
在這裏插入圖片描述
調用原理圖:
在這裏插入圖片描述

Dubbo入門案例

修改配置文件內容

1).修改SpringBoot的版本
在這裏插入圖片描述
2).修改模塊名稱 改成dubbo-jt-demo-interface
在這裏插入圖片描述

導入maven項目

在這裏插入圖片描述
修改倆個生產者的驅動爲com.mysql.cj.jdbc.Driver
2020-11-18_201617.png

測試效果

在這裏插入圖片描述

建立接口

1).定義接口
在這裏插入圖片描述
2).定義接口代碼
在這裏插入圖片描述

建立服務生產者

定義生產者的實現類

package com.jt.dubbo.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.dubbo.config.annotation.Service;
import com.jt.dubbo.mapper.UserMapper;
import com.jt.dubbo.pojo.User;
@Service(timeout=3000)    //3秒超時 內部實現了rpc
//@org.springframework.stereotype.Service//將對象交給spring容器管理
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    public List<User> findAll() {
        
        System.out.println("我是第一個服務的提供者");
        return userMapper.selectList(null);
    }
    
    @Override
    public void saveUser(User user) {
        
        userMapper.insert(user);
    }
}

提供者配置文件

server:
  port: 9000   #定義端口

spring:
  datasource:
    #引入druid數據源
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

#關於Dubbo配置   
dubbo:
  scan:
    basePackages: com.jt    #指定dubbo的包路徑
  application:              #應用名稱
    name: provider-user     #一個接口對應一個服務名稱
  registry:
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
  protocol:  #指定協議
    name: dubbo  #使用dubbo協議(tcp-ip)  web-controller直接調用sso-Service
    port: 20880  #每個服務都有本身特定的端口 不能重複.

      
mybatis-plus:
  type-aliases-package: com.jt.dubbo.pojo       #配置別名包路徑
  mapper-locations: classpath:/mybatis/mappers/*.xml  #添加mapper映射文件
  configuration:
    map-underscore-to-camel-case: true                #開啓駝峯映射規則

服務消費者

編輯Controller

package com.jt.dubbo.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.dubbo.pojo.User;
import com.jt.dubbo.service.UserService;

@RestController
public class UserController {
    
    //利用dubbo的方式爲接口建立代理對象 利用rpc調用
    //@Reference(loadbalance="random") //負載均衡的隨機算法(若是不寫參數,默認也是random)
    //@Reference(loadbalance="roundrobin") //輪循算法
    //@Reference(loadbalance="consistenthash") //一致性hash的算法(參數全小寫)
    //調用遠程服務就像調用本身的服務同樣的簡單!!!
    @Reference(loadbalance="leastactive") //挑選壓力最小的服務器
    private UserService userService; 
    
    /**
     * Dubbo框架調用特色:遠程RPC調用就像調用本身本地服務同樣簡單
     * @return
     */
    @RequestMapping("/findAll")
    public List<User> findAll(){
        
        //遠程調用時傳遞的對象數據必須序列化.
        return userService.findAll();
    }
    
    @RequestMapping("/saveUser/{name}/{age}/{sex}")
    public String saveUser(User user) {
        
        userService.saveUser(user);
        return "用戶入庫成功!!!";
    }
}

編輯YML配置文件

server:
  port: 9001
dubbo:
  scan:
    basePackages: com.jt
  application:
    name: consumer-user   #定義消費者名稱
  registry:               #註冊中心地址
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.12

消費者測試

在這裏插入圖片描述

Dubbo高可用測試

測試需求

1).測試當服務器宕機,用戶訪問是否受影響. 用戶訪問不受影響. zk心跳檢測機制
2).測試當zk集羣宕機,用戶訪問是否受影響. 不受影響 消費者在本地有服務列表數據,本身維護.
3).測試是否有負載均衡的效果 用戶訪問有負載均衡的效果

Dubbo負載均衡

負載均衡方式

1.服務端負載均衡(集中式負載均衡)
說明: 用戶訪問服務器時不清楚真實的服務器究竟是誰,由負載均衡服務器動態動態管理.
典型表明: NGINX
通常nginx服務器作反向代理使用,負載均衡只是提供的功能.

2.客戶端負載均衡
說明:採用微服務架構時,當消費者訪問服務提供者時,因爲框架內部已經實現了負載均衡的策略,因此消費者訪問提供者時已經完成了負載均衡的機制.因此將全部的壓力平衡到了各個消費者中.
在這裏插入圖片描述

負載均衡-隨機算法

默認條件下就是隨機算法
在這裏插入圖片描述

在這裏插入圖片描述

負載均衡-輪詢算法

在這裏插入圖片描述
在這裏插入圖片描述

負載均衡-一致性hash

在這裏插入圖片描述
在這裏插入圖片描述

負載均衡-最少訪問

在這裏插入圖片描述
在這裏插入圖片描述

重構京淘項目

導入jar包

<!--引入dubbo配置 -->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.0</version>
        </dependency>

重構接口項目

說明:在jt-common中添加接口文件.
在這裏插入圖片描述

重構JT-SSO(生產者)

編輯Service實現類

在這裏插入圖片描述

編輯YML配置文件

server:
  port: 8093
  servlet:
    context-path: /    #在根目錄中發佈  缺省值.
spring:
  datasource:
    #引入druid數據源
    #type: com.alibaba.druid.pool.DruidDataSource
    #driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp
#mybatis-plush配置
mybatis-plus:
  type-aliases-package: com.jt.pojo
  mapper-locations: classpath:/mybatis/mappers/*.xml
  configuration:
    map-underscore-to-camel-case: true

logging:
  level: 
    com.jt.mapper: debug

#關於Dubbo配置
dubbo:
  scan:
    basePackages: com.jt    #指定dubbo的包路徑
  application:              #應用名稱
    name: provider-user     #一個接口對應一個服務名稱
  registry:
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
  protocol:  #指定協議
    name: dubbo  #使用dubbo協議(tcp-ip)  web-controller直接調用sso-Service
    port: 20880  #每個服務都有本身特定的端口 不能重複.

重構服務消費者

編輯UserController

在這裏插入圖片描述

編輯YML配置文件

server:
  port: 8092    
spring:     #定義springmvc視圖解析器
  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp
      
#配置dubbo消費者
dubbo:
  scan:
    basePackages: com.jt
  application:
    name: consumer-user   #定義消費者名稱
  registry:               #註冊中心地址
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183

用戶模塊實現

用戶註冊實現

頁面分析

1).頁面url地址
在這裏插入圖片描述
2.頁面提交參數
在這裏插入圖片描述
3.頁面JS分析
在這裏插入圖片描述

編輯UserController

/**
     * 完成用戶的註冊操做
     * url地址: http://www.jt.com/user/doRegister
     *          Request Method: POST
     * 請求參數:
     *          password: admin123
     *          username: admin123123123
     *          phone: 13111112225
     * 返回值類型:
     *          SysResult對象
     */
    @RequestMapping("/doRegister")
    @ResponseBody
    public SysResult saveUser(User user){

        //利用dubbo進行RPC調用
        dubboUserService.saveUser(user);
        return SysResult.success();
    }

編輯UserService

package com.jt.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;

@Service(timeout = 3000)
public class DubboUserServiceImpl implements DubboUserService{

    @Autowired
    private UserMapper userMapper;

    @Override
    public void saveUser(User user) {
        //密碼採用md5方式進行加密處理
        String password = user.getPassword();
        String md5Pass = DigestUtils.md5DigestAsHex(password.getBytes());
        user.setEmail(user.getPhone()).setPassword(md5Pass);
        userMapper.insert(user);
    }
}

頁面效果展示

在這裏插入圖片描述

用戶登陸

單點登陸業務實現

單點登陸(SingleSignOn,SSO),就是經過用戶的一次性鑑別登陸。當用戶在身份認證服務器上登陸一次之後,便可得到訪問單點登陸系統中其餘關聯繫統和應用軟件的權限,同時這種實現是不須要管理員對用戶的登陸狀態或其餘信息進行修改的,這意味着在多個應用系統中,用戶只需一次登陸就能夠訪問全部相互信任的應用系統。這種方式減小了由登陸產生的時間消耗,輔助了用戶管理,是目前比較流行的.

在這裏插入圖片描述
實現步驟:
1.用戶輸入用戶名和密碼以後點擊登陸按鈕開始進行登陸操做.
2.JT-WEB向JT-SSO發送請求,完成數據校驗
3.當JT-SSO獲取數據信息以後,完成用戶的校驗,若是校驗經過則將用戶信息轉化爲json.而且動態生成UUID.將數據保存到redis中. 而且返回值uuid.
若是校驗不存在時,直接返回"不存在"便可.
4.JT-SSO將數據返回給JT-WEB服務器.
5.若是登陸成功,則將用戶UUID保存到客戶端的cookie中.

頁面URL分析

1).url請求
在這裏插入圖片描述
2).url參數
在這裏插入圖片描述
3).頁面JS分析
在這裏插入圖片描述

編輯UserController

/**
     * 業務:完成用戶登陸操做
     * url地址: http://www.jt.com/user/doLogin?r=0.35842191622936337
     * 參數:
     *          username: admin123
     *          password: admin123456
     * 返回值:   SysResult對象
     *
     * 業務具體實現:
     *      1.校驗用戶名和密碼是否正確
     *      2.判斷返回值結果是否爲null 用戶名和密碼有誤 返回201狀態碼
     *      3.若是返回值結果不爲null  uuid保存到cookie中便可.
     *
     *  Cookie知識介紹:
     *      1.cookie.setPath("/")  根目錄有效
     *      url1:  www.jt.com/addUser
     *      url2:  www.jt.com/user/addUser
     *
     *      2. cookie.setDomain("域名地址");  cookie在哪一個域名中共享
     *      例子1:   cookie.setDomain("www.jt.com");
     *               只有在www.jt.com的域名中有效
     *
     *               cookie.setDomain("jt.com");
     *               只有在jt.com結尾的域名中有效
     *
     */
    @RequestMapping("/doLogin")
    @ResponseBody
    public SysResult doLogin(User user, HttpServletResponse response){
        String uuid = dubboUserService.doLogin(user);
        if(StringUtils.isEmpty(uuid)){
            return SysResult.fail();
        }
        //將uuid保存到Cookie中
        Cookie cookie = new Cookie("JT_TICKET",uuid);
        cookie.setMaxAge(30*24*60*60);  //讓cookie 30天有效
        cookie.setPath("/");            //cookie在哪一個url路徑生效
        cookie.setDomain("jt.com");     //設定cookie共享
        response.addCookie(cookie);

        return SysResult.success();
    }

編輯UserService

/**
     * 1.根據用戶名和密碼查詢後端服務器數據
     * 2.將密碼加密處理
     * @param user
     * @return
     */
    @Override
    public String doLogin(User user) {
        String md5Pass = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        user.setPassword(md5Pass);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);//u/p不能
        //根據對象中不爲空的屬性,充當where條件.
        User userDB = userMapper.selectOne(queryWrapper);
        if(userDB == null){
            //根據用戶名和密碼錯誤
            return null;
        }
        //開始進行單點登陸業務操做
        String uuid = UUID.randomUUID()
                          .toString()
                          .replace("-", "");
        userDB.setPassword("123456你信不?");   //去除有效信息.
        String userJSON = ObjectMapperUtil.toJSON(userDB);
        jedisCluster.setex(uuid, 30*24*60*60, userJSON);

        return uuid;
    }

頁面效果展示

在這裏插入圖片描述

用戶信息回顯

用戶信息回顯業務需求

思路: 用戶經過TICKET信息,利用JSONP的方式動態獲取遠程的服務器數據信息.以後將數據返回以後 回顯數據.

用戶URL請求

在這裏插入圖片描述

頁面JS分析

在這裏插入圖片描述

編輯JT-SSO的UserController

/**
     * 業務說明:
     *   經過跨域請求方式,獲取用戶的JSON數據.
     *   1.url地址:  http://sso.jt.com/user/query/efd321aec0ca4cd6a319b49bd0bed2db?callback=jsonp1605775149414&_=1605775149460
     *   2.請求參數:  ticket信息
     *   3.返回值:   SysResult對象 (userJSON)
     *   需求: 經過ticket信息獲取user JSON串
     */
    @RequestMapping("/query/{ticket}")
    public JSONPObject findUserByTicket(@PathVariable String ticket,String callback){

        String userJSON = jedisCluster.get(ticket);
        if(StringUtils.isEmpty(userJSON)){

            return new JSONPObject(callback, SysResult.fail());
        }else{
            return new JSONPObject(callback, SysResult.success(userJSON));
        }
    }

頁面效果展示

在這裏插入圖片描述

用戶登出操做

退出業務邏輯

當用戶點擊退出操做時,應該重定向到系統首頁. 同時刪除redis信息/Cookie信息.

編輯UserController

/**
     * 完成用戶退出操做
     * url地址:http://www.jt.com/user/logout.html
     * 參數:   沒有參數
     * 返回值:  String 重定向到系統首頁
     * 業務:
     *      1.刪除redis   K-V   獲取ticket信息
     *      2.刪除cookie
     */
    @RequestMapping("/logout")
    public String logout(HttpServletRequest request,HttpServletResponse response){
        //1.獲取Cookie中的JT_TICKET值
        Cookie[] cookies = request.getCookies();
        if(cookies != null && cookies.length>0){
            for (Cookie cookie : cookies){
                if(cookie.getName().equals("JT_TICKET")){
                    String ticket = cookie.getValue();
                    //redis刪除ticket信息
                    jedisCluster.del(ticket);
                    cookie.setMaxAge(0);    //0表示當即刪除
                    //規則cookie若是須要操做,必須嚴格定義
                    cookie.setPath("/");
                    cookie.setDomain("jt.com");
                    response.addCookie(cookie);
                }
            }
        }

        return "redirect:/";
    }

商品信息展示

業務需求說明

當用戶點擊商品時應該跳轉到商品的展示頁面,在頁面中應該展示2部分數據.item數據/itemDesc數據. item.jsp頁面
數據取值方式:
1.獲取item信息 ${item.title }
2.獲取ItemDesc數據 ${itemDesc.itemDesc}

重構JT-MANAGE

編輯ItemService

在這裏插入圖片描述

編輯YML配置

server:
  port: 8091
  servlet:
    context-path: /    #在根目錄中發佈  缺省值.
spring:
  datasource:
    #引入druid數據源
    #type: com.alibaba.druid.pool.DruidDataSource
    #driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp
#mybatis-plush配置
mybatis-plus:
  type-aliases-package: com.jt.pojo
  mapper-locations: classpath:/mybatis/mappers/*.xml
  configuration:
    map-underscore-to-camel-case: true

logging:
  level: 
    com.jt.mapper: debug

#配置manage Dubbo服務
dubbo:
  scan:
    basePackages: com.jt    #指定dubbo的包路徑
  application:              #應用名稱
    name: provider-item     #一個接口對應一個服務名稱
  registry:
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
  protocol:  #指定協議
    name: dubbo  #使用dubbo協議(tcp-ip)  web-controller直接調用sso-Service
    port: 20881  #每個服務都有本身特定的端口 不能重複.

實現頁面跳轉

頁面URL分析

在這裏插入圖片描述

編輯ItemController

package com.jt.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import com.jt.service.DubboItemService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.xml.ws.RequestWrapper;

@Controller
public class ItemController {

    @Reference(check = false)
    private DubboItemService itemService;

    /**
     * 實現商品的展示
     * url:     http://www.jt.com/items/562379.html
     * 參數:     562379商品ID號
     * 返回值:   item.jsp
     * 頁面取值:    item對象/itemDesc對象
     *          {item.id/title}
     */
    @RequestMapping("/items/{itemId}")
    public String findItemById(@PathVariable Long itemId, Model model){

        Item item = itemService.findItemById(itemId);
        ItemDesc itemDesc = itemService.findItemDescById(itemId);
        model.addAttribute("item",item);
        model.addAttribute("itemDesc",itemDesc);
        return "item";
    }

}

編輯ItemService

package com.jt.web.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.ItemDescMapper;
import com.jt.mapper.ItemMapper;
import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import com.jt.service.DubboItemService;
import org.springframework.beans.factory.annotation.Autowired;

@Service(timeout = 3000)
public class DubboItemServiceImpl implements DubboItemService {

    @Autowired
    private ItemMapper itemMapper;
    @Autowired
    private ItemDescMapper itemDescMapper;

    @Override
    public Item findItemById(Long itemId) {

        return itemMapper.selectById(itemId);
    }

    @Override
    public ItemDesc findItemDescById(Long itemId) {

        return itemDescMapper.selectById(itemId);
    }
}

頁面效果展示

在這裏插入圖片描述

相關文章
相關標籤/搜索