国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Home WeChat Applet WeChat Development java WeChat development API WeChat custom personalized menu implementation example code

java WeChat development API WeChat custom personalized menu implementation example code

Mar 21, 2017 pm 03:46 PM
api java WeChat development

This article mainly introduces in detail the fourth step of java WeChat development API, custom menu and personalized menu implementation. Interested friends can refer to

How to implement custom personality in WeChat The following is an introduction to the menu.

1. Global description
Please refer to the first two articles for detailed description.

2. Description of this article
This article is divided into five parts:
* Encapsulation of tool class AccessTokenUtils
* Reading and analysis of custom menu and personalized menu documents
* Analysis of menu JSON and construction of corresponding beans
* Implementation of custom menu
* Implementation of personalized menu
All types of menus in WeChat custom menu will be demonstrated
At the end of this article Output all the demo source codes including the first four articles of this article

Encapsulation of tool class AccessTokenUtils
The acquisition and scheduled saving of AccessToken have been introduced in detail above However, the encapsulated AccessTokenUtils after processing is directly given here, and the implementation principle and document reading are no longer given.
AccessTokenUtils.java


package com.gist.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

import com.gist.bean.Access_token;
import com.google.gson.Gson;

/**
 * @author 高遠(yuǎn)</n> 郵箱:wgyscsf@163.com</n> 博客 http://blog.csdn.net/wgyscsf</n>
 *   編寫時期 2016-4-7 下午5:44:33
 */
public class AccessTokenUtils {
 private static final long MAX_TIME = 7200 * 1000;// 微信允許最長Access_token有效時間(ms)
 private static final String TAG = "WeixinApiTest";// TAG
 private static final String APPID = "wx889b020b3666b0b8";// APPID
 private static final String SECERT = "6da7676bf394f0a9f15fbf06027856bb";// 秘鑰

 /*
  * 該方法實(shí)現(xiàn)獲取Access_token、保存并且只保存2小時Access_token。如果超過兩個小時重新獲?。蝗绻麤]有超過兩個小時,直接獲取。該方法依賴
  * :public static String getAccessToken();
  * 
  * 思路:將獲取到的Access_token和當(dāng)前時間存儲到file里,
  * 取出時判斷當(dāng)前時間和存儲里面的記錄的時間的時間差,如果大于MAX_TIME,重新獲取,并且將獲取到的存儲到file替換原來的內(nèi)容
  * ,如果小于MAX_TIME,直接獲取。
  */
 // 為了調(diào)用不拋異常,這里全部捕捉異常,代碼有點(diǎn)長
 public static String getSavedAccess_token() {
  Gson gson = new Gson();// 第三方j(luò)ar,處理json和bean的轉(zhuǎn)換
  String mAccess_token = null;// 需要獲取的Access_token;
  FileOutputStream fos = null;// 輸出流
  FileInputStream fis = null;// 輸入流
  File file = new File("temp_access_token.temp");// Access_token保存的位置
  try {
   // 如果文件不存在,創(chuàng)建
   if (!file.exists()) {
    file.createNewFile();
   }
  } catch (Exception e1) {
   e1.printStackTrace();
  }
  // 如果文件大小等于0,說明第一次使用,存入Access_token
  if (file.length() == 0) {
   try {
    mAccess_token = getAccessToken();// 獲取AccessToken
    Access_token at = new Access_token();
    at.setAccess_token(mAccess_token);
    at.setExpires_in(System.currentTimeMillis() + "");// 設(shè)置存入時間
    String json = gson.toJson(at);
    fos = new FileOutputStream(file, false);// 不允許追加
    fos.write((json).getBytes());// 將AccessToken和當(dāng)前時間存入文件
    fos.close();
    return mAccess_token;
   } catch (Exception e) {
    e.printStackTrace();
   }
  } else {
   // 讀取文件內(nèi)容
   byte[] b = new byte[2048];
   int len = 0;
   try {
    fis = new FileInputStream(file);
    len = fis.read(b);
   } catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
   }
   String mJsonAccess_token = new String(b, 0, len);// 讀取到的文件內(nèi)容
   Access_token access_token = gson.fromJson(mJsonAccess_token,
     new Access_token().getClass());
   if (access_token.getExpires_in() != null) {
    long saveTime = Long.parseLong(access_token.getExpires_in());
    long nowTime = System.currentTimeMillis();
    long remianTime = nowTime - saveTime;
    // System.out.println(TAG + "時間差:" + remianTime + "ms");
    if (remianTime < MAX_TIME) {
     Access_token at = gson.fromJson(mJsonAccess_token,
       new Access_token().getClass());
     mAccess_token = at.getAccess_token();
     return mAccess_token;
    } else {
     mAccess_token = getAccessToken();
     Access_token at = new Access_token();
     at.setAccess_token(mAccess_token);
     at.setExpires_in(System.currentTimeMillis() + "");
     String json = gson.toJson(at);
     try {
      fos = new FileOutputStream(file, false);// 不允許追加
      fos.write((json).getBytes());
      fos.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     return mAccess_token;
    }

   } else {
    return null;
   }
  }

  return mAccess_token;
 }

 /*
  * 獲取微信服務(wù)器AccessToken。該部分和getAccess_token() 一致,不再加注釋
  */
 public static String getAccessToken() {
  String urlString = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
    + APPID + "&secret=" + SECERT;
  String reslut = null;
  try {
   URL reqURL = new URL(urlString);
   HttpsURLConnection httpsConn = (HttpsURLConnection) reqURL
     .openConnection();
   InputStreamReader isr = new InputStreamReader(
     httpsConn.getInputStream());
   char[] chars = new char[1024];
   reslut = "";
   int len;
   while ((len = isr.read(chars)) != -1) {
    reslut += new String(chars, 0, len);
   }
   isr.close();
  } catch (IOException e) {

   e.printStackTrace();
  }
  Gson gson = new Gson();
  Access_token access_token = gson.fromJson(reslut,
    new Access_token().getClass());
  if (access_token.getAccess_token() != null) {
   return access_token.getAccess_token();
  } else {
   return null;
  }
 }
}

Reading and parsing of custom menu and personalized menu documents
?Auto Define menu
?Custom menu creation interface
?Custom menu query interface
?Custom menu deletion interface
?Custom menu event push
?Personalized menu interface
? Get the menu configuration of the public account

?Document address: http://mp.weixin.qq.com/wiki/10/0234e39a2025342c17a7d23595c6b40a.html
?The official website document gives this Explanation:
* The custom menu interface can implement multiple types of buttons, as follows: 1. click: click event...; 2. view: jump event...; 3.... (About custom menu )
* Interface call request description http request method: POST (please use https protocol) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN( About custom menu)
* Click and view request example {"button":[...]} (About custom menu)
* Parameter description...(About custom menu)
* Create personalized menu http request method: POST (please use https protocol) https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=ACCESS_TOKEN(About personalized menu )
* Request example: {"button":[...],"matchrule":{...}}(About personalized menu)
* Parameter description...(About personalized menu)
* Developers can set the menu that users see (about personalized menus) through the following conditions:
1. User grouping (the developer's business needs can be completed with the help of user grouping)
2. Gender
3. Mobile operating system
4. Region (the region set by the user on the WeChat client)
5. Language (the language set by the user on the WeChat client)

?Understanding:
?It is the familiar POST request again, but the call seems to be vague and I don’t quite understand it. We just know that we need to use the "?access_token=ACCESS_TOKEN" parameter, which we have already obtained in the previous article. If we replace the "ACCESS_TOKEN" in the request address given by the WeChat document with our own ACCESS_TOKEN we obtained, and visit the URL, we will see "{"errcode":44002,"errmsg":"empty post data hint: [ Gdveda0984vr23]”}”. It probably means empty post request data. Therefore, we need to pass the parameters to the WeChat server in the form of a POST request. The parameter format is also given below the document: {"button":[...]}, so we need to pass the parameters to the WeChat server according to this format.
? Regarding parameter description, we can see that there are seven parameters in custom menu creation. In addition to these seven parameters, there are eight more parameters in the personalized menu interface. Simply looking at this part of the document, we can understand that these eight parameters are used for matching and screening of personalized menus.
?Now, we need to construct json according to the requirements of WeChat documents and send this string of json data to the WeChat server through post requests. The json includes various types of button events we created.

Menu JSON analysis and construction of corresponding beans
Custom menu json analysis (excluding personalized menus). The following code is an example given by WeChat documentation.
Click and view request examples


 {
  "button":[
  { 
   "type":"click",
   "name":"今日歌曲",
   "key":"V1001_TODAY_MUSIC"
  },
  {
   "name":"菜單",
   "sub_button":[
   { 
    "type":"view",
    "name":"搜索",
    "url":"http://www.soso.com/"
   },
   {
    "type":"view",
    "name":"視頻",
    "url":"http://v.qq.com/"
   },
   {
    "type":"click",
    "name":"贊一下我們",
    "key":"V1001_GOOD"
   }]
  }]
 }

經(jīng)過分析我們可以看到這串json數(shù)據(jù)分為三層:“”button”:[{…},{…}]”、“[{…},{{“name”:菜單,”sub_button”:[{},{}]}]”、“{“type”:”view”,”name:”:”視頻”,”url”:”…”},{},{}”,可能看起來比較暈。
但是,如果我們能夠聯(lián)想起來現(xiàn)實(shí)中看到的微信菜單,就會好理解一點(diǎn):一級:菜單(一個菜單),下包括一到三個父按鈕;二級:父按鈕(1~3個父按鈕),下包括一到五個子按鈕;三級:子按鈕(1~5個子按鈕)。
現(xiàn)在,我們可以看到j(luò)son和我們理解的“菜單”可以一一對應(yīng)起來了。現(xiàn)在重點(diǎn)是如何確認(rèn)每一級的“級名”,在java中也就是對應(yīng)的javabean對象。
同時,因?yàn)橐患壊藛蜗聲卸鄠€父按鈕,所以是一個List<父菜單>的形式。父按鈕下可能有多個子菜單,也是一個 List<子菜單>;但是,父按鈕也有可能也是一個單獨(dú)的可以響應(yīng)的按鈕。是一個單獨(dú)的父按鈕對象。子按鈕就是一個單獨(dú)的子按鈕對象。
查看關(guān)于自定義菜單的參數(shù)說明,我們可以看到按鈕分為一級按鈕(“button”)和二級按鈕(“sub_button”)。還有一些公用的數(shù)據(jù)類型,例如:菜單響應(yīng)類型(“type”)、菜單標(biāo)題(“name”)、click類型的參數(shù)(“key”)、view類型的參數(shù)(“url”)、media_id類型和view_limited類型的參數(shù)(“media_id”)。
?數(shù)據(jù)抽象(沒有寫setter,getter):


//按鈕基類
public class BaseButton {
 private String type;
 private String name;
 private String key;
 private String url;
 private String media_id;
} 
//子按鈕
public class SonButton extends BaseButton {
 private String sub_button;
}
//父按鈕
public class FatherButton extends BaseButton {
private String button;//可能直接一個父按鈕做響應(yīng)
@SerializedName("sub_button")//為了保證Gson解析后子按鈕的名字是“sub_button”,具體用法請搜索
private List<SonButton> sonButtons;//可能有多個子按鈕
}

public class Menu {
@SerializedName("button")
private List<FatherButton> fatherButtons;
}

以上是完整的自定義菜單的分析以及對應(yīng)javabean的構(gòu)建。

對于個性化菜單,如果查看該部分的文檔,會發(fā)現(xiàn)和自定義菜單大致相同,只是多個一個“配置”的json,格式是這樣的:{“button”:[…],”matchrule”:{…}}。
我們發(fā)現(xiàn),“匹配”這段json和“button”是同級的,分析和實(shí)現(xiàn)和上面基本等同,直接給出實(shí)現(xiàn)的javabean。


//匹配的json對應(yīng)的json
public class MatchRule {
private String group_id;
private String sex;
private String client_platform_type;
private String country;
private String province;
private String city;
private String language;
}

//修改Menu.java
public class Menu {
@SerializedName("button")
private List<FatherButton> fatherButtons;
private MatchRule matchrule;
}

自定義菜單的實(shí)現(xiàn)
任務(wù),我們實(shí)現(xiàn)所有微信按鈕響應(yīng)類型:
任務(wù)(注釋:“m-0”表示父按鈕;“m-n”表示第m個父按鈕,第n個子按鈕(m,n≠0)):1-0:名字:click,響應(yīng)點(diǎn)擊事件:點(diǎn)擊推事件 。2-0:名字:父按鈕2。2-1:名字:view,響應(yīng)事件:跳轉(zhuǎn)網(wǎng)頁;2-2:名字:scancode_push,響應(yīng)事件:掃碼推事件;2-3:名字:scancode_waitmsg,響應(yīng)事件:掃碼推事件且彈出“消息接收中”提示框;2-4:名字:pic_sysphoto,響應(yīng)事件
:彈出系統(tǒng)拍照發(fā)圖。2-5:名字:pic_photo_or_album,響應(yīng)事件:彈出拍照或者相冊發(fā)圖。3-0:名字:父按鈕3。3-1:名字
:pic_weixin,響應(yīng)事件:彈出微信相冊發(fā)圖器;3-2:名字:location_select,響應(yīng)事件:彈出地理位置選擇器;3-3:名字:media_id,響應(yīng)事件:下發(fā)消息(除文本消息);3-4:名字:view_limited,響應(yīng)事件:跳轉(zhuǎn)圖文消息url。

實(shí)現(xiàn)源碼(引用的AccessTokenUtils.java在第一部分:工具類AccessTokenUtils的封裝)


 /*
  * 創(chuàng)建自定義菜單。
  */
 @Test
 public void createCommMenu() {
  String ACCESS_TOKEN = AccessTokenUtils.getAccessToken();// 獲取AccessToken,AccessTokenUtils是封裝好的類
  // 拼接api要求的httpsurl鏈接
  String urlString = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="
    + ACCESS_TOKEN;
  try {
   // 創(chuàng)建一個url
   URL reqURL = new URL(urlString);
   // 拿取鏈接
   HttpsURLConnection httpsConn = (HttpsURLConnection) reqURL
     .openConnection();
   httpsConn.setDoOutput(true);
   // 取得該連接的輸出流,以讀取響應(yīng)內(nèi)容
   OutputStreamWriter osr = new OutputStreamWriter(
     httpsConn.getOutputStream());
   osr.write(getMenuJson());// 使用本類外部方法getMenuJson()
   osr.close();

   // 返回結(jié)果
   InputStreamReader isr = new InputStreamReader(
     httpsConn.getInputStream());
   // 讀取服務(wù)器的響應(yīng)內(nèi)容并顯示
   char[] chars = new char[1024];
   String reslut = "";
   int len;
   while ((len = isr.read(chars)) != -1) {
    reslut += new String(chars, 0, len);
   }
   System.out.println("返回結(jié)果:" + reslut);
   isr.close();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }

 public String getMenuJson() {
  Gson gson = new Gson();// json處理工具

  Menu menu = new Menu();// 菜單類
  List<FatherButton> fatherButtons = new ArrayList<FatherButton>();// 菜單中的父按鈕集合
  // -----------
  // 父按鈕1
  FatherButton fb1 = new FatherButton();
  fb1.setName("click");
  fb1.setType("click");
  fb1.setKey("10");
  // -------------
  // 父按鈕2
  FatherButton fb2 = new FatherButton();
  fb2.setName("父按鈕2");
  List<SonButton> sonButtons2 = new ArrayList<SonButton>();// 子按鈕的集合

  // 子按鈕2-1
  SonButton sb21 = new SonButton();
  sb21.setName("view");
  sb21.setUrl("http://www.baidu.com");
  sb21.setType("view");
  // 子按鈕2-2
  SonButton sb22 = new SonButton();
  sb22.setName("scancode_push");
  sb22.setType("scancode_push");
  sb22.setKey("22");
  // 子按鈕2-3
  SonButton sb23 = new SonButton();
  sb23.setName("scancode_waitmsg");
  sb23.setType("scancode_waitmsg");
  sb23.setKey("23");
  // 子按鈕2-4
  SonButton sb24 = new SonButton();
  sb24.setName("pic_sysphoto");
  sb24.setType("pic_sysphoto");
  sb24.setKey("24");
  // 子按鈕2-5
  SonButton sb25 = new SonButton();
  sb25.setName("pic_photo_or_album");
  sb25.setType("pic_photo_or_album");
  sb25.setKey("25");

  // 添加子按鈕到子按鈕集合
  sonButtons2.add(sb21);
  sonButtons2.add(sb22);
  sonButtons2.add(sb23);
  sonButtons2.add(sb24);
  sonButtons2.add(sb25);

  // 將子按鈕放到2-0父按鈕集合
  fb2.setSonButtons(sonButtons2);

  // ------------------
  // 父按鈕3
  FatherButton fb3 = new FatherButton();
  fb3.setName("父按鈕3");
  List<SonButton> sonButtons3 = new ArrayList<SonButton>();

  // 子按鈕3-1
  SonButton sb31 = new SonButton();
  sb31.setName("pic_weixin");
  sb31.setType("pic_weixin");
  sb31.setKey("31");
  // 子按鈕3-2
  SonButton sb32 = new SonButton();
  sb32.setName("locatselect");
  sb32.setType("location_select");
  sb32.setKey("32");
  // // 子按鈕3-3-->測試不了,因?yàn)橐猰edia_id。這需要調(diào)用素材id.
  // SonButton sb33 = new SonButton();
  // sb33.setName("media_id");
  // sb33.setType("media_id");
  // sb33.setMedia_id("???");
  // // 子按鈕3-4-->測試不了,因?yàn)橐猰edia_id。這需要調(diào)用素材id.
  // SonButton sb34 = new SonButton();
  // sb34.setName("view_limited");
  // sb34.setType("view_limited");
  // sb34.setMedia_id("???");

  // 添加子按鈕到子按鈕隊列
  sonButtons3.add(sb31);
  sonButtons3.add(sb32);
  // sonButtons3.add(sb33);
  // sonButtons3.add(sb34);

  // 將子按鈕放到3-0父按鈕隊列
  fb3.setSonButtons(sonButtons3);
  // ---------------------

  // 將父按鈕加入到父按鈕集合
  fatherButtons.add(fb1);
  fatherButtons.add(fb2);
  fatherButtons.add(fb3);

  // 將父按鈕隊列加入到菜單欄
  menu.setFatherButtons(fatherButtons);
  String json = gson.toJson(menu);
  System.out.println(json);// 測試輸出
  return json;

 }

個性化菜單的實(shí)現(xiàn)
?任務(wù):根據(jù)性別展示不同的按鈕顯示(可以根據(jù)性別、地區(qū)、分組手機(jī)操作系統(tǒng)等)
?修改代碼一,因?yàn)槭遣煌奈⑿藕笈_實(shí)現(xiàn),所以接口也不一樣,不過還是POST請求,代碼不用改,只要替換原來urlString即可。


// 拼接api要求的httpsurl鏈接
String urlString = "https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token="
   + ACCESS_TOKEN;

?修改代碼二,只要創(chuàng)建一個MatchRule,設(shè)置匹配規(guī)則,然后將matchrule加入到menu便可以完成匹配規(guī)則。


// -----
// 從此處開始設(shè)置個性菜單
MatchRule matchrule = new MatchRule();
matchrule.setSex("2");// 男生
menu.setMatchrule(matchrule);
// ----

The above is the detailed content of java WeChat development API WeChat custom personalized menu implementation example code. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

PHP Tutorial
1502
276
How to handle transactions in Java with JDBC? How to handle transactions in Java with JDBC? Aug 02, 2025 pm 12:29 PM

To correctly handle JDBC transactions, you must first turn off the automatic commit mode, then perform multiple operations, and finally commit or rollback according to the results; 1. Call conn.setAutoCommit(false) to start the transaction; 2. Execute multiple SQL operations, such as INSERT and UPDATE; 3. Call conn.commit() if all operations are successful, and call conn.rollback() if an exception occurs to ensure data consistency; at the same time, try-with-resources should be used to manage resources, properly handle exceptions and close connections to avoid connection leakage; in addition, it is recommended to use connection pools and set save points to achieve partial rollback, and keep transactions as short as possible to improve performance.

How to work with Calendar in Java? How to work with Calendar in Java? Aug 02, 2025 am 02:38 AM

Use classes in the java.time package to replace the old Date and Calendar classes; 2. Get the current date and time through LocalDate, LocalDateTime and LocalTime; 3. Create a specific date and time using the of() method; 4. Use the plus/minus method to immutably increase and decrease the time; 5. Use ZonedDateTime and ZoneId to process the time zone; 6. Format and parse date strings through DateTimeFormatter; 7. Use Instant to be compatible with the old date types when necessary; date processing in modern Java should give priority to using java.timeAPI, which provides clear, immutable and linear

Comparing Java Frameworks: Spring Boot vs Quarkus vs Micronaut Comparing Java Frameworks: Spring Boot vs Quarkus vs Micronaut Aug 04, 2025 pm 12:48 PM

Pre-formanceTartuptimeMoryusage, Quarkusandmicronautleadduetocompile-Timeprocessingandgraalvsupport, Withquarkusoftenperforminglightbetterine ServerLess scenarios.2.Thyvelopecosyste,

H5 Payment Handler API for Custom Payment Flows H5 Payment Handler API for Custom Payment Flows Aug 02, 2025 pm 01:37 PM

PaymentHandlerAPI is part of the WebPayments standard, as an extension of PaymentRequestAPI, and its core role is to allow developers to register a "payment processor" to implement custom payment processes. It registers payment methods through ServiceWorker and combines the payment application manifest file under the .well-known directory to declare payment processor information. When used, the payment request is initiated through the PaymentRequest interface, the registered payment processor is called, and the complete() method is called after the payment is completed. Common precautions include: 1. Ensure HTTPS deployment; 2. Properly configure Service

How does garbage collection work in Java? How does garbage collection work in Java? Aug 02, 2025 pm 01:55 PM

Java's garbage collection (GC) is a mechanism that automatically manages memory, which reduces the risk of memory leakage by reclaiming unreachable objects. 1.GC judges the accessibility of the object from the root object (such as stack variables, active threads, static fields, etc.), and unreachable objects are marked as garbage. 2. Based on the mark-clearing algorithm, mark all reachable objects and clear unmarked objects. 3. Adopt a generational collection strategy: the new generation (Eden, S0, S1) frequently executes MinorGC; the elderly performs less but takes longer to perform MajorGC; Metaspace stores class metadata. 4. JVM provides a variety of GC devices: SerialGC is suitable for small applications; ParallelGC improves throughput; CMS reduces

Using HTML `input` Types for User Data Using HTML `input` Types for User Data Aug 03, 2025 am 11:07 AM

Choosing the right HTMLinput type can improve data accuracy, enhance user experience, and improve usability. 1. Select the corresponding input types according to the data type, such as text, email, tel, number and date, which can automatically checksum and adapt to the keyboard; 2. Use HTML5 to add new types such as url, color, range and search, which can provide a more intuitive interaction method; 3. Use placeholder and required attributes to improve the efficiency and accuracy of form filling, but it should be noted that placeholder cannot replace label.

go by example http middleware logging example go by example http middleware logging example Aug 03, 2025 am 11:35 AM

HTTP log middleware in Go can record request methods, paths, client IP and time-consuming. 1. Use http.HandlerFunc to wrap the processor, 2. Record the start time and end time before and after calling next.ServeHTTP, 3. Get the real client IP through r.RemoteAddr and X-Forwarded-For headers, 4. Use log.Printf to output request logs, 5. Apply the middleware to ServeMux to implement global logging. The complete sample code has been verified to run and is suitable for starting a small and medium-sized project. The extension suggestions include capturing status codes, supporting JSON logs and request ID tracking.

Comparing Java Build Tools: Maven vs. Gradle Comparing Java Build Tools: Maven vs. Gradle Aug 03, 2025 pm 01:36 PM

Gradleisthebetterchoiceformostnewprojectsduetoitssuperiorflexibility,performance,andmoderntoolingsupport.1.Gradle’sGroovy/KotlinDSLismoreconciseandexpressivethanMaven’sverboseXML.2.GradleoutperformsMaveninbuildspeedwithincrementalcompilation,buildcac

See all articles