Spring cloud实战 从零开始一个简单搜索网站(四)

上篇用了2个方法来来做断路由,太蛋疼了  Spring Cloud集成的是javanica hystrix 虽然集成方便了很多,不过

javanica默认好像不支持 动态修改 commandKey , Hystrix是根据commandKey来分配每个熔断器的  网上也有些解决办法

不过感觉还是太蛋疼了  算了 还是直接用Hystrix好了


先把javanica hystrix的引用换成 hystrix core

            <dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-core</artifactId>
    </dependency>

POM配置

<?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>tsearch_web</groupId>
    <artifactId>springtest-client</artifactId>
    <version>0.0.1</version>
    <packaging>jar</packaging>

    <name>springtest-client</name>
    <description>Note Server catch</description>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.M3</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 断路由 -->
            <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
            <dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-core</artifactId>
    </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

Application 需要把断路由注解去掉 不然会报Caused by: java.lang.NoClassDefFoundError: com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCommandAspect

@EnableEurekaClient
@SpringBootApplication
@EnableHystrixDashboard
public class SpringtestClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringtestClientApplication.class, args);
    }
    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

package com.springtest.client;

import org.springframework.web.client.RestTemplate;

public class SearchEntity {
    public String key;
    public String page;
    public String  serviceId;
    RestTemplate restTemplate;
    public String url;

    public SearchEntity(String key,String page,String serviceId) {
        this.key = key;
        this.page = page;
        this.serviceId = serviceId;
    }

    public SearchEntity url(String url) {
        this.url = url;
        return this;
    }
    public SearchEntity restTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
        return this;
    }
}

SearchEntity

这里新加了一个 SearchHystrix

package com.springtest.client;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;

public class SearchHystrix extends HystrixCommand<String>{
private SearchEntity mSearchEntity;
private SearchMethodListener smListener;
public SearchHystrix(SearchEntity entity,SearchMethodListener smListener) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(entity.serviceId))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withCircuitBreakerRequestVolumeThreshold(5)
.withCircuitBreakerSleepWindowInMilliseconds(10000))
.andCommandKey(HystrixCommandKey.Factory.asKey(entity.serviceId)));
this.mSearchEntity = entity;
this.smListener = smListener;
}

@Override
protected String run() throws Exception {
// TODO Auto-generated method stub
if(smListener!=null) {
return smListener.onSearch(mSearchEntity);
}
return null;
}

public interface SearchMethodListener{
public String onSearch(SearchEntity entity);
}

@Override
protected String getFallback() {
// TODO Auto-generated method stub
return "error:"+mSearchEntity.serviceId;
}
}

Group key 不用管 默认DEMO都自带的

withCircuitBreakerRequestVolumeThreshold  这个是报错多少次后垄断 为了测试方便 可以改小一点 用脚本测的话最好弄个sleep(50)不然这个数据会不准
withCircuitBreakerSleepWindowInMilliseconds 这个是垄断多久后恢复, 默认好像是恢复一次  比如你出错了5次 等10秒后 恢复  又出错了一次  又会垄断修改下ClientService

@Service
public class ClientService implements SearchMethodListener{
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    private EurekaClient discoveryClient;

    @Value("${serviceIds}")
    public String serviceIds;

    public String search(String key, String page) {
        StringBuffer sb = new StringBuffer();
        if (serviceIds.contains(",")) {
            String[] ids = serviceIds.split(",");
            for(int i=0;i<ids.length;i++) {
                String res = new SearchHystrix(new SearchEntity(key, page, ids[i]),this).execute();
                sb.append(res);
            }
        }
        else {
            String res = new SearchHystrix(new SearchEntity(key, page, serviceIds),this).execute();
            sb.append(res);
        }
        return sb.toString();
    }

    @Override
    public String onSearch(SearchEntity entity) {
        // TODO Auto-generated method stub
        HashMap<String, String> map = new HashMap<>();
        map.put("key", entity.key);
        map.put("page", entity.page);
        String str = restTemplate.getForObject(serviceUrl(entity.serviceId) + "/search?key={key}&page={page}", String.class,
                map);
        return str;
    }

    public String serviceUrl(String serviceId) {
        InstanceInfo instance = discoveryClient.getNextServerFromEureka(serviceId, false);
        return instance.getHomePageUrl();
    }

    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

现在就算配置100个搜索端也不用改代码了    因为resttemplete默认是实例化当前类的   所以我把他放在这里做了个回调

两个搜索端还是一样  CSDN 端弄个sleep 5 秒   SDN 正常 重启下Client

测试脚本

package com.lin.search;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class TestHystic {
    public static void main(String[]  args) {
        long time1=System.currentTimeMillis();
        String b ="";

        for(int i=0;i<100;i++) {
            try {
                getData();
                System.out.println("usertime="+(System.currentTimeMillis()-time1));
                time1=System.currentTimeMillis();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public static  void  getData() throws Exception {
        URL serverUrl = new URL("http://localhost:8881/search?key=spring&page=1");
        HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();
        InputStream in = conn.getInputStream();
        BufferedReader br =new BufferedReader(new InputStreamReader(in, "UTF-8"));
       StringBuffer sb= new StringBuffer();
       String line;
        while((line=br.readLine())!=null) {
            sb.append(line);
        }
        System.out.println(sb.toString());
        in.close();
    }
}

从等待时间 可以看到 CSDN 方法执行了6次后 后面开始垄断 不执行了
hystrix dashboard不用改 http://localhost:8881/hystrix/monitor?stream=http%3A%2F%2Flocalhost%3A8881%2Fhystrix.stream

 

断路由这里差不多结束了 ,把2个CSDN  和SDN 改成正常返回数据

SDN

@RestController
public class CsdnController {
    Gson gson = new Gson();

    @RequestMapping(value = "/search")
    public String search(@RequestParam("key") String key, @RequestParam("page") String page) {
        System.out.println("search");
        ArrayList<HashMap<String, String>> result;
        try {
            result = SearchUtil.search(key, "discuss", page);
            return gson.toJson(result);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

CSDN

@RestController
public class CsdnController {
    Gson gson = new Gson();

    @RequestMapping(value = "/search")
    public String search(@RequestParam("key") String key, @RequestParam("page") String page) {
        System.out.println("search");
        ArrayList<HashMap<String, String>> result;
        try {
            key = key.trim().replaceAll("\\s+" , "+");
            result = SearchUtil.search(key, "blog", page);
            return gson.toJson(result);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

这里还是有区别的  一个是讨论 一个是博客

修改下ClientService 两个JSON 做下拼接

@Service
public class ClientService implements SearchMethodListener{
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    private EurekaClient discoveryClient;

    @Value("${serviceIds}")
    public String serviceIds;

    public String search(String key, String page) {
        StringBuffer sb = new StringBuffer();
        if (serviceIds.contains(",")) {
            String[] ids = serviceIds.split(",");
            for(int i=0;i<ids.length;i++) {
                String res = new SearchHystrix(new SearchEntity(key, page, ids[i]),this).execute();
                int l=sb.length();
                sb.append(res);
                if(l>0) {
                    sb.replace(l-1, l+1, ",");
                }
            }
        }
        else {
            String res = new SearchHystrix(new SearchEntity(key, page, serviceIds),this).execute();
            sb.append(res);
        }
        System.out.println(sb.toString());
        return sb.toString();
    }

    @Override
    public String onSearch(SearchEntity entity) {
        // TODO Auto-generated method stub
        HashMap<String, String> map = new HashMap<>();
        map.put("key", entity.key);
        map.put("page", entity.page);
        String str = restTemplate.getForObject(serviceUrl(entity.serviceId) + "/search?key={key}&page={page}", String.class,
                map);
        return str;
    }

    public String serviceUrl(String serviceId) {
        InstanceInfo instance = discoveryClient.getNextServerFromEureka(serviceId, false);
        return instance.getHomePageUrl();
    }

    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

修改下Client项目下的 index.ftl 这里加了个自动分页是不是很高大上

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            .searchBtn{
                background-color:#38f;
                color:#fff;
                font-size: 16px;
                padding-top: 0px;
                width: 80px;
                height: 34px;
                vertical-align: middle;
                padding: 0;
                border: 0;
            }
        .searchBtn:hover {
            background-color: #3171f3;
        }
        .searchBtn:active {
            background-color: #2964bb;
        }
            .searchSpan{
                padding-left: 10px;
                padding-right: 10px;
                margin-top: 0px;
                margin-bottom: 0px;
                border-color: #b8b8b8;
                width: 40%;
                vertical-align: middle;
                display: inline-block;
                height: 34px;
                border: 1px solid #b6b6b6;
            }
                .searchText{
                font-size: 16px;
                width: 100%;
                margin-top: 5px;
                    outline: 0;
                border: 0;
            }

        dt{
            margin: 0px;
            padding: 0px;
            font-size: 16px;
            color: #303030;
            line-height: 24px;
            margin-top: 20px;
        }
        dd{
            margin: 0px;
            padding: 0px;
            font-size: 14px;
            line-height: 22px;
            color: #999999;

        }
        a{
            text-decoration: none;
        }
    .contentDiv{
            width: 800px;
            text-align: left;
            padding-bottom: 30px;

        }
        .contentDiv em{
            color: #CA0C16;
            font-style:normal;
        }
        .nextdiv{
      width: 50px;
      height: 50px;
          position: relative;
  }
 .next a:visited {
    text-decoration: none;
    color: #9B8878;
}
        </style>
        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js"></script>
<script >
String.prototype.replaceAll = function(s1,s2){
    return this.replace(new RegExp(s1,"gm"),s2);
}
$(document).ready(function(){
    var width =$(window).width();
    if(width<900){
        $(".searchSpan").css("width","50%")
        $(".searchBtn").css("width","20%")
        $("#contentDiv").css("width","80%")

    }
    else{
        $(".searchSpan").css("width","600px")
        $("#contentDiv").css("width","800px")
        $(".searchBtn").css("width","80px")
        $(".searchSpan").css("margin-left","-85px")
    }

    $(‘.searchText‘).bind(‘keydown‘,function(event){
        if(event.keyCode == "13") {
            openSearch(0);
        }
    });
});

    function openSearch(state){
        if(state!=null){
               $("#contentDiv").html("");
        }
        isLoad = true;
        $.ajax({
             type: "GET",
             url: "search",
             data: {"key":$("#searchText").val(),
                 "page":p},
             dataType: "json",
             success: function(data){
                var str = "";
                   $.each(data, function(i, item){
                         str = str +"<dl><a target=‘_blank‘ href=‘"+item.link;
                         str = str+"‘><dt>";
                        str= str + item.title;
                    str=str+"</dt>";
                          str = str +"<dd>";
                        str= str + item.content;
                    str=str+"</dd></a></dl>";
                   });
                  isLoad = false;
                $("#contentDiv").append(str);
             }
         });
    }
    var p=1;
    var isLoad = false;
    $(window).scroll(function(){
             if($(window).scrollTop()> $(document).height() - $(window).height()-10){
                   if(!isLoad){
                       p++;
                       openSearch();
                   }
             }
    });

</script>
    </head>
    <body >
    <div align="center" style="margin-top: 30px;font-size: 24px;margin-left: -50px;"  >博客搜</div>
        <div align="center" style="margin-top: 20px;"  >
            <span class="searchSpan">
                <input type="text" id="searchText"
             value="spring cloud"
                class="searchText" /></span>

        <input type="submit" value="Search" id="su" class="searchBtn"
            onclick="openSearch(0)"
            ></input>
    </div>
    <div align="center">
    <div id="contentDiv" class="contentDiv" ></div>
    </div>

    </body>
</html>

前端代码不具体说了  没啥特别的

访问地址http://localhost:8881/

点击搜索 往下滑会自动分页

基础功能完成了

原文地址:https://www.cnblogs.com/dikeboy/p/10066846.html

时间: 2024-07-30 09:25:18

Spring cloud实战 从零开始一个简单搜索网站(四)的相关文章

Spring cloud实战 从零开始一个简单搜索网站(一)

效果地址http://121.40.36.198:9080/web/ 本文从建站开始,就不跟别的顺序一样要怎么开始开始的,懂java就行 我会尽量讲的详细, 首先肯定是工具的选择 ,俗话说工欲善其事,必先利其器,Eclipse 和IDEA 都可以集成Spring 插件,不过最好还是用Spring Tool suite ,它有三个版本,看个人喜好,我比较偏向eclipse 安装完后 第一步 记得把maven 改成阿里云的 软件安装完后New - Spring start Project  然后填写

Spring cloud实战 从零开始一个简单搜索网站(三)

上文已经完成了一个简单的   浏览器 到 Client 到CSDN端的通路 我们的架构是每个博客网址为一个单独的组件, 这里为了方便直接先用CSDN 那个组件复制下 我这里改成 SDN 修改下 application.properties   端口记得改 eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/spring.application.name=sdnserver.port=8983 下面是TOMCAT   

Spring Cloud实战之初级入门(四)— 利用Hystrix实现服务熔断与服务监控

目录 1.环境介绍 2.服务监控 2.1 加入依赖 2.2 修改配置文件 2.3 修改启动文件 2.4 监控服务 2.5 小结 3. 利用hystrix实现消费服务熔断 3.1 加入服务熔断 3.2 测试服务熔断 4. 利用turbine监控所有应用 4.1 创建工程 4.2 修改配置文件 4.3 修改启动文件 4.4 启动 5.一点点重要的事情 1.环境介绍 本篇文章涉及到前面文章的工程,mirco-service-provider.mirco-service-consumer以及需要另外新建

《重新定义Spring Cloud实战(许进 等著)》 高清pdf

<重新定义Spring Cloud实战> Spring Cloud中国社区出品,核心成员来自原阿里.蚂蚁金服和*金融等,BAT近10位专家力荐,内容足够广.有深度.重生产实践 ? 百度网盘链接: https://pan.baidu.com/s/1iAWBPi2J_ATTYsjzl41dnw 提取码: yhjx 内容简介 这是一本实践与理论并重.广度与深度兼顾的Spring Cloud生产实践开发指南,由SpringCloud中国社区倾力打造,作者来自阿里.蚂蚁金服.*金融等企业,本书针对Spr

spring cloud实战 1-高可用注册中心

创建父maven项目 提交代码至GitHub 创建eureka-server-1 项目搭建两种方式: 父pom中继承spring-boot-starter-parent,子pom中直接结成父pom.该方式比较方便,但子项目都是spring boot项目了. 父项目不需要继承spring-boot-starter-parent,子pom中通过使用scope = import依赖关系. 123456789101112 <dependencyManagement> <dependencies&

一个简单的网站访问过程

对于我们一个简单的网站访问,涉及到的技术: 1.用户访问浏览器时,浏览器会向服务器发出一个 HTTP 请求: 2.服务器接收到 HTTP 请求,Web Server 进行相应的初步处理,使用服务器脚本生成页面: 3.服务器脚本(利用Web Framework)调用本地和客户端传来的数据,生成页面: 4.Web Server 将生成的页面作为 HTTP 响应的 body,根据不同的处理结果生成 HTTP header,发回给客户端: 5.客户端(浏览器)接收到 HTTP 响应,通常第一个请求得到的

学生成绩管理后台第二项任务:初步建模,搭建一个简单的网站

负责人:程琳茹 合伙人:李玉婷 签约员工:闫玉荣 前言:学生成绩管理后台,看起来是一个简单的项目,但是对于我们今后的发展很重要,建设一个管理后台有很多方法,这里我们主要使用Rstudio,在之后的文章中,会详细给出我们小组完成项目的过程与遇到的问题,欢迎大家借鉴,此外,同学们要积极参与讨论. 项目步骤:1.熟悉与安装Rstudio,并且配置好R内部环境. 2.建立好文件所存放的位置与确保文档可以正常使用. 3.搭建一个简单的网站,分别分为server.R端口与ui.R端口. 4.搭建好网站后,插

3.开始使用Spring Cloud实战微服务

                 开始使用Spring Cloud实战微服务 3.1. Spring Cloud实战前提 3.1.1. 需要的技术储备 3.1.2. 使用的工具及软件版本 3.2. 服务提供者与服务消费者 3.3. 编写服务提供者 3.3.1. 手动编写项目 3.3.2. 使用Spring Initializr快速创建Spring Boot项目 3.4. 编写服务消费者 3.5. 为项目整合Spring Boot Actuator 3.6. 硬编码有哪些问题 原文地址:https

【spring cloud】导入一个新的spring boot项目作为spring cloud的一个子模块微服务,怎么做/或者 每次导入一个新的spring boot项目,IDEA不识别子module,启动类无法启动/右下角没有蓝色图标

如题:导入一个新的spring boot项目作为spring cloud的一个子模块微服务,怎么做 或者说每次导入一个新的spring boot项目,IDEA不识别,启动类无法启动,怎么解决 下面一起来走一遍这个流程: 1.将一个spring boot服务导入spring cloud中作为一个子模块 如图:这里有一个现成的spring cloud微服务集群,[如何创建一个spring cloud微服务:https://www.cnblogs.com/sxdcgaq8080/p/9035724.h