2022版Maven教程 - 第八章 微服务架构案例

2022版Maven教程 - 第八章 微服务架构案例

视频连接
资料连接


一、创建工程

1、创建工程

工程名地位说明
pro07-demo-imperial-court-micro-service父工程总体管理各个子工程
demo01-imperial-court-gateway子工程网关
demo02-user-auth-center子工程用户中心
demo03-emp-manager-center子工程员工数据维护中心
demo04-memorials-manager-center子工程奏折数据维护中心
demo05-working-manager-center子工程批阅奏折工作中心
demo06-mysql-data-provider子工程MySQL 数据提供者
demo07-redis-data-provider子工程Redis 数据提供者
demo08-base-api子工程声明 Feign 接口
demo09-base-entity子工程实体类
demo10-base-util子工程工具类

在这里插入图片描述


2、建立工程间依赖关系

在这里插入图片描述

项目demo02-user-auth-center工程依赖:demo08-base-ap工程

在这里插入图片描述

    <dependencies>
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>demo08-base-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

项目demo08-base-api工程依赖:demo09-base-entity工程 和 demo10-base-util工程
在这里插入图片描述

    <dependencies>
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>demo09-base-entity</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>demo10-base-util</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

项目demo06-mysql-data-provider工程依赖:demo09-base-entity工程 和 demo10-base-util工程

在这里插入图片描述

    <dependencies>
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>demo09-base-entity</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>demo10-base-util</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>



二、父工程管理依赖

在这里插入图片描述

<dependencyManagement>
    <dependencies>

        <!-- SpringCloud 依赖导入 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR9</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!-- SpringCloud Alibaba 依赖导入 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.6.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!-- SpringBoot 依赖导入 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.3.6.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!-- 通用 Mapper 依赖 -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.1.5</version>
        </dependency>

        <!-- Druid 数据源依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

        <!-- JPA 依赖 -->
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>



三、打基础

1、demo10-base-util

①ImperialCourtConst 常量类

package com.atguigu.imperial.court.util;

public class ImperialCourtConst {
    public static final String LOGIN_FAILED_MESSAGE = "账号、密码错误,不可进宫!";
    public static final String ACCESS_DENIED_MESSAGE = "宫闱禁地,不得擅入!";
    public static final String LOGIN_EMP_ATTR_NAME = "loginInfo";
}

②字符串加密工具类

package com.atguigu.imperial.court.util;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Util {

    /**
     * 针对明文字符串执行MD5加密
     * @param source
     * @return
     */
    public static String encode(String source) {
        // 1.判断明文字符串是否有效
        if (source == null || "".equals(source)) {
            throw new RuntimeException("用于加密的明文不可为空");
        }
        // 2.声明算法名称
        String algorithm = "md5";
        // 3.获取MessageDigest对象
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // 4.获取明文字符串对应的字节数组
        byte[] input = source.getBytes();
        // 5.执行加密
        byte[] output = messageDigest.digest(input);
        // 6.创建BigInteger对象
        int signum = 1;
        BigInteger bigInteger = new BigInteger(signum, output);
        // 7.按照16进制将bigInteger的值转换为字符串
        int radix = 16;
        String encoded = bigInteger.toString(radix).toUpperCase();
        return encoded;
    }
}

③登录失败异常

package com.atguigu.imperial.court.exception;

public class LoginFailedException extends RuntimeException {

    public LoginFailedException() {
    }

    public LoginFailedException(String message) {
        super(message);
    }

    public LoginFailedException(String message, Throwable cause) {
        super(message, cause);
    }

    public LoginFailedException(Throwable cause) {
        super(cause);
    }

    public LoginFailedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

④远程方法调用统一返回结果

package com.atguigu.imperial.court.util;

/**
 * 统一整个项目中远程方法调用返回的结果
 * @param <T>
 */
public class ResultEntity<T> {

    public static final String SUCCESS = "SUCCESS";
    public static final String FAILED = "FAILED";

    // 用来封装当前请求处理的结果是成功还是失败
    private String result;

    // 请求处理失败时返回的错误消息
    private String message;

    // 要返回的数据
    private T data;

    /**
     * 请求处理成功且不需要返回数据时使用的工具方法
     * @return
     */
    public static <Type> ResultEntity<Type> successWithoutData() {
        return new ResultEntity<Type>(SUCCESS, null, null);
    }

    /**
     * 请求处理成功且需要返回数据时使用的工具方法
     * @param data 要返回的数据
     * @return
     */
    public static <Type> ResultEntity<Type> successWithData(Type data) {
        return new ResultEntity<Type>(SUCCESS, null, data);
    }

    /**
     * 请求处理失败后使用的工具方法
     * @param message 失败的错误消息
     * @return
     */
    public static <Type> ResultEntity<Type> failed(String message) {
        return new ResultEntity<Type>(FAILED, message, null);
    }

    public ResultEntity() { }

    public ResultEntity(String result, String message, T data) {
        super();
        this.result = result;
        this.message = message;
        this.data = data;
    }

    @Override
    public String toString() {
        return "ResultEntity [result=" + result + ", message=" + message + ", data=" + data + "]";
    }

    public String getResult() { return result; }
    public void setResult(String result) { this.result = result; }
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    public T getData() { return data; }
    public void setData(T data) { this.data = data; }
}

2、demo09-base-entity

①引入依赖

在这里插入图片描述

    <dependencies>
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
        </dependency>
    </dependencies>

②创建实体类

MySQL 数据提供服务中用到的通用 Mapper 技术需要借助 @Table 注解将实体类和数据库表关联起来。

package com.atguigu.imperial.court.entity;

import javax.persistence.Table;
import java.io.Serializable;

@Table(name = "t_emp")
public class Emp implements Serializable {

    private Integer empId;

    private String empName;

    private String empPosition;

    private String loginAccount;

    private String loginPassword;

    public Integer getEmpId() { return empId; }
    public void setEmpId(Integer empId) { this.empId = empId; }
    public String getEmpName() { return empName; }
    public void setEmpName(String empName) { this.empName = empName == null ? null : empName.trim(); }
    public String getEmpPosition() { return empPosition; }
    public void setEmpPosition(String empPosition) { this.empPosition = empPosition == null ? null : empPosition.trim(); }
    public String getLoginAccount() { return loginAccount; }
    public void setLoginAccount(String loginAccount) { this.loginAccount = loginAccount == null ? null : loginAccount.trim(); }
    public String getLoginPassword() { return loginPassword; }
    public void setLoginPassword(String loginPassword) { this.loginPassword = loginPassword == null ? null : loginPassword.trim(); }
}



四、用户登录认证服务:提供端

1、总体分析

在这里插入图片描述


2、注册中心

在本地启动 Nacos 注册中心:

d:\software\nacos\bin>startup.cmd -m standalone


3、声明接口,暴露服务

①接口文档

用户登录验证接口
接口描述
  • 传入用户名、密码,验证是否可以登录。
    • 验证成功:返回从数据库查询到的 Emp 对象。
    • 验证失败:返回错误消息。
请求URL

https://localhost:10001/remote/get/emp/by/login/info

请求方式
  • GET/POST
请求参数
参数名必选类型默认值说明
oginAccountstring登录账号
loginPasswordstring登录密码
返回示例
//成功
{
  "result":"SUCCESS",
  "message":null,
  "data":{
    "empId":1,
    "empName":"爱新觉罗·玄烨",
    "empPosition":"emperor",
    "loginAccount":"xiaoxuanzi1654",
    "loginPassword":"25325C896624D444B2E241807DCAC98B"
  }
}

//失败
{
  "result":"FAILED",
  "message":"账号、密码错误,不可进宫!",
  "data":null
}
返回参数说明
参数名类型说明可取值
resultstring远程方法调用执行结果是否成功SUCCESS:操作成功
FAILED:操作失败
messagestring远程方法调用失败时的提示消息
dataJSON有查询结果的远程方法调用成功后返回的查询结果
备注
  • 无。

② Feign 接口代码

[1]接口位置

在这里插入图片描述

[2]引入依赖
    <dependencies>
        <!-- 提供 Emp 实体类使用 -->
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>demo09-base-entity</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- 提供 ResultEntity 工具类使用 -->
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>demo10-base-util</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!-- OpenFeign 专用依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
[3]接口代码

注意@FeignClient 注解中指定的是提供服务的微服务名称,要和注册中心注册的一致

package com.atguigu.imperial.court.api;

import com.atguigu.imperial.court.entity.Emp;
import com.atguigu.imperial.court.util.ResultEntity;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

// @FeignClient 注解将当前接口标记为服务暴露接口
// name 属性:指定被暴露服务的微服务名称
@FeignClient(name = "demo06-mysql-data-provider")
public interface MySQLProvider {

    @RequestMapping("/remote/get/emp/by/login/info")
    ResultEntity<Emp> getEmpByLoginInfo(
            // @RequestParam 无论如何不能省略
            @RequestParam("loginAccount") String loginAccount,
            @RequestParam("loginPassword") String loginPassword);
}

4、实现接口

①所在工程

demo06-mysql-data-provider

在这里插入图片描述

②引入依赖

    <dependencies>
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>demo09-base-entity</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>demo10-base-util</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!-- Nacos 服务注册发现启动器 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!-- 通用mapper启动器依赖 -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
        </dependency>

        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- druid启动器依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>

        <!-- web启动器依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 编码工具包 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

        <!-- 单元测试启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
    </dependencies>

③Java 代码

[1]总体结构

在这里插入图片描述

[2]EmpMapper

继承 tk.mybatis.mapper.common.Mapper 后就可以使用通用 Mapper 提供的常规代码实现。除非有非常规需求,否则我们自己什么都不用写。

package com.imperial.court.mapper;

import com.imperial.court.entity.Emp;
import tk.mybatis.mapper.common.Mapper;

public interface EmpMapper extends Mapper<Emp> {
}
[3]Service 接口
package com.imperial.court.service.api;

import com.imperial.court.entity.Emp;

public interface EmpService {
    Emp getEmpByLoginInfo(String loginAccount, String loginPassword);
}
[4]Service 实现
package com.imperial.court.service.impl;

import com.imperial.court.entity.Emp;
import com.imperial.court.exception.LoginFailedException;
import com.imperial.court.mapper.EmpMapper;
import com.imperial.court.service.api.EmpService;
import com.imperial.court.util.ImperialCourtConst;
import com.imperial.court.util.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.List;

@Service
@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;

    @Override
    public Emp getEmpByLoginInfo(String loginAccount, String loginPassword) {
        // 执行密码加密
        String encodedLoginPassword = MD5Util.encode(loginPassword);
        // 创建 Example 对象,用于封装查询条件
        Example example = new Example(Emp.class);
        // 封装查询条件
        example.createCriteria()
                .andEqualTo("loginAccount", loginAccount)
                .andEqualTo("loginPassword", encodedLoginPassword);

        List<Emp> empList = empMapper.selectByExample(example);
        if (empList == null || empList.size() == 0) {
            throw new LoginFailedException(ImperialCourtConst.LOGIN_FAILED_MESSAGE);
        }
        return empList.get(0);
    }
}
[5]EmpController
package com.imperial.court.controller;

import com.imperial.court.entity.Emp;
import com.imperial.court.service.api.EmpService;
import com.imperial.court.util.ResultEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EmpController {

    @Autowired
    private EmpService empService;

    @RequestMapping("/remote/get/emp/by/login/info")
    ResultEntity<Emp> getEmpByLoginInfo(@RequestParam("loginAccount") String loginAccount,
                                        @RequestParam("loginPassword") String loginPassword) {
        try {
            // 1、调用 service 方法根据账号、密码查询 Emp 对象
            Emp emp = empService.getEmpByLoginInfo(loginAccount, loginPassword);
            // 2、返回成功消息
            return ResultEntity.successWithData(emp);
        } catch (Exception e) {
            e.printStackTrace();
            String message = e.getMessage();
            // 3、返回失败消息
            return ResultEntity.failed(message);
        }
    }

}
[6]主启动类
package com.imperial.court;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import tk.mybatis.spring.annotation.MapperScan;

// 为了让当前微服务对接(注册或发现服务)注册中心
@EnableDiscoveryClient
// SpringBoot 标配注解
@SpringBootApplication
// 扫描通用 Mapper 的 Mapper 接口所在包
// 这个注解全类名:tk.mybatis.spring.annotation.MapperScan
// basePackage 属性:指定要扫描的 Mapper 接口所在的包
@MapperScan(basePackages = "com.imperial.court.mapper")
public class MainType {
    public static void main(String[] args) {
        SpringApplication.run(MainType.class, args);
    }
}

④YAML 配置文件

application.yml配置文件

在这里插入图片描述

server:
  port: 10001
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/db_imperial_court?useUnicode=true&characterEncoding=utf8&serverTimezone=PRC&useSSL=false
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource
  application:
    name: demo06-mysql-data-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

启动测试:

浏览器访问:http://localhost:10001/remote/get/emp/by/login/info?loginAccount=123&loginPassword=123

在这里插入图片描述

浏览器访问:http://localhost:10001/remote/get/emp/by/login/info?loginAccount=xiaoxuanzi1654&loginPassword=16540504

在这里插入图片描述



五、用户登录认证服务:消费端

1、所在工程

demo02-user-auth-center

在这里插入图片描述


2、引入依赖

    <dependencies>
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>demo08-base-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!-- Nacos 服务注册发现启动器 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!-- web启动器依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 视图模板技术 thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

3、YAML 配置文件

application.yml配置文件

在这里插入图片描述

server:
  port: 10002
spring:
  application:
    name: demo02-user-auth-center
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

Thymeleaf 而言,有两个常用属性,但我们全部都使用的是默认值,所以可以省略。


4、显示首页

①配置 view-controller

在这里插入图片描述

package com.imperial.court.config;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@SpringBootConfiguration
public class MyMVCConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }
}

②Thymeleaf 视图模板页面

在这里插入图片描述

<!DOCTYPE html>
<html lang="en" xml:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>

<form th:action="@{/consumer/do/login}" method="post">
    <p style="color: red;font-weight: bold;" th:if="${not #strings.isEmpty(message)}" th:text="${message}">
        这里根据条件显示登录失败消息</p>
    <p style="color: red;font-weight: bold;" th:if="${not #strings.isEmpty(systemMessage)}" th:text="${systemMessage}">
        这里根据条件显示系统消息</p>
    账号:<input type="text" name="loginAccount"/><br/>
    密码:<input type="password" name="loginPassword"><br/>
    <button type="submit">进宫</button>
</form>
</body>
</html>

测试;
http://localhost:10002/

在这里插入图片描述


5、登录验证

①流程图

在这里插入图片描述

②主启动类

注意:一定要标记 @EnableFeignClients 注解。

在这里插入图片描述

package com.imperial.court;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class MainType {
    public static void main(String[] args) {
        SpringApplication.run(MainType.class, args);
    }
}

③AuthController

[1]装配远程接口分析
package com.imperial.court.controller;

import com.imperial.court.api.MySQLProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class AuthController {

    // 1、本地使用 @Autowired 注解装配远程接口类型即可实现方法的远程调用,
    // 看起来就像是调用本地方法一样,我们管这种特性叫方法的声明式远程调用。
    // 2、凭啥通过 @Autowired 注解就能够导入远程接口对应的 bean
    //      ①当前环境包含 Feign 相关 jar 包。
    //      ②当前微服务的主启动类上标记 @EnableFeignClients
    //      ③符合 SpringBoot 自动扫描包的约定规则:默认情况下主启动类所在的包、以及主启动类所在包的子包都会被自动扫描
    //          主启动类所在包:      com.imperial.court
    //          被扫描的接口所在的包: com.imperial.court.api
    @Autowired
    private MySQLProvider mySQLProvider;

}

示意图:
在这里插入图片描述

[2]执行登录验证的方法
@Controller
public class AuthController {

    //...
    @Autowired
    private MySQLProvider mySQLProvider;

    @RequestMapping("/consumer/do/login")
    public String doLogin(@RequestParam("loginAccount") String loginAccount,
                          @RequestParam("loginPassword") String loginPassword, HttpSession session, Model model) {
        // 1、调用远程接口根据登录账号、密码查询 Emp 对象
        ResultEntity<Emp> resultEntity = mySQLProvider.getEmpByLoginInfo(loginAccount, loginPassword);
        // 2、验证远程接口调用是否成功
        String result = resultEntity.getResult();
        if ("SUCCESS".equals(result)) {
            // 3、从 ResultEntity 中获取查询得到的 Emp 对象
            Emp emp = resultEntity.getData();
            // 4、将 Emp 对象存入 Session 域
            session.setAttribute("loginInfo", emp);
            // 5、前往 target 页面
            return "target";
        } else {
            // 6、获取失败消息
            String message = resultEntity.getMessage();
            // 7、将失败消息存入模型
            model.addAttribute("message", message);
            // 8、回到登录页面
            return "index";
        }
    }
}
[3]验证测试

准备target.html页面

在这里插入图片描述

<!DOCTYPE html>
<html lang="en" xml:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录成功</title>
</head>
<body>

<p th:text="${session.loginInfo}"></p>

</body>
</html>

访问:http://localhost:10002/

在这里插入图片描述
失败:
在这里插入图片描述

成功:【注意:代码的 Emp实体没有加 toString方法】

在这里插入图片描述



六、部署运行

1、最终目标

在这里插入图片描述


2、微服务打包

①修改 MySQL 连接信息

在这里插入图片描述

server:
  port: 10001
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db_imperial_court?useUnicode=true&characterEncoding=utf8&serverTimezone=PRC&useSSL=false
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource
  application:
    name: demo06-mysql-data-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

②在父工程执行 install 命令

[1]Why parent?工程间关系梳理

正确的安装顺序:

  • ①父工程:pro07-demo-imperial-court-micro-service
  • ②被依赖的 module:demo10-base-util demo09-base-entity
  • ③当前 module:demo06-mysql-data-provider

在这里插入图片描述

[2]执行命令

mvn clean install -Dmaven.test.skip=true

③生成微服务可运行 jar 包

[1]应用微服务打包插件

可以以 SpringBoot 微服务形式直接运行的jar包包括:

  • 当前微服务本身代码
  • 当前微服务所依赖的 jar 包
  • 内置 TomcatServlet 容器)
  • jar 包可以通过 java -jar 方式直接启动相关的配置

要加入额外的资源、相关配置等等,仅靠 Maven 自身的构建能力是不够的,所以要通过build标签引入下面的插件。

<!-- build 标签:用来配置对构建过程的定制 -->
<build>
    <!-- plugins 标签:定制化构建过程中所使用到的插件 -->
	<plugins>
        <!-- plugin 标签:一个具体插件 -->
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>

加入这个插件后的效果:
在这里插入图片描述
提示:IDEA 对于我们这里 build 标签里加入的 plugin 的配置没有能够很好的识别到插件的版本。如果我们能够保证其它操作都正常执行完成,准备工作都准备好了,那么这里我们判定是 IDEA 识别能力不足导致。一切以实际执行的结果为准:运行结果是最高权威

请对 demo02-user-auth-centerdemo06-mysql-data-provider 都添加上面的 build 配置。

[2]执行插件目标

请对 demo02-user-auth-centerdemo06-mysql-data-provider 目录下(有带pom文件的目录)都执行下面的命令:

  • clean 子命令:清理之前构建的结果
  • package 子命令:我们真正要调用的 spring-boot:repackage 要求必须将当前微服务本身的 jar 包提前准备好,所以必须在它之前执行package子命令。
  • spring-boot:repackage 子命令:调用 spring-boot 插件的 repackage 目标
  • -Dmaven.test.skip=true 参数:跳过测试

mvn clean package spring-boot:repackage -Dmaven.test.skip=true


3、执行部署

①启动 Nacos

sh /opt/nacos/bin/startup.sh -m standalone

②上传微服务 jar 包

/opt/maven/目录下

②启动微服务

nohup java -jar demo06-mysql-data-provider-1.0-SNAPSHOT.jar>demo06.log 2>&1 &
nohup java -jar demo02-user-auth-center-1.0-SNAPSHOT.jar>demo02.log 2>&1 &

nohup命令详解
1、提出问题

我们把一个 SpringBoot 工程导出为jar包,jar 包上传到阿里云 ECS 服务器上,使用 java -jar xxx-xxx.jar 命令启动这个 SpringBoot 程序。此时我们本地的 xshell 客户端必须一直开着,一旦 xshell 客户端关闭,java -jar xxx-xxx.jar 进程就会被结束,SpringBoot 程序就访问不了了。

所以我们希望启动 SpringBootjar 包之后,对应的进程可以一直运行,不会因为 xshell 客户端关闭而被结束。

在这里插入图片描述

2、解决方案
1)前台、后台运行

默认情况下 Linux 命令都是前台运行的,前台运行的特点是前面命令不执行完,命令行就一直被前面的命令占用,不能再输入、执行新的命令

#!/bin/bash
echo "hello before sleep"
sleep 20
echo "hello after sleep"

前台(默认情况)运行上面脚本的效果是:

在这里插入图片描述

后台运行上面脚本的效果是:

在这里插入图片描述

但是以后台方式运行并不能解决前面提出的问题:我们的 shell 客户端(例如:xshell)和服务器断开连接后,SpringBoot 进程会随之结束,这显然不满足我们部署运行项目的初衷。

2)不挂断运行

所谓“不挂断”就是指客户端断开连接后,命令启动的进程仍然运行。nohup 命令就是 ”no hang up“ 的缩写。使用nohup 命令启动 SpringBoot 微服务工程的完整写法是:

nohup java -jar spring-boot-demo.jar>springboot.log 2>&1 &

在这里插入图片描述

③测试

在这里插入图片描述

访问:http://192.168.37.132:10002/

在这里插入图片描述

demo参考网上资料,使用mvn建项,使用者需要有一定mvn基础。 demo没有实现复杂业务,只实现了部分功能: 微服务模块初始化时,常量和数据库信息等使用云配置服务(spring config)获取; 微服务之间使用负载均衡(ribbon); 微服务网关路由配置; 微服务断路器(hystrix)及监听服务等 启动步骤: 1.启动server-eureka,端口6600,微服务注册中心 访问http://localhost:6600,查看效果 2.启动server-config,端口6700,统一配置服务中心 访问http://localhost:6700/service-order/online,查看效果 3.启动service-order,端口6002,初始化使用配置服务server-config动态加载数据库 访问http://localhost:6002/order,查看效果 4.启动service-user,端口6001,使用注册后的服务名service-order进行服务之间调用,避免传统维护困难的ip:port方式 模块中使用了ribbon负载均衡请求service-order,需要启动至少两个service-order服务 访问http://localhost:6001/user/order,查看效果 5.启动gateway-zuul,端口6000,用于url路由配置,服务统一端口入口 http://localhost:6000/service-order/order等效于访问http://localhost:6002/order http://localhost:6000/service-user/user/order等效于访问http://localhost:6001/user/order 6.启动hystrix-dashboard,端口6500,可选,WEB界面查看监听服务,如服务成功多少,失败多少等信息 进入hystrix-dashboard界面后,填入监控地址:http://localhost:6001/hystrix.stream
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值