diff --git a/.gitignore b/.gitignore
index 3a545dc26ce79c0ee4e3913be741b42d29ff8922..d1b23a5296216964d466203355c929aa670e9508 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,3 +35,4 @@
/itstack-demo-design-19-01/itstack-demo-design-19-01.iml
/itstack-demo-design-19-00/itstack-demo-design-19-00.iml
/itstack-demo-design-20-01/itstack-demo-design-20-01.iml
+/itstack-demo-design-21-00/itstack-demo-design-21-00.iml
diff --git a/README.md b/README.md
index 6716374bc323a34523a4fe46229c33d1d68bf8a8..a64a221f06c0672f0a7a1a24a7fd6668693add30 100644
--- a/README.md
+++ b/README.md
@@ -27,4 +27,5 @@
- [`5. 重学 Java 设计模式:实战备忘录模式「模拟互联网系统上线过程中,配置文件回滚场景」`](https://bugstack.cn/itstack-demo-design/2020/06/28/%E9%87%8D%E5%AD%A6-Java-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%AE%9E%E6%88%98%E5%A4%87%E5%BF%98%E5%BD%95%E6%A8%A1%E5%BC%8F.html)
- [`6. 重学 Java 设计模式:实战观察者模式「模拟类似小客车指标摇号过程,监听消息通知用户中签场景」`](https://bugstack.cn/itstack-demo-design/2020/06/30/%E9%87%8D%E5%AD%A6-Java-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%AE%9E%E6%88%98%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F.html)
- [`7. 重学 Java 设计模式:实战状态模式「模拟系统营销活动,状态流程审核发布上线场景」`](https://bugstack.cn/itstack-demo-design/2020/07/02/%E9%87%8D%E5%AD%A6-Java-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%AE%9E%E6%88%98%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F.html)
-- [`8. 重学 Java 设计模式:实战策略模式「模拟多种营销类型优惠券,折扣金额计算策略场景」`](https://bugstack.cn/itstack-demo-design/2020/07/05/%E9%87%8D%E5%AD%A6-Java-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%AE%9E%E6%88%98%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F.html)
\ No newline at end of file
+- [`8. 重学 Java 设计模式:实战策略模式「模拟多种营销类型优惠券,折扣金额计算策略场景」`](https://bugstack.cn/itstack-demo-design/2020/07/05/%E9%87%8D%E5%AD%A6-Java-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%AE%9E%E6%88%98%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F.html)
+- [`9. 重学 Java 设计模式:实战模版模式「模拟爬虫各类电商商品,生成营销推广海报场景」`](https://bugstack.cn/itstack-demo-design/2020/07/07/%E9%87%8D%E5%AD%A6-Java-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%AE%9E%E6%88%98%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F.html)
\ No newline at end of file
diff --git a/itstack-demo-design-21-00/pom.xml b/itstack-demo-design-21-00/pom.xml
new file mode 100755
index 0000000000000000000000000000000000000000..a095f42788a0d12a2cb88272b4d314fce458673d
--- /dev/null
+++ b/itstack-demo-design-21-00/pom.xml
@@ -0,0 +1,27 @@
+
+
+
+ itstack-demo-design
+ org.itstack
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ itstack-demo-design-21-00
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 8
+ 8
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/HttpClient.java b/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/HttpClient.java
new file mode 100755
index 0000000000000000000000000000000000000000..b2cf587cb17c0bf2dd462e283c967e36c267d9c3
--- /dev/null
+++ b/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/HttpClient.java
@@ -0,0 +1,74 @@
+package org.itstack.demo.design;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class HttpClient {
+
+ public static String doGet(String httpurl) {
+ HttpURLConnection connection = null;
+ InputStream is = null;
+ BufferedReader br = null;
+ String result = null;// 返回结果字符串
+ try {
+ // 创建远程url连接对象
+ URL url = new URL(httpurl);
+ // 通过远程url连接对象打开一个连接,强转成httpURLConnection类
+ connection = (HttpURLConnection) url.openConnection();
+ // 设置连接方式:get
+ connection.setRequestMethod("GET");
+ // 设置连接主机服务器的超时时间:15000毫秒
+ connection.setConnectTimeout(15000);
+ // 设置读取远程返回的数据时间:60000毫秒
+ connection.setReadTimeout(60000);
+ // 发送请求
+ connection.connect();
+ // 通过connection连接,获取输入流
+ if (connection.getResponseCode() == 200) {
+ is = connection.getInputStream();
+ // 封装输入流is,并指定字符集
+ br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+ // 存放数据
+ StringBuilder sbf = new StringBuilder();
+ String temp = null;
+ while ((temp = br.readLine()) != null) {
+ sbf.append(temp);
+ sbf.append("\r\n");
+ }
+ result = sbf.toString();
+ }
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ // 关闭资源
+ if (null != br) {
+ try {
+ br.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (null != is) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ assert connection != null;
+ connection.disconnect();// 关闭远程连接
+ }
+
+ return result;
+ }
+
+}
diff --git a/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/NetMall.java b/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/NetMall.java
new file mode 100755
index 0000000000000000000000000000000000000000..2abb7f8084ac77cdca727851778558d98e4f6209
--- /dev/null
+++ b/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/NetMall.java
@@ -0,0 +1,46 @@
+package org.itstack.demo.design;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+/**
+ * 基础电商推广服务
+ * 1. 生成最优价商品海报
+ * 2. 海报含带推广邀请码
+ */
+public abstract class NetMall {
+
+ protected Logger logger = LoggerFactory.getLogger(NetMall.class);
+
+ String uId; // 用户ID
+ String uPwd; // 用户密码
+
+ public NetMall(String uId, String uPwd) {
+ this.uId = uId;
+ this.uPwd = uPwd;
+ }
+
+ /**
+ * 生成商品推广海报
+ *
+ * @param skuUrl 商品地址(京东、淘宝、当当)
+ * @return 海报图片base64位信息
+ */
+ public String generateGoodsPoster(String skuUrl) {
+ if (!login(uId, uPwd)) return null; // 1. 验证登录
+ Map reptile = reptile(skuUrl); // 2. 爬虫商品
+ return createBase64(reptile); // 3. 组装海报
+ }
+
+ // 模拟登录
+ protected abstract Boolean login(String uId, String uPwd);
+
+ // 爬虫提取商品信息(登录后的优惠价格)
+ protected abstract Map reptile(String skuUrl);
+
+ // 生成商品海报信息
+ protected abstract String createBase64(Map goodsInfo);
+
+}
diff --git a/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/impl/DangDangNetMall.java b/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/impl/DangDangNetMall.java
new file mode 100755
index 0000000000000000000000000000000000000000..5728568a58147003b3eece7569551d204d779a46
--- /dev/null
+++ b/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/impl/DangDangNetMall.java
@@ -0,0 +1,46 @@
+package org.itstack.demo.design.impl;
+
+import com.alibaba.fastjson.JSON;
+import org.itstack.demo.design.HttpClient;
+import org.itstack.demo.design.NetMall;
+import sun.misc.BASE64Encoder;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class DangDangNetMall extends NetMall {
+
+ public DangDangNetMall(String uId, String uPwd) {
+ super(uId, uPwd);
+ }
+
+ @Override
+ public Boolean login(String uId, String uPwd) {
+ logger.info("模拟当当用户登录 uId:{} uPwd:{}", uId, uPwd);
+ return true;
+ }
+
+ @Override
+ public Map reptile(String skuUrl) {
+ String str = HttpClient.doGet(skuUrl);
+ Pattern p9 = Pattern.compile("(?<=title\\>).*(?= map = new ConcurrentHashMap();
+ if (m9.find()) {
+ map.put("name", m9.group());
+ }
+ map.put("price", "4548.00");
+ logger.info("模拟当当商品爬虫解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl);
+ return map;
+ }
+
+ @Override
+ public String createBase64(Map goodsInfo) {
+ BASE64Encoder encoder = new BASE64Encoder();
+ logger.info("模拟生成当当商品base64海报");
+ return encoder.encode(JSON.toJSONString(goodsInfo).getBytes());
+ }
+
+}
diff --git a/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/impl/JDNetMall.java b/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/impl/JDNetMall.java
new file mode 100755
index 0000000000000000000000000000000000000000..7b74d7063a120e79231761121f0355a4675cdd38
--- /dev/null
+++ b/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/impl/JDNetMall.java
@@ -0,0 +1,46 @@
+package org.itstack.demo.design.impl;
+
+import com.alibaba.fastjson.JSON;
+import org.itstack.demo.design.HttpClient;
+import org.itstack.demo.design.NetMall;
+import sun.misc.BASE64Encoder;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 模拟JD商城
+ */
+public class JDNetMall extends NetMall {
+
+ public JDNetMall(String uId, String uPwd) {
+ super(uId, uPwd);
+ }
+
+ public Boolean login(String uId, String uPwd) {
+ logger.info("模拟京东用户登录 uId:{} uPwd:{}", uId, uPwd);
+ return true;
+ }
+
+ public Map reptile(String skuUrl) {
+ String str = HttpClient.doGet(skuUrl);
+ Pattern p9 = Pattern.compile("(?<=title\\>).*(?= map = new ConcurrentHashMap();
+ if (m9.find()) {
+ map.put("name", m9.group());
+ }
+ map.put("price", "5999.00");
+ logger.info("模拟京东商品爬虫解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl);
+ return map;
+ }
+
+ public String createBase64(Map goodsInfo) {
+ BASE64Encoder encoder = new BASE64Encoder();
+ logger.info("模拟生成京东商品base64海报");
+ return encoder.encode(JSON.toJSONString(goodsInfo).getBytes());
+ }
+
+}
diff --git a/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/impl/TaoBaoNetMall.java b/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/impl/TaoBaoNetMall.java
new file mode 100755
index 0000000000000000000000000000000000000000..2c5dd32377039d5089f04bb70c62f29a503e7ef9
--- /dev/null
+++ b/itstack-demo-design-21-00/src/main/java/org/itstack/demo/design/impl/TaoBaoNetMall.java
@@ -0,0 +1,46 @@
+package org.itstack.demo.design.impl;
+
+import com.alibaba.fastjson.JSON;
+import org.itstack.demo.design.HttpClient;
+import org.itstack.demo.design.NetMall;
+import sun.misc.BASE64Encoder;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class TaoBaoNetMall extends NetMall {
+
+ public TaoBaoNetMall(String uId, String uPwd) {
+ super(uId, uPwd);
+ }
+
+ @Override
+ public Boolean login(String uId, String uPwd) {
+ logger.info("模拟淘宝用户登录 uId:{} uPwd:{}", uId, uPwd);
+ return true;
+ }
+
+ @Override
+ public Map reptile(String skuUrl) {
+ String str = HttpClient.doGet(skuUrl);
+ Pattern p9 = Pattern.compile("(?<=title\\>).*(?= map = new ConcurrentHashMap();
+ if (m9.find()) {
+ map.put("name", m9.group());
+ }
+ map.put("price", "4799.00");
+ logger.info("模拟淘宝商品爬虫解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl);
+ return map;
+ }
+
+ @Override
+ public String createBase64(Map goodsInfo) {
+ BASE64Encoder encoder = new BASE64Encoder();
+ logger.info("模拟生成淘宝商品base64海报");
+ return encoder.encode(JSON.toJSONString(goodsInfo).getBytes());
+ }
+
+}
diff --git a/itstack-demo-design-21-00/src/test/java/org/itstack/demo/design/test/ApiTest.java b/itstack-demo-design-21-00/src/test/java/org/itstack/demo/design/test/ApiTest.java
new file mode 100755
index 0000000000000000000000000000000000000000..23f08eeb7a933d2bd83e76a58aac9386e06662af
--- /dev/null
+++ b/itstack-demo-design-21-00/src/test/java/org/itstack/demo/design/test/ApiTest.java
@@ -0,0 +1,26 @@
+package org.itstack.demo.design.test;
+
+import org.itstack.demo.design.NetMall;
+import org.itstack.demo.design.impl.JDNetMall;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ApiTest {
+
+ public Logger logger = LoggerFactory.getLogger(ApiTest.class);
+
+ /**
+ * 测试链接
+ * 京东;https://item.jd.com/100008348542.html
+ * 淘宝;https://detail.tmall.com/item.htm
+ * 当当;http://product.dangdang.com/1509704171.html
+ */
+ @Test
+ public void test_NetMall() {
+ NetMall netMall = new JDNetMall("1000001","*******");
+ String base64 = netMall.generateGoodsPoster("https://item.jd.com/100008348542.html");
+ logger.info("测试结果:{}", base64);
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index b5f8b25d6853b1f04988d6bf1df96ada6f37c920..1622c9be74508430299f26b52b122644ef56b4e6 100755
--- a/pom.xml
+++ b/pom.xml
@@ -57,6 +57,7 @@
itstack-demo-design-19-02
itstack-demo-design-20-01
itstack-demo-design-20-02
+ itstack-demo-design-21-00