中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java開發如何實現訂閱到貨通知

發布時間:2023-02-22 15:55:30 來源:億速云 閱讀:142 作者:iii 欄目:開發技術

本篇內容主要講解“java開發如何實現訂閱到貨通知”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“java開發如何實現訂閱到貨通知”吧!

    思路

    為什么每次到貨通知進去看都沒貨呢?猜想可能有幾種情況,可能這個通知并不是實時的一有貨就通知,也可能是訂閱的人太多了沒有全部發。總之,這個到貨通知不靠譜,那就只能自己實現一個到貨通知了。

    實現步驟:

    • 分析商品信息api

    • 定時請求商品信息api查看商品庫存

    • 發送消息通知

    分析商品信息api

    先用Charles或者Fiddler等工具分析查看商品數據時請求的api數據,之前有寫過Charles的具體使用方法,有興趣的同學可以看一下,這邊就不再細說了。

    手機wifi代理配置Charles主機地址,查看api數據,根據api名稱和返回內容,可以判斷接口路徑是:/api/v1/xxx/goods-portal/spu/queryDetail

    java開發如何實現訂閱到貨通知

    分析下api的返回數據內容,可以看到具體的庫存信息(刪除了許多沒用的數據),通過名稱分析可以定位到庫存字段為:stockQuantity,所以我們就可以通過這個api來查看具體商品的庫存數據了

    {
      "data": {
        "spuId": "1277934",
        "hostItem": "980033855",
        "storeId": "6782",
        "title": "Member's Mark 精選鮮雞蛋 30枚裝",
        "masterBizType": 1,
        "viceBizType": 1,
        "categoryIdList": [
          "10003023",
          "10003228",
          "10004626",
          "10012102"
        ],
        "isAvailable": true,
        "isPutOnSale": true,
        "sevenDaysReturn": false,
        "intro": "MM 精選鮮雞蛋 30枚",
        "subTitle": "(粉殼雞蛋/褐殼雞蛋, 兩種隨機發貨, 不影響雞蛋品質) 精心培育 每一顆雞蛋都可溯源 口感香醇 做法多樣 懶人早餐",
        "brandId": "10194688",
        "weight": 1.5,
        "desc": "",
        "priceInfo": [
          {
            "priceType": 2,
            "price": "0",
            "priceTypeName": "原始價"
          },
          {
            "priceType": 1,
            "price": "2380",
            "priceTypeName": "銷售價"
          }
        ],
        "stockInfo": {
          "stockQuantity": 68,
          "safeStockQuantity": 0,
          "soldQuantity": 0
        },
        "limitInfo": [
          {
            "limitType": 3,
            "limitNum": 5,
            "text": "限購2件",
            "cycleDays": 1
          }
        ],
        "deliveryAttr": 3,
        "favorite": false,
        "giveaway": false,
        "beltInfo": [
          
        ],
        "isStoreExtent": false,
        "isTicket": false
      },
      "code": "Success",
      "msg": "",
      "errorMsg": "",
      "traceId": "a80e1d3df8f7f216",
      "requestId": "54c25d584f8a4b39b95ba7bdd1331da6.182.16740102252700000",
      "rt": 0,
      "success": true
    }

    確定完接口返回數據后,我們還要獲取接口的請求數據request params(如上圖所示),因為請求數據中帶有商品的信息和個人的位置信息,不同的位置可能會查詢到不同的倉庫庫存(待驗證)。

    定時請求商品信息api,查看商品庫存

    本文以Java為例,代碼僅供參考和學習討論。

    獲取到api信息后,我們就可以使用OkHttp或者webclient等請求工具類定時訪問api,查看商品庫存信息。

    引入pom依賴

    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>3.10.0</version>
    </dependency>

    OkHttpUtils代碼示例:

    package util;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import lombok.val;
    import okhttp3.*;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    import java.io.IOException;
    import java.net.URLEncoder;
    import java.security.SecureRandom;
    import java.security.cert.X509Certificate;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.Map;
    import java.util.concurrent.Semaphore;
    import java.util.concurrent.TimeUnit;
    public class OkHttpUtils {
        private static volatile OkHttpClient okHttpClient = null;
        private static volatile Semaphore semaphore = null;
        private Map<String, String> headerMap;
        private Map<String, String> paramMap;
        private String url;
        private Request.Builder request;
        /**
         * 初始化okHttpClient,并且允許https訪問
         */
        private OkHttpUtils() {
            if (okHttpClient == null) {
                synchronized (OkHttpUtils.class) {
                    if (okHttpClient == null) {
                        TrustManager[] trustManagers = buildTrustManagers();
                        okHttpClient = new OkHttpClient.Builder()
                                .connectTimeout(15, TimeUnit.SECONDS)
                                .writeTimeout(20, TimeUnit.SECONDS)
                                .readTimeout(20, TimeUnit.SECONDS)
                                .sslSocketFactory(createSSLSocketFactory(trustManagers), (X509TrustManager) trustManagers[0])
                                .hostnameVerifier((hostName, session) -> true)
                                .retryOnConnectionFailure(true)
                                .build();
                        addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
                    }
                }
            }
        }
        /**
         * 用于異步請求時,控制訪問線程數,返回結果
         *
         * @return
         */
        private static Semaphore getSemaphoreInstance() {
            //只能1個線程同時訪問
            synchronized (OkHttpUtils.class) {
                if (semaphore == null) {
                    semaphore = new Semaphore(0);
                }
            }
            return semaphore;
        }
        /**
         * 創建OkHttpUtils
         *
         * @return
         */
        public static OkHttpUtils builder() {
            return new OkHttpUtils();
        }
        /**
         * 添加url
         *
         * @param url
         * @return
         */
        public OkHttpUtils url(String url) {
            this.url = url;
            return this;
        }
        /**
         * 添加參數
         *
         * @param key   參數名
         * @param value 參數值
         * @return
         */
        public OkHttpUtils addParam(String key, String value) {
            if (paramMap == null) {
                paramMap = new LinkedHashMap<>(16);
            }
            paramMap.put(key, value);
            return this;
        }
        /**
         * 添加參數
         *
         * @param data
         * @return
         */
        public OkHttpUtils addParam(String data) {
            if (paramMap == null) {
                paramMap = new LinkedHashMap<>(16);
            }
            val hashMap = JSONObject.parseObject(data, HashMap.class);
            paramMap.putAll(hashMap);
            return this;
        }
        /**
         * 添加請求頭
         *
         * @param key   參數名
         * @param value 參數值
         * @return
         */
        public OkHttpUtils addHeader(String key, String value) {
            if (headerMap == null) {
                headerMap = new LinkedHashMap<>(16);
            }
            headerMap.put(key, value);
            return this;
        }
        /**
         * 初始化get方法
         *
         * @return
         */
        public OkHttpUtils get() {
            request = new Request.Builder().get();
            StringBuilder urlBuilder = new StringBuilder(url);
            if (paramMap != null) {
                urlBuilder.append("?");
                try {
                    for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                        urlBuilder.append(URLEncoder.encode(entry.getKey(), "utf-8")).
                                append("=").
                                append(URLEncoder.encode(entry.getValue(), "utf-8")).
                                append("&");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                urlBuilder.deleteCharAt(urlBuilder.length() - 1);
            }
            request.url(urlBuilder.toString());
            return this;
        }
        /**
         * 初始化post方法
         *
         * @param isJsonPost true等于json的方式提交數據,類似postman里post方法的raw
         *                   false等于普通的表單提交
         * @return
         */
        public OkHttpUtils post(boolean isJsonPost) {
            RequestBody requestBody;
            if (isJsonPost) {
                String json = "";
                if (paramMap != null) {
                    json = JSON.toJSONString(paramMap);
                }
                requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
            } else {
                FormBody.Builder formBody = new FormBody.Builder();
                if (paramMap != null) {
                    paramMap.forEach(formBody::add);
                }
                requestBody = formBody.build();
            }
            request = new Request.Builder().post(requestBody).url(url);
            return this;
        }
        /**
         * 同步請求
         *
         * @return
         */
        public String sync() {
            setHeader(request);
            try {
                Response response = okHttpClient.newCall(request.build()).execute();
                assert response.body() != null;
                return response.body().string();
            } catch (IOException e) {
                e.printStackTrace();
                return "請求失敗:" + e.getMessage();
            }
        }
        /**
         * 異步請求,有返回值
         */
        public String async() {
            StringBuilder buffer = new StringBuilder("");
            setHeader(request);
            okHttpClient.newCall(request.build()).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    buffer.append("請求出錯:").append(e.getMessage());
                }
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    assert response.body() != null;
                    buffer.append(response.body().string());
                    getSemaphoreInstance().release();
                }
            });
            try {
                getSemaphoreInstance().acquire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return buffer.toString();
        }
        /**
         * 異步請求,帶有接口回調
         *
         * @param callBack
         */
        public void async(ICallBack callBack) {
            setHeader(request);
            okHttpClient.newCall(request.build()).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    callBack.onFailure(call, e.getMessage());
                }
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    assert response.body() != null;
                    callBack.onSuccessful(call, response.body().string());
                }
            });
        }
        /**
         * 為request添加請求頭
         *
         * @param request
         */
        private void setHeader(Request.Builder request) {
            if (headerMap != null) {
                try {
                    for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                        request.addHeader(entry.getKey(), entry.getValue());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        /**
         * 生成安全套接字工廠,用于https請求的證書跳過
         *
         * @return
         */
        private static SSLSocketFactory createSSLSocketFactory(TrustManager[] trustAllCerts) {
            SSLSocketFactory ssfFactory = null;
            try {
                SSLContext sc = SSLContext.getInstance("SSL");
                sc.init(null, trustAllCerts, new SecureRandom());
                ssfFactory = sc.getSocketFactory();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return ssfFactory;
        }
        private static TrustManager[] buildTrustManagers() {
            return new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(X509Certificate[] chain, String authType) {
                        }
                        @Override
                        public void checkServerTrusted(X509Certificate[] chain, String authType) {
                        }
                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[]{};
                        }
                    }
            };
        }
        /**
         * 自定義一個接口回調
         */
        public interface ICallBack {
            void onSuccessful(Call call, String data);
            void onFailure(Call call, String errorMsg);
        }
    }

    定時查詢邏輯示例:

    import cn.hutool.core.date.DateUtil;
    import com.alibaba.fastjson.JSONObject;
    import entity.EmailDto;
    import lombok.SneakyThrows;
    import lombok.val;
    import org.junit.Test;
    import util.EmailUtil;
    import util.OkHttpUtils;
    /**
     * TODO
     *
     * @author Huangshaoyang
     * @date 2022-08-12 15:58:04
     */
    public class OkHttpTest {
        @Test
        @SneakyThrows
        public void t1() {
            // request params
            String data = "";
            while (true) {
                String res = OkHttpUtils.builder().url("https://xxxx/api/v1/xxx/goods-portal/spu/queryDetail")
                        // 有參數的話添加參數,可多個
                        .addParam(data)
                        // 也可以添加多個
                        .addHeader("Content-Type", "application/json; charset=utf-8")
                        // 如果是true的話,會類似于postman中post提交方式的raw,用json的方式提交,不是表單
                        // 如果是false的話傳統的表單提交
                        .post(true)
                        .sync();
    //            System.out.println(res);
                JSONObject json = JSONObject.parseObject(res);
                val stockQuantity = json.getJSONObject("data").getJSONObject("stockInfo").getIntValue("stockQuantity");
                System.out.println(DateUtil.now() + "   庫存:" + stockQuantity);
                if (stockQuantity > 0 ) {
                    sendNotify();
                } else {
                    Thread.sleep(10000);
                }
            }
        }
        @SneakyThrows
        private void sendNotify() {
            for (int i = 0; i < 3; i++) {
                System.out.println("send email");
                EmailUtil.sendTextEmail(EmailDto.builder()
                        .subject("有貨了快來搶購!!!")
                        .context("有貨了快來搶購!!!")
                        .build());
                Thread.sleep(60000);
            }
        }
    }

    注意點:

    • 請求不要太頻繁,不要違背爬蟲規則

    • 短信通知大部分是需要收費的,所以使用郵件通知

    發送消息通知

    本次案例使用的是qq郵件通知,qq郵箱發送需要進入設置中開啟pop3服務,開啟后會有一個獨立密碼用來發送郵件。

    發送郵件工具類示例:

    package util;
    import entity.EmailDto;
    import javax.activation.DataHandler;
    import javax.activation.DataSource;
    import javax.activation.FileDataSource;
    import javax.mail.*;
    import javax.mail.Message.RecipientType;
    import javax.mail.internet.*;
    import java.io.*;
    import java.util.Date;
    import java.util.Properties;
    /**
     * 使用SMTP協議發送電子郵件
     */ 
    public class EmailUtil1 {
        // 郵箱賬號 
        private final static String USERNAME = "xxx@qq.com";
        // 郵箱密碼
        private final static String PASSWORD = "xxx";
        // 郵件發送協議 
        private final static String PROTOCOL = "smtp"; 
        // SMTP郵件服務器 
        private final static String HOST = "smtp.qq.com"; 
        // SMTP郵件服務器默認端口 
        private final static String PORT = "587";
        // 發件人
        private static String from = "xxx@qq.com";
        // 是否要求身份認證 
        private final static String IS_AUTH = "true"; 
        // 是否啟用調試模式(啟用調試模式可打印客戶端與服務器交互過程時一問一答的響應消息) 
        private final static String IS_ENABLED_DEBUG_MOD = "false";
        // 收件人 
        private static String to = "aaa@qq.com";
        // 初始化連接郵件服務器的會話信息 
        private static Properties props = null;
        
        
        static { 
            props = new Properties(); 
            props.setProperty("mail.transport.protocol", PROTOCOL); 
            props.setProperty("mail.smtp.host", HOST); 
            props.setProperty("mail.smtp.port", PORT); 
            props.setProperty("mail.smtp.auth", IS_AUTH); 
            props.setProperty("mail.debug",IS_ENABLED_DEBUG_MOD);
    //        props.setProperty("mail.smtp.ssl.enable", "true");
        } 
        
        /**
         * 發送簡單的文本郵件
         */ 
        public static void sendTextEmail(EmailDto dto) throws Exception {
            // 創建Session實例對象 
            Session session = Session.getDefaultInstance(props); 
            // 創建MimeMessage實例對象 
            MimeMessage message = new MimeMessage(session); 
            // 設置發件人 
            message.setFrom(new InternetAddress(from)); 
            // 設置郵件主題 
            message.setSubject(dto.getSubject());
            // 設置收件人 
            message.setRecipient(RecipientType.TO, new InternetAddress(to)); 
            // 設置發送時間 
            message.setSentDate(new Date()); 
            // 設置純文本內容為郵件正文 
            message.setText(dto.getContext());
            // 保存并生成最終的郵件內容 
            message.saveChanges();
            // 獲得Transport實例對象
            Transport transport = session.getTransport(); 
            // 打開連接 
            transport.connect(USERNAME, PASSWORD); 
            // 將message對象傳遞給transport對象,將郵件發送出去 
            transport.sendMessage(message, message.getAllRecipients()); 
            // 關閉連接 
            transport.close(); 
        } 
        
    }

    到此,相信大家對“java開發如何實現訂閱到貨通知”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    新乡市| 竹北市| 金秀| 安新县| 开封县| 麻江县| 汝州市| 康平县| 长乐市| 墨玉县| 黄冈市| 丹东市| 巫溪县| 辽阳县| 石河子市| 砚山县| 县级市| 和静县| 庆元县| 广宁县| 赤峰市| 万盛区| 改则县| 新乐市| 徐州市| 磐安县| 长沙市| 南和县| 福海县| 观塘区| 曲松县| 疏勒县| 泽普县| 揭东县| 安丘市| 十堰市| 栖霞市| 兰坪| 平果县| 高邮市| 普定县|