Spring Cloud(1)

续 开发问题采纳的功能

编写显示页面的控制器

不同身份显示不同的问题详情页

老师:detail_teacher.html

学生:detail.html

我们已经将不需要由学生操作的功能从detail.html页面中删除了

我们找到HomeController中跳转到detail.html的方法

去修改,代码如下

 //显示问题详情页面
    @GetMapping("/question/detail.html")
    public ModelAndView detail(
            @AuthenticationPrincipal User user){
        if(user.getAuthorities().contains(STUDENT)){
            //如果是学生,跳detail.html
            return new ModelAndView("question/detail");
        }else if(user.getAuthorities().contains(TEACHER)){
            //如果是老师,跳detail_teacher.html
            return new ModelAndView(
                    "question/detail_teacher");
        }
        return null;
    }

开发采纳答案功能

步骤1:

完成页面上采纳答案的二次确认效果

在点击采纳答案后,弹出二次确认的按钮

detail.html页面的采纳答案链接修改为:

<a class="btn btn-primary mx-2 text-white"
                         style="cursor: pointer"
                          onclick="$(this).next().toggle(200)"
                          >采纳答案</a>
                      <a class="text-white badge badge-pill badge-success"
                         style="display: none; cursor: pointer"
                         @click="answerSolved(answer.id,answer)"
                      >
                        <i class="fa fa-check-square"></i>
                      </a>

步骤2:

编写js文件

在question_detail.js文件的answersApp中编写方法,代码如下

//问题采纳
        answerSolved: function (answerId, answer) {
            if (!answerId) {
                return;
            }
            //判断这个问题是否已经被采纳
            if (answer.acceptStatus == 1) {
                alert("此问题已经被采纳")
                return;
            }
            $.ajax({
                url: "/v1/answers/" + answerId + "/solved",
                method: "get",
                success: function (r) {
                   console.log(r);
                   if(r.code==ACCEPTED){
                       answer.acceptStatus=1;
                   }else{
                       alert(r.message);
                   }
                }
            });

        }

步骤3:

开始编写控制器的接收

AnswerController类中添加方法代码如下

@GetMapping("/{id}/solved")
    public R solved(
            @PathVariable Integer id){
        log.debug("收到参数:{}",id);
        return  R.accepted("采纳成功!");
    }

步骤4:

开发数据访问层和业务逻辑层

首先明确采纳业务的数据库操作

修改answer表中accept_status 列的值为1

修改question表中status列的值为2

一个业务有两个修改操作,需要事务的支持

先来编写数据访问层的代码

AnswerMapper接口中添加修改accept_status列的方法

@Update("update answer set accept_status=#{status}" +
                " where id=#{answerId}")
        int updateStatus(@Param("answerId") Integer answerId,
                         @Param("status") Integer acceptStatus);

QuestionMapper中添加修改问题状态的方法

@Update("update question set status=#{status} " +
            " where id=#{questionId}")
    int updateStatus(@Param("questionId") Integer questionId,
                     @Param("status") Integer status);

推荐大家去测试一下代码运行的效果

步骤5:

推荐在Question实体类中添加问题状态的常量,以便调用和表示

public class Question implements Serializable {

    private static final long serialVersionUID = 1L;

    //定义问题状态的常量
    public static final Integer POSTED=0; //已添加/未回复
    public static final Integer SOLVING=1;//正在采纳/已回复
    public static final Integer SOLVED=2; //已经采纳/已解决
 	//..其它代码略   
}    

步骤6:

编写业务逻辑层

IAnswerService接口中添加方法

 //采纳答案的方法
 boolean accept(Integer answerId);

AnswerServiceImpl实现类中方法的代码如下

@Resource
    private QuestionMapper questionMapper;
    @Override
    @Transactional
    public boolean accept(Integer answerId) {
        //查询当前要采纳的answer对象
        Answer answer=answerMapper.selectById(answerId);
        //判断这个answer是不是已经被采纳
        if(answer.getAcceptStatus()==1){
            //如果已经被采纳返回false
            return false;
        }
        //开始执行采纳业务
        answer.setAcceptStatus(1);
        int num=answerMapper.updateStatus(answerId
                ,answer.getAcceptStatus());
        if(num!=1){
            throw ServiceException.busy();
        }
        //修改问题状态为已解决
        num=questionMapper.updateStatus(answer.getQuestId(),
                Question.SOLVED);
        if(num!=1){
            throw ServiceException.busy();
        }
        return true;
    }

推荐测试一下

步骤7:重构控制层代码

@GetMapping("/{id}/solved")
    public R solved(
            @PathVariable Integer id){
        log.debug("收到参数:{}",id);
        boolean accepted=answerService.accept(id);
        if(accepted) {
            return R.accepted("采纳成功!");
        }else{
            return R.notFound("不能重复采纳答案");
        }
    }

微服务项目结构准备

将现在项目中的pom.xml文件进行重构

重构后的结构为:如图所示

在这里插入图片描述

这样的结构方便后续微服务项目搭建,减少pom.xml文件中依赖的冗余

微服务

什么是微服务

2014年马丁.福勒(Martin Fowler),提出了微服务的概念

每个项目应该有自己最小的行程,和轻量化处理

项目与项目之间

使用Http协议通信,可以实现不同编程语言和不同数据库的互通

为什么需要微服务

下面通过一个生活中的案例,来了解微服务的特性

在这里插入图片描述

微服务的好处

1.添加和维护服务器方便,对项目整体影响最小化

2.某单一业务的繁忙,不会影响其他业务

3.更适合要求高并发,高可用,高性能的互联网项目使用

微服务结构

如图

在这里插入图片描述

什么是SpringCloud

我们自己实现微服务的系统搭建是非常麻烦的

只能使用框架提供的现成的结构

常见的微服务的框架有SpringCloud\Dubbo

我们学习SpringCloud,它解决的主要问题有

  • API Gateway 网关

  • 服务间调用

  • 服务的发现

  • 服务部署

  • 服务容错

  • 数据调用

    SpringCloud提供了一整套微服务的解决方法,大大的降低了项目使用微服务架构的门槛

    同时降低了微服务的开发成本

    SpringCloud不是一个特定框架,而是一系列程序框架或组件的组合

    使微服务项目开发起来非常简单

    在这里插入图片描述

Eureka 注册中心概述

Eureka就是SpringCloud提供的注册中心

相当于一个家酒店的前台

酒店中可以入住或已经入住的房价信息,都会在前台保存,并可以查询到

当有新顾客前来访问时,可以迅速登记入住

在这里插入图片描述

在计算机的世界里变为下图

在这里插入图片描述

上面的图中有两个概念

除了注册中心之外还有

服务消费者和服务提供者的概念

两个微服务互相调用,谁主动调用谁是服务的消费者,谁被调用谁是服务的提供者

而注册中心提供了服务列表,列表上有各个服务器能提供的服务,当有服务消费者出现时

可以通过这个列表快速找到合适的服务

创建Eureka项目

再创建一个子项目

这个子项目就是Eureka注册中心

在这里插入图片描述

将新创建的子项目中pom.xml文件中的dependencyManagement标签中的内容

和properties中的内容都复制到父项目中

最终的父项目的pom.xml文件为:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>cn.tedu</groupId>
    <artifactId>straw</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>straw</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <mybatis.plus.version>3.3.1</mybatis.plus.version>
        <pagehelper.starter.version>1.3.0</pagehelper.starter.version>
        <straw.commons.version>0.0.1-SNAPSHOT</straw.commons.version>
        <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
    </properties>

    <packaging>pom</packaging>

    <modules>
        <module>straw-portal</module>
        <module>straw-generator</module>
        <module>straw-resource</module>
        <module>straw-kafka</module>
        <module>straw-commons</module>
        <module>straw-search</module>
        <module>straw-eureka</module>
    </modules>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>cn.tedu</groupId>
                <artifactId>straw-commons</artifactId>
                <version>${straw.commons.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis.plus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-extension</artifactId>
                <version>${mybatis.plus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-generator</artifactId>
                <version>${mybatis.plus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>${pagehelper.starter.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

最终的子项目pom.xml文件为:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.tedu</groupId>
        <artifactId>straw</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>straw-eureka-center</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>straw-eureka-center</name>
    <description>Demo project for Spring Boot</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>
              spring-cloud-starter-netflix-eureka-server
            </artifactId>
        </dependency>
    </dependencies>

</project>

全部复制完毕后进行刷新操作

配置Eureka的启动信息

application.properties

# Eureka服务器端的默认端口是8761,所以,推荐将当前项目的端口设置为8761,则其它各Eureka客户端可以简化配置
server.port=8761

# 每个Eureka Server其实也是一个Eureka Client,默认情况下,也会自行注册
# 以下配置表示“不要注册自己”
eureka.client.register-with-eureka=false

# 由于以上配置了“不要注册自己”,就更“不要抓取注册表”
eureka.client.fetch-registry=false

在SpringBoot的运行类中,添加注解

@EnableEurekaServer代码如下

@SpringBootApplication
@EnableEurekaServer
public class StrawEurekaApplication {

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

}

然后就可以运行这个main方法然后访问

localhost:8761来验证eureka的运行状态

如果能看到页面,证明运行正常

注册EurekaClient

我们现成有个子项目就是straw-resource它可以充当Eureka的客户端进行运行测试

在straw-resource的pom.xml文件中添加客户端的依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>

配置完xml文件之后

每个微服务都有自己的名称

要配置当前微服务的名字

也是配置application.properties添加如下内容

#设置微服务的名字
spring.application.name=resource-server
#如果Eureka的端口不是8761,则下面的配置必须编写
#如果是8761,可以省略
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

如果Eureka的端口是8761可以跳过上面的步骤

在main方法的类上添加注解

@EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class StrawResourceApplication {

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

}

Eureka常见名称解释

在这里插入图片描述

注册:(registry)

EurekaClient会想EurekaServer提交注册信息

包括实例名,主机地址,端口号

抓取:(fetch)

EurekaServer会整理出一个注册表,注册表中包含所有当前可用的服务器信息

每个EurekaClient在注册之后会立即抓取这个注册表,并缓存到本地

心跳:

心跳是一个周期操作

默认每30秒会向EurekaServer发出续订信息

表示"我"还好好活着

Eureka 集群

所谓集群其实就是多台服务器做同样的事情

当我们的项目需要多个Eureka服务器才能保证运行时

我们就可以搭建Eureka 集群来解决

Eureka 集群的本质就是多个EurekaServer的微服务项目

搭建步骤

  1. 每个EurekaServer要有不同的端口号

  2. 编写配置:application.properties文件中

    1号项目的配置

    server.port=8761
    
    spring.application.name=eureka1
    
    eureka.client.service-url.defaultZone=http://localhost:8762/eureka, http://localhost:8763/eureka
    eureka.client.register-with-eureka=true
    eureka.client.fetch-registry=true
    

    2号项目的配置

    server.port=8762
    
    spring.application.name=eureka2
    
    eureka.client.service-url.defaultZone=http://localhost:8761/eureka, http://localhost:8763/eureka
    eureka.client.register-with-eureka=true
    eureka.client.fetch-registry=true
    

    3号项目的配置

    server.port=8763
    
    spring.application.name=eureka3
    
    eureka.client.service-url.defaultZone=http://localhost:8761/eureka, http://localhost:8762/eureka
    eureka.client.register-with-eureka=true
    eureka.client.fetch-registry=true
    

    Eureka自我保护机制

    在这里插入图片描述

    当出现图片中的红色文字时表示开启了自我保护机制

    英文大意为:

    注意!Eureka可能错误将某些已经下线的实例声明为在线,为了安全起见,由于续订比例尚且低于阈值,因此这些实例并不会声明为过期.

    出现自我保护机制的原理是EurekaServer在运行期间统计"丢失心跳比例"

    如果出现任何连续3次心跳续订失败EurekaClient,都会被认为是异常终止

    15分钟内,超过85%的EurekaClient都死了,就会开启自我保护机制

    Zuul网关

    什么是网关

    就是一个项目对外提供的一个统一入口

    因为每个服务器都有不同的ip地址或端口号

    但是用户访问网站时,确是通过同一个地址访问的,这个地址实际上就是网关

    为什么需要网关

    因为统一的入口能够方便用户访问,同时隐藏服务器真是的ip和端口号,也有助于安全

    使用SpringCloud提供的Zuul组件实现网关项目

    它的功能主要包括

    1. 动态路由
    2. 洞察于监控
    3. 身份验证与安全控制
    4. 其它…

    创建一个网关项目

    创建一个子项目straw-gateway

    没有其它注意事项,注意依赖的勾选即可

    在这里插入图片描述

    修改pom.xml文件如下

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>cn.tedu</groupId>
            <artifactId>straw</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>cn.tedu</groupId>
        <artifactId>straw-gateway</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>straw-gateway</name>
        <description>Demo project for Spring Boot</description>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
        </dependencies>
    
    </project>
    

    application.properties

    server.port=9000
    
    #给当前实例起名
    spring.application.name=gateway
    
    #设置动态路由routes.后面的名字是自己起的
    #path指定一个路径,在有请求访问这个路径时开始路由
    zuul.routes.resource.path=/resource/**
    #routes.跟的名字和上面的配置必须一致
    #service-id跟的必须是已经存在的微服务实例名
    zuul.routes.resource.service-id=resource-server
    
    

    主方法类上添加注解

   package cn.tedu.straw.gateway;
   
   @SpringBootApplication
   @EnableZuulProxy
   public class StrawGatewayApplication {
   
       public static void main(String[] args) {
           SpringApplication.run(StrawGatewayApplication.class, args);
       }
   
   }

随笔

什么是敏捷软件开发

传统开发模式是先准备,再行动

敏捷开发是发现问题解决问题,出现什么需求就解决什么需求

敏捷开发有准备时间短,实现效率高等优点,

​ 但是由于开发思想就是不断迭代完善,所以可能会频繁的维护和修改代码,很费心力

什么是互联网项目

互联网项目顾名思义就是任何人都可以通过internet访问的项目

一般项目指一个公司内部使用的局域网系统

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值