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

西安正邦网站建设医院建设网站要求分析 amp

西安正邦网站建设,医院建设网站要求分析 amp,个人如何做免费网站,网站 建设 领导小组前言 RabbitMQ作为一款常用的消息中间件#xff0c;在微服务项目中得到大量应用#xff0c;其本身是微服务中的重点和难点#xff0c;有不少概念我自己的也是一知半解#xff0c;本系列博客尝试结合实际应用场景阐述RabbitMQ的应用#xff0c;分析其为什么使用#xff0… 前言 RabbitMQ作为一款常用的消息中间件在微服务项目中得到大量应用其本身是微服务中的重点和难点有不少概念我自己的也是一知半解本系列博客尝试结合实际应用场景阐述RabbitMQ的应用分析其为什么使用并给出怎么用的案例。 本篇博客结合场景来阐述RabbitMQ的几种模式描述了不同模式的应用场景并给出相应的代码。文末有惊喜~ 其他相关的rabbitmq博客文章列表如下 RabbitMQ基础1——生产者消费者模型 RabbitMQ简介 Docker版本的安装配置 RabbitMQ的helloworld 分模块构建 解决大量注册案例 RabbitMQ基础2——发布订阅/fanout模式 topic模式 rabbitmq回调确认 延迟队列死信设计 RabbitMQ的Docker版本安装 延迟插件安装 QQ邮箱和阿里云短信验证码的主题模式发送 目录 前言引出MQ场景1异步处理2解耦3削峰填谷常见的MQ 拆解控制台页面总览页面连接connection队列页面 简单模式工具类建立连接生产者生产消息消费者消费消息进行测试Ack项目中必须false 工作模式一个生产者两个消费者QOS: 限流Tips队列参数怎么变 队列相关参数x-max-lengthx-overflowx-max-length-bytes 发布者订阅模式生产者给fanout交换机发消息消费者1队列q32消费者2队列q321 路由模式生产者发给交换机告诉路由键消费者1根据路由键接收3种消息消费者2根据路由键接收1种消息 主题模式(Topic)生产者主题交换机带路由键消费者1通配符的路由键消费者2统配符 总结 引出 1.MQ消息队列的应用场景几种MQ简单对比 2.分析RabbitMQ的浏览器控制台页面 3.结合场景来阐述RabbitMQ的几种模式描述了不同模式的应用场景并给出相应的代码 MQ场景 Message Queue 消息队列。 有比较大的负载而且这些负载不用立刻马上给程序返回结构可以有一些等待时间。可以用消息队列。 1异步处理 过去的项目大部分都是同步解决问题。 UserinfoService{register(){//典型的同步//插入数据库//发短信//发邮件} } //如果你的操作基本没有任何延时操作或者瓶颈没有压力。那么你没有必要用MQ UserinfoService{register(){//发起的是一个异步请求都不等待对方给我返回的结果//异步插入数据库//异步发短信//异步发邮件} }2解耦 库存有没有可能挂了。或者访问量巨大。因为库存慢导致订单也慢。 解耦。 3削峰填谷 双12的时候叫好早上的8点。秒杀的时候。 有些瞬间服务器压力是超大的过了这个瞬间几乎没有消耗量。 等服务器能够正常的时候我慢慢执行就行了。 常见的MQ MQ的前身就是一个发布者订阅模式。 Kafka RabbitMQ1W/s RocketMQ ActiveMQ Kafka : 10w/S 主要用于日志。 Kafka是由Apache软件基金会开发的一个开源流处理平台由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统它可以处理消费者在网站中的所有动作流数据。 这种动作网页浏览搜索和其他用户的行动是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop一样的日志数据和离线分析系统但又要求实时处理的限制这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理也是为了通过集群来提供实时的消息。 拆解控制台页面 总览页面 包括刷新时间间隔rabbitmq节点连接端口的信息等 配置可以导出和导入 连接connection 队列页面 包括队列的名字状态准备好的消息数量未确认的消息数量总计消息数量 简单模式 使用的依赖 !-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client --dependencygroupIdcom.rabbitmq/groupIdartifactIdamqp-client/artifactIdversion5.7.3/version/dependency工具类建立连接 package com.tianju.config;import com.rabbitmq.client.Connection;import java.io.IOException; import java.util.concurrent.TimeoutException;/*** 建立连接的工具类*/ public class ConnectionFactory {public static Connection createConnection() throws IOException, TimeoutException {com.rabbitmq.client.ConnectionFactory connectionFactory new com.rabbitmq.client.ConnectionFactory();connectionFactory.setHost(192.168.111.130); // http://192.168.111.130/connectionFactory.setPort(5672);connectionFactory.setUsername(admin);connectionFactory.setPassword(123);connectionFactory.setVirtualHost(/demo);// amqp://admin192.168.111.130:5672/return connectionFactory.newConnection();} } 生产者生产消息 package com.tianju.simple;import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.tianju.config.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate;import java.io.IOException; import java.util.concurrent.TimeoutException;/*** 生产者发送消息* 建立连接-- 创建频道 -- 创建队列 -- 发送消息*/ public class Provider {private static String QUEUE_ORDER queue_order;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建队列channel.queueDeclare(QUEUE_ORDER,false,false,false,null);// 发送消息指定给哪个队列上发消息for (int i 0; i 100; i) {String msg hello rabbitmq--i;channel.basicPublish(, QUEUE_ORDER, null, msg.getBytes());System.out.println(消息发布成功);}connection.close();} } 消费者消费消息 package com.tianju.simple;import com.rabbitmq.client.*; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.concurrent.TimeoutException;public class Consumer {private static String QUEUE_ORDER queue_order;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建队列channel.queueDeclare(QUEUE_ORDER,false,false,false,null);// 队列必须声明如果不存在则自动创建// 声明一个消费者DefaultConsumer defaultConsumer new DefaultConsumer(channel){/*** 回调函数用来接收消息* param consumerTag the iconsumer tag/i associated with the consumer* param envelope packaging data for the message* param properties content header data for the message* param body the message body (opaque, client-specific byte array)字节数组* throws IOException*/public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body)throws IOException{// no work to doString msg new String(body); // 收到的信息System.out.println(消费者接收到msg);try {Thread.sleep(3000);// 模拟一个耗时操作} catch (InterruptedException e) {throw new RuntimeException(e);}}};// 表明自己是消费者接收消息/*** autoAck自动确认设置成 true*/channel.basicConsume(QUEUE_ORDER, true, defaultConsumer);} } 进行测试 生产者发送100条消息 消费者进行消费假设突然之间服务宕机了此时消费了4条消息理论上还应该有96条消息 打开控制台页面查看消息全部消失了出现了数据丢失的情况 全部用默认值的情况下如果发生异常则消息全部丢失。 消费者一次性拿到了所有的消息。 Ack项目中必须false 生产者 投递消息》队列 消费者接受》队列 ack: false 必须要手工确认。 消费者接到这个消息的时候 这个消息进入 unack状态。 1手工确认。消息删除。完成 2: 没手工确认断开连接或者超时。 3这个消息重新进入ready状态。等待其他消费者进行消费。 先设置自动ack为false表示需要手工确认然后在消费消息的方法中进行消息的确认。 package com.tianju.simple;import com.rabbitmq.client.*; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.concurrent.TimeoutException;public class Consumer {private static String QUEUE_ORDER queue_order;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建队列channel.queueDeclare(QUEUE_ORDER,false,false,false,null);// 队列必须声明如果不存在则自动创建// 声明一个消费者DefaultConsumer defaultConsumer new DefaultConsumer(channel){/*** 回调函数用来接收消息* param consumerTag the iconsumer tag/i associated with the consumer* param envelope packaging data for the message* param properties content header data for the message* param body the message body (opaque, client-specific byte array)字节数组* throws IOException*/public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body)throws IOException {// no work to doString msg new String(body); // 收到的信息System.out.println(消费者接收到msg);try {Thread.sleep(3000);// 模拟一个耗时操作} catch (InterruptedException e) {throw new RuntimeException(e);}// 消费者代码可能有失败消息拿到之后可能还没有处理就宕机了// 消息确认的代码一定在最后一行// long deliveryTag 消息的下标// boolean multiple 是否批量确认channel.basicAck(envelope.getDeliveryTag(),true); // 确认消息批量确认}};// 表明自己是消费者接收消息/*** autoAck自动确认设置成 true* 是否自动确认* false不进行自动确认true自动确认* 消费过程中可能产生异常* 如果产生异常则必须进行消费补偿*/channel.basicConsume(QUEUE_ORDER, false, defaultConsumer); // 接收消息} } 再次模拟宕机的情况一开始消息全部被放到Unack中当宕机时又把消息吐了出来至少消息没有出现丢失的情况。 工作模式 一个生产者两个消费者 两个消费者消费的是同一个队列中的消息。 两个消费者上来后默认是按照平均分配。结果 有人瞬间干完。有人很久都没干完。 QOS: 限流 可以限制你一次拉取几个。 这样两个消费者也能够节省服务器CPU了。 // 创建频道Channel channel connection.createChannel();channel.basicQos(1); /** 1次只能拿1个 **/当消费的速度太慢觉得不够加入其他的消费者。 核心只有一个消息队列。 消息是轮询的方式发送给不同的消费者。 Tips队列参数怎么变 队列的参数发生变化后要删除再添加。 // 创建频道Channel channel connection.createChannel();channel.queueDelete(QUEUE_ORDER); // 先删除旧的队列boolean durable true; // 当前队列中的消息持久化操作重启之后消息还在// 创建队列channel.queueDeclare(QUEUE_ORDER,durable,false,false,null);队列相关参数 x-max-length package com.tianju.work;import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException;/*** 生产者发送消息* 建立连接-- 创建频道 -- 创建队列 -- 发送消息*/ public class Provider {private static String QUEUE_ORDER queue_order;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();channel.queueDelete(QUEUE_ORDER); // 先删除旧的队列boolean durable true; // 当前队列中的消息持久化操作重启之后消息还在Map map new HashMap();map.put(x-max-length, 10); // 设置最大的长度只接受10个// 创建队列channel.queueDeclare(QUEUE_ORDER,durable,false,false,map);// 发送消息指定给哪个队列上发消息for (int i 0; i 1000; i) {String msg hello rabbitmq--i;channel.basicPublish(, QUEUE_ORDER, null, msg.getBytes());System.out.println(消息发布成功);}connection.close();} } How many (ready) messages a queue can contain before it starts to drop them from its head. x-overflow Sets the queue overflow behaviour. This determines what happens to messages when the maximum length of a queue is reached. Valid values are drop-head, reject-publish or reject-publish-dlx. The quorum queue type only supports drop-head and reject-publish. 此时就是前10个了 x-max-length-bytes package com.tianju.work;import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException;/*** 生产者发送消息* 建立连接-- 创建频道 -- 创建队列 -- 发送消息*/ public class Provider {private static String QUEUE_ORDER queue_order;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();channel.queueDelete(QUEUE_ORDER); // 先删除旧的队列boolean durable true; // 当前队列中的消息持久化操作重启之后消息还在Map map new HashMap();map.put(x-max-length, 10); // 设置最大的长度只接受10个map.put(x-overflow, reject-publish); // 拒绝发布变成前10gemap.put(x-max-length-bytes, 4); // 消息的最大字节长度// 创建队列channel.queueDeclare(QUEUE_ORDER,durable,false,false,map);// 发送消息指定给哪个队列上发消息for (int i 0; i 20; i) {String msg 53i;channel.basicPublish(, QUEUE_ORDER, null, msg.getBytes());msg hello rabbitmq--i;channel.basicPublish(, QUEUE_ORDER, null, msg.getBytes());System.out.println(消息发布成功);}connection.close();} } 参数 //创建队列boolean durable true;//当前队列中的消息进行持久化操作 重启之后消息还在Map map new HashMap();map.put(x-max-length,10);//设置队列的最大长度map.put(x-overflow,reject-publish);//设置队列的最大长度 drop headmap.put(x-max-length-bytes,4);//设置消息的最大字节长度 // map.put(x-expires,10000);//超时后直接删除队列channel.queueDeclare(QUQUENAME,durable,false,false,map);发布者订阅模式 工作模式中只有一个队列。两个消费者轮询从同一个队列中取数据。 发布者订阅模式 交换机后面会绑定多个消息队列。每个消息队列都有完整的信息。每个队列后的消费者都会有完整的消息。 交换机就是一个无意识的广播。行为就是扇出. 场景 下订单 1订单的数据入数据库 2发送订单的短信 3 物流 要每个队列都有完整的信息。 生产者给fanout交换机发消息 package com.tianju.publish;import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.MessageProperties; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.concurrent.TimeoutException;/*** 生产者发送消息* 建立连接-- 创建频道 -- 创建队列 -- 发送消息*/ public class Provider {private static String QUEUE_ORDER queue_order;private static String EXCHANGE pet_exchange;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建交换机channel.exchangeDeclare(EXCHANGE, fanout); // 扇出类型只能用这个for (int i 0; i 100; i) {channel.basicPublish(EXCHANGE, , MessageProperties.TEXT_PLAIN, (hello fanouti).getBytes());}} } 消费者1队列q32 package com.tianju.publish;import com.rabbitmq.client.*; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.concurrent.TimeoutException;public class Consumer {private static String EXCHANGE pet_exchange;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建交换机channel.exchangeDeclare(EXCHANGE, fanout); // 扇出类型只能用这个channel.queueDeclare(q32, false, false, false, null);channel.queueBind(q32, EXCHANGE, ); // 路由键fanout模式必须为空即使写了是无效的channel.basicConsume(q32, new DefaultConsumer(channel){public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body)throws IOException{// no work to doString msg new String(body);System.out.println(消费者1msg);channel.basicAck(envelope.getDeliveryTag(), false);}});} } 消费者2队列q321 package com.tianju.publish;import com.rabbitmq.client.*; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.concurrent.TimeoutException;public class Consumer2 {private static String EXCHANGE pet_exchange;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建交换机channel.exchangeDeclare(EXCHANGE, fanout); // 扇出类型只能用这个channel.queueDeclare(q321, false, false, false, null);channel.queueBind(q321, EXCHANGE, ); // 路由键fanout模式必须为空即使写了是无效的channel.basicConsume(q321, new DefaultConsumer(channel){public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body)throws IOException{// no work to doString msg new String(body);System.out.println(消费者2msg);channel.basicAck(envelope.getDeliveryTag(), false);}});} } 路由模式 允许用不同的路由键来接受不同的信息。 队列会接到完整的全部的信息。 日志系统 日志级别 OFF INFO DEBUG ERROR FATAL ALL 如果是致命错误 立刻给运维发短信。 全部信息 放到专门的日志系统 Error: 进行发邮件 生产者发给交换机告诉路由键 package com.tianju.routing;import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.MessageProperties; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.concurrent.TimeoutException;/*** 生产者发送消息* 建立连接-- 创建频道 -- 创建队列 -- 发送消息*/ public class Provider {private static String EXCHANGE exchange_58;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建交换机channel.exchangeDeclare(EXCHANGE, direct); // 直接交换机String msg this is fatal message;channel.basicPublish(EXCHANGE,fatal, MessageProperties.TEXT_PLAIN,msg.getBytes());msg this is error message;channel.basicPublish(EXCHANGE,error, MessageProperties.TEXT_PLAIN,msg.getBytes());msg this is debug message;channel.basicPublish(EXCHANGE,debug, MessageProperties.TEXT_PLAIN,msg.getBytes());} } 消费者1根据路由键接收3种消息 package com.tianju.routing;import com.rabbitmq.client.*; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.Calendar; import java.util.concurrent.TimeoutException;public class Consumer {private static String EXCHANGE exchange_58;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建队列// 创建交换机channel.exchangeDeclare(EXCHANGE, direct); // 直接交换机// 队列必须声明如果不存在则自动创建channel.queueDeclare(q58, false, false, false, null);channel.queueBind(q58, EXCHANGE, fatal);channel.queueBind(q58, EXCHANGE, error);channel.queueBind(q58, EXCHANGE, debug);channel.basicConsume(q58, new DefaultConsumer(channel){public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body)throws IOException{// no work to doString msg new String(body);System.out.println(消费者1msg);channel.basicAck(envelope.getDeliveryTag(), false);}});} } 消费者2根据路由键接收1种消息 package com.tianju.routing;import com.rabbitmq.client.*; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.concurrent.TimeoutException;public class Consumer2 {private static String EXCHANGE exchange_58;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建队列// 创建交换机channel.exchangeDeclare(EXCHANGE, direct); // 直接交换机// 队列必须声明如果不存在则自动创建channel.queueDeclare(q581, false, false, false, null);channel.queueBind(q581, EXCHANGE, fatal);channel.basicConsume(q581, new DefaultConsumer(channel){public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body)throws IOException{// no work to doString msg new String(body);System.out.println(消费者1msg);channel.basicAck(envelope.getDeliveryTag(), false);}});} } 主题模式(Topic) 可以采取通配符模式 * (star) can substitute for exactly one word. # (hash) can substitute for zero or more words.#匹配0个或多个词 *匹配不多不少恰好1个词 举例 item.#能够匹配item.insert.abc 或者 item.insert item.*只能匹配item.insert 场景 京东 无锡河南下订单。退货 总部 收到这个订单 . 无锡分销商也有这个消息 *.wuxi 生产者主题交换机带路由键 package com.tianju.topic;import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.MessageProperties; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.concurrent.TimeoutException;/*** 生产者发送消息* 建立连接-- 创建频道 -- 创建队列 -- 发送消息*/ public class Provider {private static String EXCHANGE exchange_58;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建交换机channel.exchangeDeclare(EXCHANGE, topic); // 主题模式交换机String msg this is wuxi order;channel.basicPublish(EXCHANGE,order.wuxi, MessageProperties.TEXT_PLAIN,msg.getBytes());msg this is henan order;channel.basicPublish(EXCHANGE,order.henan, MessageProperties.TEXT_PLAIN,msg.getBytes());msg this is wuxi back;channel.basicPublish(EXCHANGE,back.wuxi, MessageProperties.TEXT_PLAIN,msg.getBytes());msg this is henan back;channel.basicPublish(EXCHANGE,back.henan, MessageProperties.TEXT_PLAIN,msg.getBytes());} } 消费者1通配符的路由键 package com.tianju.topic;import com.rabbitmq.client.*; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.concurrent.TimeoutException;public class Consumer {private static String EXCHANGE exchange_58;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建队列// 创建交换机channel.exchangeDeclare(EXCHANGE, topic); // 主题交换机// 队列必须声明如果不存在则自动创建channel.queueDeclare(q58, false, false, false, null);channel.queueBind(q58, EXCHANGE, *.wuxi); // 意味着无锡的订单和退货都能收到channel.basicConsume(q58, new DefaultConsumer(channel){public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body)throws IOException{// no work to doString msg new String(body);System.out.println(无锡仓库msg);channel.basicAck(envelope.getDeliveryTag(), false);}});} } 消费者2统配符 package com.tianju.topic;import com.rabbitmq.client.*; import com.tianju.config.ConnectionFactory;import java.io.IOException; import java.util.concurrent.TimeoutException;public class Consumer2 {private static String EXCHANGE exchange_58;public static void main(String[] args) throws IOException, TimeoutException {// 建立连接Connection connection ConnectionFactory.createConnection();// 创建频道Channel channel connection.createChannel();// 创建队列// 创建交换机channel.exchangeDeclare(EXCHANGE, topic); // 主题交换机// 队列必须声明如果不存在则自动创建channel.queueDeclare(q581, false, false, false, null);channel.queueBind(q581, EXCHANGE, *.*); // 意味着所有的订单和退货都能收到channel.basicConsume(q581, new DefaultConsumer(channel){public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body)throws IOException{// no work to doString msg new String(body);System.out.println(总部仓库msg);channel.basicAck(envelope.getDeliveryTag(), false);}});} } 总结 1.MQ消息队列的应用场景几种MQ简单对比 2.分析RabbitMQ的浏览器控制台页面 3.结合场景来阐述RabbitMQ的几种模式描述了不同模式的应用场景并给出相应的代码
http://www.w-s-a.com/news/177560/

相关文章:

  • 做网站的中文名字汕尾网站开发
  • 网站推广效果推广网站推荐
  • 腾讯企业网站建设网络推广比较经典和常用的方法有
  • 四川成都网站网页设计上海外贸网站制作公司
  • wordpress模板首页图片锦州网站做优化
  • 哔哩哔哩网站建设分析有哪些做网站好的公司
  • 福建建设执业中心网站沧州网络推广外包公司
  • 做网站怎么改关键词营销网站建设818gx
  • 广撒网网站怎么进行网络营销
  • 中职计算机网站建设教学计划电商网站如何避免客户信息泄露
  • 惠州微网站建设外贸进出口代理公司
  • 网站建设最常见的问题建设银行网站机构
  • 网站集群建设相关的招标南通seo网站建设费用
  • 网络培训的网站建设能够做二维码网站
  • 网站类游戏网站开发wordpress 文章首标点
  • 徐州网站建设熊掌号免费推广网站入口2020
  • 网站建设有前途长春高铁站
  • 做网站网课阿里云域名查询系统
  • saas建站平台有哪些简述网站建设基本流程答案
  • 个人怎么做网站网站浏览思路
  • 网站建设里的知识长沙网络营销公司
  • 网站建设与维护大作业pc网站转换成微网站
  • php网站开发经典教材东莞网站开发
  • 教育培训手机网站模板下载跨境电商培训哪家最好
  • 网站开发淄博网站被降权会发生什么影响吗
  • 网站开发常用的语言东城手机网站制作
  • 微小店网站建设平台手机优化加速有什么用
  • 沈阳酒店企业网站制作公司竞价网站怎么做seo
  • 中山企业网站多少钱学网站建设的好处
  • 做官网网站哪家公司好jianux wordpress