当前位置: 首页 > news >正文

分布式项目 09.服务器之间的通信和三个工具类

在这里插入图片描述
项目的结构:1.通过Nginx首先把访问首页的请求发送到前端web服务器,2.web服务器会根据请求的url中的一些细节,来把相关的请求发送到相关的服务器中,3.相关的服务器会处理业务,并且返回结果到web服务器中,最后在web服务器中去显示。

步骤:
01.在Nginx中配置首页的web服务器:(因为域名之前在hosts文件中已经配置过了,所以这次就没有配置hosts文件)
首页的配置服务器如下:

#配置前台管理服务器
server {
listen 80;
server_name www.jt.com;
location / {
#实现http请求的转发
proxy_pass http://localhost:8092;
}
}

02.在总项目jt中去再次声明一个新的子系统web服务器,专门用来处理web请求,并进行相关的分类转发。
第一步:先创建一个新的maven module
在这里插入图片描述
第二步:
写出相关项目的名称 web
打包方式是war,因为有静态资源需要管理。
在这里插入图片描述
在这里插入图片描述
第三步:在新创建的web项目中添加相关依赖:

添加总项目的common依赖,可以使用common中的工具包

<dependencies>
<dependency>
<groupId>com.jt</groupId>
<artifactId>jt-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>

插件:

<build>
<plugins>
<!--跳过测试类打包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

02.配置伪静态html页面:
以京东为例,京东的主页面有很多的html文件。但是这样子的html文件都是伪静态的html,本质上不是html文件,是开发人员为了好看做的修饰。

伪静态是相对真实静态来讲的,通常我们为了增强搜索引擎的友好面,都将文章内容生成静态页
面,但是有时为了实时的显示一些信息,或者还想运用动态脚本解决一些问题,不能用静态的方式来展示网站内容。这就损失了对搜索引擎的友好面。怎么样在两者之间找个中间方法呢,这就产生了伪静态技术。伪静态技术是指展示出来的是以html一类的静态页面形式,但其实是用ASP一类的动态脚本来处理的。
总结: 以html结尾展现的动态页面。
配置一个专门的类,用来修饰伪静态html文件。

@Configuration
public class MvcConfigurer implements WebMvcConfigurer{
//开启匹配后缀型配置 后缀任意.
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(true);
}
}

03.使用httpclient来实现服务器与服务器之间的通信

HTTP 协议是现在 Internet 上使用得最多、最重要的协议,越来越多的 Java 应用程序需要直接通过HTTP 协议来访问网络资源。虽然在 JDK 的 java net包中已经提供了访问 HTTP 协议的基本功能,但是
对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache JakartaCommon 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient。现在HttpClient最新版本为HttpClient 4.5.6(2015-09-11)。

以下列出的是 HttpClient 提供的主要的功能,要知道更多详细的功能可以参见 HttpClient 的主页。
(1)实现了所有 HTTP 的方法(GET,POST,PUT,Delete 等)
(2)支持自动转向
(3)支持 HTTPS 协议
(4)支持代理服务器等

第一步:导入依赖jar包

<!--添加httpClient jar包 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency

第二步:测试入门案例

@Test
public void doGet() throws ClientProtocolException, IOException {
HttpClient httpClient = HttpClients.createDefault();
String url = "http://www.baidu.com";
HttpGet get = new HttpGet(url);
HttpResponse response = httpClient.execute(get);
if(200 == response.getStatusLine().getStatusCode()) {
System.out.println("请求正确!!!!!!");
// HttpEntity封装返回值信息
HttpEntity entity = response.getEntity();
//将entity中携带的信息转化为字符串
String result = EntityUtils.toString(entity,"utf-8");
System.out.println(result);
}else {
System.out.println("请求异常!!!!!");
}
}

第三步:封装需要使用到的对象,三个工具类
HttpClientService:封装服务器之间通信的方法,get,post,其中就包括返回结果的状态state

package com.jt.util;import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;@Service
public class HttpClientService {@Autowiredprivate CloseableHttpClient httpClient;@Autowiredprivate RequestConfig requestConfig;public String doGet(String url,Map<String,String> params,String charset){String result = null;//1.判断字符集编码是否为空 如果为空则给定默认值utf-8if(StringUtils.isEmpty(charset)){charset = "UTF-8";}//2.判断用户是否需要传递参数if(params != null){try {URIBuilder uriBuilder = new URIBuilder(url);for (Map.Entry<String,String> entry : params.entrySet()) {uriBuilder.addParameter(entry.getKey(), entry.getValue());}//url?id=1&name=tomurl = uriBuilder.build().toString();} catch (Exception e) {e.printStackTrace();}}//3.定义参数提交对象HttpGet get = new HttpGet(url);//4.为请求设定超时时间get.setConfig(requestConfig);//5.通过httpClient发送请求try {CloseableHttpResponse response = httpClient.execute(get);if(response.getStatusLine().getStatusCode() == 200){//表示程序调用成功result = EntityUtils.toString(response.getEntity(),charset);}else{System.out.println("调用异常:状态信息:"+response.getStatusLine().getStatusCode());throw new RuntimeException();}} catch (Exception e) {e.printStackTrace();}return result;}public String doGet(String url){return doGet(url, null, null);}public String doGet(String url,Map<String,String> params){return doGet(url, params, null);}public String doGet(String url,String charset){return doGet(url, null, charset);}//实现httpClient POST提交public String doPost(String url,Map<String,String> params,String charset){String result = null;//1.定义请求类型HttpPost post = new HttpPost(url);post.setConfig(requestConfig);  	//定义超时时间//2.判断字符集是否为nullif(StringUtils.isEmpty(charset)){charset = "UTF-8";}//3.判断用户是否传递参数if(params !=null){//3.2准备List集合信息List<NameValuePair> parameters = new ArrayList<>();//3.3将数据封装到List集合中for (Map.Entry<String,String> entry : params.entrySet()) {parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}//3.1模拟表单提交try {UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters,charset); //采用u8编码//3.4将实体对象封装到请求对象中post.setEntity(formEntity);} catch (UnsupportedEncodingException e) {e.printStackTrace();}}//4.发送请求try {CloseableHttpResponse response = httpClient.execute(post);//4.1判断返回值状态if(response.getStatusLine().getStatusCode() == 200) {//4.2表示请求成功result = EntityUtils.toString(response.getEntity(),charset);}else{System.out.println("获取状态码信息:"+response.getStatusLine().getStatusCode());throw new RuntimeException();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return result;}public String doPost(String url){return doPost(url, null, null);}public String doPost(String url,Map<String,String> params){return doPost(url, params, null);}public String doPost(String url,String charset){return doPost(url, null, charset);}
}

HttpClientConfig ,这里获取到上文提到案例中的CloseableHttpClient 对象,使用注解@Bean来将对象的管理权限交给spring容器进行管理。

package com.jt.config;import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;@Configuration
@PropertySource(value="classpath:/properties/httpClient.properties")
public class HttpClientConfig {@Value("${http.maxTotal}")private Integer maxTotal;						//最大连接数@Value("${http.defaultMaxPerRoute}")private Integer defaultMaxPerRoute;				//最大并发链接数@Value("${http.connectTimeout}")private Integer connectTimeout;					//创建链接的最大时间@Value("${http.connectionRequestTimeout}") private Integer connectionRequestTimeout;		//链接获取超时时间@Value("${http.socketTimeout}")private Integer socketTimeout;			  		//数据传输最长时间@Value("${http.staleConnectionCheckEnabled}")private boolean staleConnectionCheckEnabled; 	//提交时检查链接是否可用//定义httpClient链接池@Bean(name="httpClientConnectionManager")public PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager() {PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();manager.setMaxTotal(maxTotal);  //设定最大链接数manager.setDefaultMaxPerRoute(defaultMaxPerRoute);  //设定并发链接数return manager;}//定义HttpClient/*** 实例化连接池,设置连接池管理器。* 这里需要以参数形式注入上面实例化的连接池管理器@Qualifier 指定bean标签进行注入*/@Bean(name = "httpClientBuilder")public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager")PoolingHttpClientConnectionManager httpClientConnectionManager){//HttpClientBuilder中的构造方法被protected修饰,所以这里不能直接使用new来实例化一个HttpClientBuilder,可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();httpClientBuilder.setConnectionManager(httpClientConnectionManager);return httpClientBuilder;}/*** 	注入连接池,用于获取httpClient* @param httpClientBuilder* @return*/@Beanpublic CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder){return httpClientBuilder.build();}/*** Builder是RequestConfig的一个内部类* 通过RequestConfig的custom方法来获取到一个Builder对象* 设置builder的连接信息* @return*/@Bean(name = "builder")public RequestConfig.Builder getBuilder(){RequestConfig.Builder builder = RequestConfig.custom();return builder.setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout).setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);}/*** 使用builder构建一个RequestConfig对象* @param builder* @return*/@Beanpublic RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder){return builder.build();}
}

HttpClientClose

package com.jt.config;import javax.annotation.PreDestroy;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component	//交给spring容器管理
public class HttpClientClose extends Thread{@Autowiredprivate PoolingHttpClientConnectionManager manage;private volatile boolean shutdown;	//开关 volatitle表示多线程可变数据,一个线程修改,其他线程立即修改public HttpClientClose() {///System.out.println("执行构造方法,实例化对象");//线程开启启动this.start();}@Overridepublic void run() {try {//如果服务没有关闭,执行线程while(!shutdown) {synchronized (this) {wait(5000);			//等待5秒//System.out.println("线程开始执行,关闭超时链接");//关闭超时的链接PoolStats stats = manage.getTotalStats();int av = stats.getAvailable();	//获取可用的线程数量int pend = stats.getPending();	//获取阻塞的线程数量int lea = stats.getLeased();    //获取当前正在使用的链接数量int max = stats.getMax();//System.out.println("max/"+max+":	av/"+av+":  pend/"+pend+":   lea/"+lea);manage.closeExpiredConnections();}}} catch (Exception e) {e.printStackTrace();throw new RuntimeException();}super.run();}//关闭清理无效连接的线程@PreDestroy	//容器关闭时执行该方法.public void shutdown() {shutdown = true;synchronized (this) {//System.out.println("关闭全部链接!!");notifyAll(); //全部从等待中唤醒.执行关闭操作;}}
}

利用HttpClient实现远程商品及商品详情查询
案例运行时候的示意图:www.jt.com 是访问前端web服务器的url,由Nginx完成代理,manage.jt.com是后端处理数据的服务器。在这里插入图片描述
第一步:在web服务器中,写一个controller类,处理发送过来的前端http请求。
这里是item界面的http请求。

@Controller //如果需要跳转页面.则使用Controller注解
@RequestMapping("/items")
public class ItemController {
@Autowired
private ItemService itemService;
/**
* 请求:http://www.jt.com/items/56237
* 请求分析: 通过jt-web服务器 访问后台商品信息,其中562379表示商品的ID号
* 根据商品id号,之后查询后台数据库,获取商品信息之后进行数据的页面展现
* 参数接收: 需要动态的接收url中的参数 利用restFul风格实现数据的动态获取
*页面展现数据要求:
* <h1>${item.title}</h1>
<strong>${item.sellPoint}</strong>
需要查询后台数据之后.将数据保存到域中,之后利用el表达式完成数据的动态取值.
*/
@RequestMapping("/{itemId}")
public String findItemById(@PathVariable Long itemId,Model model) {
//1.根据商品id查询数据库
Item item = itemService.findItemById(itemId);
//2.将item对象保存到域中
model.addAttribute("item", item);
//查询数据之后跳转页面;
return "item";
}
}

第二步:在web服务器中,写相关的接口service

public interface ItemService {
Item findItemById(Long itemId);
}

第三步:在web服务器中,写service的实现类,这里需要使用到httpclient

@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private HttpClientService httpClientService;
/*
* 业务分析:
* 就是根据接收到的商品的id然后查询商品的数据,封装在Item对象
* 如何查询呢?
* jt-web是前台系统,不能直接连接数据库,如何查询数据呢?
* 查询方式:由前台系统jt-web发起请求去调用具体的后台系统jt-manage去查询商品数据
*/
@Override
@CacheFind//使用到了自定义的缓存注解
public Item findItemById(Long itemId) {
String url="http://manage.jt.com/web/item/findItemById/"+itemId;
String itemJSON=httpClientService.doGet(url);
//将json转换成java对象
return ObjectMapperUtil.toObject(itemJSON, Item.class);
}
}

第四步:
manage.jt.com来接受web服务器的service接口实现类中使用的httpclient的httpclientservice的get方法。
写一个controller类,转过来的也是url

@RestController
@RequestMapping("/web/item")
public class WebItemController {
@Autowired
private ItemService itemService;
/**
* 从前台向后台发起请求:
* http://manage.jt.com:80/web/item/findItemById/562379
* http://manage.jt.com:80是根目录,不用在requestmapping中写出来。因为现在就在manage.jt.com服务器中。
* 
*/
@RequestMapping("/findItemById/{itemId}")
public Item findItemById(@PathVariable Long itemId) {
return itemService.findItemById(itemId);
}
}

再去写接口的中方法和方法在接口实现类中的重写:

public interface ItemService {
Item findItemById(Long itemId);
}
@Override
public Item findItemById(Long itemId) {
return itemMapper.selectById(itemId);//利用MP实现查询
}

在这里插入图片描述
在这里插入图片描述
查询商品详情信息数据
第一步:业务分析
说明:如果需要展现商品详情信息,则需要将商品详情信息添加到域中,之后动态获取数据信息.
在item.jsp:

<div class="detail-content">
${itemDesc.itemDesc }
</div>

第二步:编辑jt-web项目的ItemController

@RequestMapping("/{itemId}")
public String findItemById(@PathVariable Long itemId,Model model) {
//1.根据商品id查询数据库
Item item = itemService.findItemById(itemId);
//2.将item对象保存到域中
model.addAttribute("item", item);
//3.查询商品详情信息
ItemDesc itemDesc = itemService.findItemDescById(itemId);
model.addAttribute("itemDesc", itemDesc);
//查询数据之后跳转页面;
return "item";
}

第三步:编辑jt-web项目的下的ItemService接口

public interface ItemService {
Item findItemById(Long itemId);
ItemDesc findItemDescById(Long itemId);
}

第四步:编辑jt-web的ItemServiceImpl实现类

@Override
public ItemDesc findItemDescById(Long itemId) {
String url = "http://manage.jt.com/web/item/findItemDescById/"+itemId;
String itemDescJSON = httpClientService.doGet(url);
return ObjectMapperUtil.toObject(itemDescJSON, ItemDesc.class);
}

第五步:编辑jt-manage项目下的WebItemController

/**
* 根据商品Id号动态查询商品详情信息
* http://manage.jt.com/web/item/findItemDescById/562379
*/
@RequestMapping("/findItemDescById/{itemId}")
public ItemDesc findItemDescById(@PathVariable Long itemId) {
return itemService.findItemDescById(itemId);
}

在这里插入图片描述

http://www.lryc.cn/news/69239.html

相关文章:

  • C# 基本语法
  • 做网络爬虫需要掌握哪些技术?
  • 工作利器:三种简单方法将PPT转换成PDF
  • 《设计模式》状态模式
  • 2023年好用的设计图制作软件推荐
  • JavaNote_1.0.2_Spring
  • 微服务多模块:Springboot+Security+Redis+Gateway+OpenFeign+Nacos+JWT (附源码)仅需一招,520彻底拿捏你
  • HNU数据结构与算法分析-作业4-图结构
  • AMPL IDE语法整理
  • 从0-1搭建支持gb28181协议搭建流媒体平台
  • 数据结构与算法之栈: Leetcode 682. 棒球比赛 (Typescript版)
  • E-office Server_v9.0 漏洞分析
  • MySQL数据库,JDBC连接数据库操作流程详细介绍
  • libevent高并发网络编程 - 06_基于libevent的C++线程池实现
  • 【Java EE 初阶】线程安全及死锁解决方案
  • C语言函数大全-- _w 开头的函数(5)
  • 机械大专生能学会云计算吗,完全零基础的
  • 腾讯云EdgeOne为什么能让客户降本增效?
  • 基于粒子群算法的微网经济优化调度——附Matalb代码
  • Flink入门
  • 【Go微服务开发】gin+grpc+etcd 重构 grpc-todolist 项目
  • 单板硬件设计:存储器SD卡( NAND FLASH)
  • C++实现日期类Date(超详细)
  • 实验室检验系统源码,集检验业务、质量控制、报告、统计分析、两癌等模块于一体
  • 学习RHCSA的day.03
  • 电子邮件协议(SMTP,MIME,POP3,IMAP)
  • Golang笔记:使用embed包将静态资源嵌入到程序中
  • ImportError: cannot import name ‘OldCsv‘ from ‘pyflink.table.descriptors‘
  • YouCompleteMe(YCM)安装
  • day33_css