diff --git a/solon-plugins/pom.xml b/solon-plugins/pom.xml
index 3bec9cb542..8d14b4461a 100644
--- a/solon-plugins/pom.xml
+++ b/solon-plugins/pom.xml
@@ -14,7 +14,7 @@
   <description>WxJava 各个模块的 Solon Plugin</description>
 
   <properties>
-    <solon.version>3.0.1</solon.version>
+    <solon.version>3.2.0</solon.version>
   </properties>
 
   <modules>
diff --git a/solon-plugins/wx-java-channel-solon-plugin/README.md b/solon-plugins/wx-java-channel-solon-plugin/README.md
new file mode 100644
index 0000000000..a7168a8edc
--- /dev/null
+++ b/solon-plugins/wx-java-channel-solon-plugin/README.md
@@ -0,0 +1,92 @@
+# wx-java-channel-solon-plugin
+
+## 快速开始
+1. 引入依赖
+    ```xml
+    <dependencies>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>wx-java-channel-solon-plugin</artifactId>
+            <version>${version}</version>
+        </dependency>
+   
+        <!-- 配置存储方式为jedis 则引入jedis -->
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>${jedis.version}</version>
+        </dependency>
+
+        <!-- 配置存储方式为redisson 则引入redisson -->
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+            <version>${redisson.version}</version>
+        </dependency>
+    </dependencies>
+    ```
+2. 添加配置(app.properties)
+    ```properties
+    # 视频号配置(必填)
+    ## 视频号小店的appId和secret
+    wx.channel.app-id=@appId
+    wx.channel.secret=@secret
+    # 视频号配置 选填
+    ## 设置视频号小店消息服务器配置的token
+    wx.channel.token=@token
+    ## 设置视频号小店消息服务器配置的EncodingAESKey
+    wx.channel.aes-key=
+    ## 支持JSON或者XML格式,默认JSON
+    wx.channel.msg-data-format=JSON
+    ## 是否使用稳定版 Access Token
+    wx.channel.use-stable-access-token=false
+    
+    
+    # ConfigStorage 配置(选填)
+    ## 配置类型: memory(默认), jedis, redisson, redis_template
+    wx.channel.config-storage.type=memory
+    ## 相关redis前缀配置: wx:channel(默认)
+    wx.channel.config-storage.key-prefix=wx:channel
+    wx.channel.config-storage.redis.host=127.0.0.1
+    wx.channel.config-storage.redis.port=6379
+    wx.channel.config-storage.redis.password=123456
+ 
+    
+    # http 客户端配置(选填)
+    ## # http客户端类型: http_client(默认)
+    wx.channel.config-storage.http-client-type=http_client
+    wx.channel.config-storage.http-proxy-host=
+    wx.channel.config-storage.http-proxy-port=
+    wx.channel.config-storage.http-proxy-username=
+    wx.channel.config-storage.http-proxy-password=
+    ## 最大重试次数,默认:5 次,如果小于 0,则为 0
+    wx.channel.config-storage.max-retry-times=5
+    ## 重试时间间隔步进,默认:1000 毫秒,如果小于 0,则为 1000
+    wx.channel.config-storage.retry-sleep-millis=1000
+    ```
+3. 自动注入的类型
+- `WxChannelService`
+- `WxChannelConfig`
+4. 使用样例
+
+```java
+import me.chanjar.weixin.channel.api.WxChannelService;
+import me.chanjar.weixin.channel.bean.shop.ShopInfoResponse;
+import me.chanjar.weixin.channel.util.JsonUtils;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.noear.solon.annotation.Inject;
+
+@Component
+public class DemoService {
+  @Inject
+  private WxChannelService wxChannelService;
+
+  public String getShopInfo() throws WxErrorException {
+    // 获取店铺基本信息
+    ShopInfoResponse response = wxChannelService.getBasicService().getShopInfo();
+    // 此处为演示,如果要返回response的结果,建议自己封装一个VO,避免直接返回response
+    return JsonUtils.encode(response);
+  }
+}
+```
+
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java
index 8b6b0689a7..e26b152daf 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java
@@ -403,7 +403,7 @@ public class WxCpTpXmlMessage implements Serializable {
    * The Agent id.
    */
   @XStreamAlias("AgentID")
-  protected String agentID;
+  protected Integer agentID;
 
   /**
    * The Pic url.
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java
index 7193c7cf6f..798a5c8b00 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java
@@ -118,7 +118,7 @@ public static class NotifyNode implements Serializable {
     /**
      * 抄送人userid
      */
-    @XStreamAlias("ItemUserid")
+    @XStreamAlias("ItemUserId")
     @XStreamConverter(value = XStreamCDataConverter.class)
     private String itemUserId;
 
@@ -190,7 +190,7 @@ public static class Item implements Serializable {
     /**
      * 分支审批人userid
      */
-    @XStreamAlias("ItemUserid")
+    @XStreamAlias("ItemUserId")
     @XStreamConverter(value = XStreamCDataConverter.class)
     private String itemUserId;
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java
index 8a9d2130d6..c88cb7b9be 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java
@@ -603,7 +603,7 @@ public static class File implements Serializable {
     private String sdkFileId;
 
     @SerializedName("filesize")
-    private Integer fileSize;
+    private Long fileSize;
 
     /**
      * From json file.
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java
index d6cd827630..28246cf00b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java
@@ -152,7 +152,7 @@ public void enterAppTest() {
     assertEquals(wxXmlMessage.getCreateTime(), Long.valueOf(1408091189));
     assertEquals(wxXmlMessage.getEvent(), "enter_agent");
     assertEquals(wxXmlMessage.getEventKey(), "");
-    assertEquals(wxXmlMessage.getAgentID(), Integer.valueOf(1));
+    assertEquals(wxXmlMessage.getAgentID(), 1);
   }
 
   /**
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java
index 43f41e9639..75db10a070 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java
@@ -227,6 +227,11 @@ public class WxPayConfig {
    */
   private Verifier verifier;
 
+  /**
+   * 是否将全部v3接口的请求都添加Wechatpay-Serial请求头,默认不添加
+   */
+  private boolean strictlyNeedWechatPaySerial = false;
+
   /**
    * 返回所设置的微信支付接口请求地址域名.
    *
@@ -295,13 +300,13 @@ public CloseableHttpClient initApiV3HttpClient() throws WxPayException {
       this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
     }
     try {
-      if (merchantPrivateKey == null) {
+      if (merchantPrivateKey == null && StringUtils.isNotBlank(this.getPrivateKeyPath())) {
         try (InputStream keyInputStream = this.loadConfigInputStream(this.getPrivateKeyString(), this.getPrivateKeyPath(),
           this.privateKeyContent, "privateKeyPath")) {
           merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream);
         }
       }
-      if (certificate == null && StringUtils.isBlank(this.getCertSerialNo())) {
+      if (certificate == null && StringUtils.isBlank(this.getCertSerialNo()) && StringUtils.isNotBlank(this.getPrivateCertPath())) {
         try (InputStream certInputStream = this.loadConfigInputStream(this.getPrivateCertString(), this.getPrivateCertPath(),
           this.privateCertContent, "privateCertPath")) {
           certificate = PemUtils.loadCertificate(certInputStream);
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
index 05d1f8c22e..530609a7dd 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
@@ -251,7 +251,7 @@ public WxPayRefundResult refundV2(WxPayRefundRequest request) throws WxPayExcept
   @Override
   public WxPayRefundV3Result refundV3(WxPayRefundV3Request request) throws WxPayException {
     String url = String.format("%s/v3/refund/domestic/refunds", this.getPayBaseUrl());
-    String response = this.postV3(url, GSON.toJson(request));
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(response, WxPayRefundV3Result.class);
   }
 
@@ -294,21 +294,21 @@ public WxPayRefundQueryResult refundQueryV2(WxPayRefundQueryRequest request) thr
   @Override
   public WxPayRefundQueryV3Result refundQueryV3(String outRefundNo) throws WxPayException {
     String url = String.format("%s/v3/refund/domestic/refunds/%s", this.getPayBaseUrl(), outRefundNo);
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, WxPayRefundQueryV3Result.class);
   }
 
   @Override
   public WxPayRefundQueryV3Result refundQueryV3(WxPayRefundQueryV3Request request) throws WxPayException {
     String url = String.format("%s/v3/refund/domestic/refunds/%s", this.getPayBaseUrl(), request.getOutRefundNo());
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, WxPayRefundQueryV3Result.class);
   }
 
   @Override
   public WxPayRefundQueryV3Result refundPartnerQueryV3(WxPayRefundQueryV3Request request) throws WxPayException {
     String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(), request.getSubMchid());
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, WxPayRefundQueryV3Result.class);
   }
 
@@ -523,7 +523,7 @@ public WxPayOrderQueryV3Result queryOrderV3(WxPayOrderQueryV3Request request) th
       url = String.format("%s/v3/pay/transactions/id/%s", this.getPayBaseUrl(), request.getTransactionId());
     }
     String query = String.format("?mchid=%s", request.getMchid());
-    String response = this.getV3(url + query);
+    String response = this.getV3WithWechatPaySerial(url + query);
     return GSON.fromJson(response, WxPayOrderQueryV3Result.class);
   }
 
@@ -548,14 +548,14 @@ public WxPayPartnerOrderQueryV3Result queryPartnerOrderV3(WxPayPartnerOrderQuery
       url = String.format("%s/v3/pay/partner/transactions/id/%s", this.getPayBaseUrl(), request.getTransactionId());
     }
     String query = String.format("?sp_mchid=%s&sub_mchid=%s", request.getSpMchId(), request.getSubMchId());
-    String response = this.getV3(url + query);
+    String response = this.getV3WithWechatPaySerial(url + query);
     return GSON.fromJson(response, WxPayPartnerOrderQueryV3Result.class);
   }
 
   @Override
   public CombineQueryResult queryCombine(String combineOutTradeNo) throws WxPayException {
     String url = String.format("%s/v3/combine-transactions/out-trade-no/%s", this.getPayBaseUrl(), combineOutTradeNo);
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, CombineQueryResult.class);
   }
 
@@ -609,7 +609,7 @@ public void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException
       request.setMchid(this.getConfig().getMchId());
     }
     String url = String.format("%s/v3/pay/transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getOutTradeNo());
-    this.postV3(url, GSON.toJson(request));
+    this.postV3WithWechatpaySerial(url, GSON.toJson(request));
   }
 
   @Override
@@ -621,13 +621,13 @@ public void closePartnerOrderV3(WxPayPartnerOrderCloseV3Request request) throws
       request.setSubMchId(this.getConfig().getSubMchId());
     }
     String url = String.format("%s/v3/pay/partner/transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getOutTradeNo());
-    this.postV3(url, GSON.toJson(request));
+    this.postV3WithWechatpaySerial(url, GSON.toJson(request));
   }
 
   @Override
   public void closeCombine(CombineCloseRequest request) throws WxPayException {
     String url = String.format("%s/v3/combine-transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getCombineOutTradeNo());
-    this.postV3(url, GSON.toJson(request));
+    this.postV3WithWechatpaySerial(url, GSON.toJson(request));
   }
 
   @Override
@@ -771,7 +771,7 @@ public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType,
     }
 
     String url = this.getPayBaseUrl() + tradeType.getBasePartnerUrl();
-    String response = this.postV3(url, GSON.toJson(request));
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class);
   }
 
@@ -788,7 +788,7 @@ public WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUn
     }
 
     String url = this.getPayBaseUrl() + tradeType.getPartnerUrl();
-    String response = this.postV3(url, GSON.toJson(request));
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class);
   }
 
@@ -801,7 +801,7 @@ public CombineTransactionsResult combine(TradeTypeEnum tradeType, CombineTransac
       request.setCombineMchid(this.getConfig().getMchId());
     }
     String url = this.getPayBaseUrl() + tradeType.getCombineUrl();
-    String response = this.postV3(url, GSON.toJson(request));
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(response, CombineTransactionsResult.class);
   }
 
@@ -1114,7 +1114,7 @@ public WxPayApplyBillV3Result applyTradeBill(WxPayApplyTradeBillV3Request reques
     } else {
       url = String.format("%s/v3/bill/tradebill?bill_date=%s&bill_type=%s&tar_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getBillType(), request.getTarType());
     }
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, WxPayApplyBillV3Result.class);
   }
 
@@ -1126,7 +1126,7 @@ public WxPayApplyBillV3Result applyFundFlowBill(WxPayApplyFundFlowBillV3Request
     } else {
       url = String.format("%s/v3/bill/fundflowbill?bill_date=%s&account_type=%s&tar_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getAccountType(), request.getTarType());
     }
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, WxPayApplyBillV3Result.class);
   }
 
@@ -1155,7 +1155,7 @@ public WxPayCodepayResult codepay(WxPayCodepayRequest request) throws WxPayExcep
       request.setMchid(this.getConfig().getMchId());
     }
     String url = String.format("%s/v3/pay/transactions/codepay", this.getPayBaseUrl());
-    String body = this.postV3(url, GSON.toJson(request));
+    String body = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(body, WxPayCodepayResult.class);
   }
 
@@ -1181,7 +1181,7 @@ public WxPayOrderReverseV3Result reverseOrderV3(WxPayOrderReverseV3Request reque
     }
     // 拼接参数请求路径并发送
     String url = String.format("%s/v3/pay/transactions/out-trade-no/%s/reverse", this.getPayBaseUrl(), request.getOutTradeNo());
-    String response = this.postV3(url, GSON.toJson(request));
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(response, WxPayOrderReverseV3Result.class);
   }
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
index d8ba95971e..f273fe1f97 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
@@ -44,6 +44,7 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
   private static final String ACCEPT = "Accept";
   private static final String CONTENT_TYPE = "Content-Type";
   private static final String APPLICATION_JSON = "application/json";
+  private static final String WECHATPAY_SERIAL = "Wechatpay-Serial";
 
   @Override
   public byte[] postForBytes(String url, String requestStr, boolean useKey) throws WxPayException {
@@ -101,7 +102,7 @@ public String postV3(String url, String requestStr) throws WxPayException {
     httpPost.addHeader(ACCEPT, APPLICATION_JSON);
     httpPost.addHeader(CONTENT_TYPE, APPLICATION_JSON);
     String serialNumber = getWechatpaySerial(getConfig());
-    httpPost.addHeader("Wechatpay-Serial", serialNumber);
+    httpPost.addHeader(WECHATPAY_SERIAL, serialNumber);
     try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
       //v3已经改为通过状态码判断200 204 成功
       int statusCode = response.getStatusLine().getStatusCode();
@@ -133,6 +134,8 @@ public String postV3(String url, String requestStr) throws WxPayException {
   public String patchV3(String url, String requestStr) throws WxPayException {
     CloseableHttpClient httpClient = this.createApiV3HttpClient();
     HttpPatch httpPatch = new HttpPatch(url);
+    String serialNumber = getWechatpaySerial(getConfig());
+    httpPatch.addHeader(WECHATPAY_SERIAL, serialNumber);
     httpPatch.setEntity(this.createEntry(requestStr));
 
     httpPatch.setConfig(RequestConfig.custom()
@@ -204,6 +207,8 @@ public String postV3WithWechatpaySerial(String url, String requestStr) throws Wx
 
   @Override
   public String postV3(String url, HttpPost httpPost) throws WxPayException {
+    String serialNumber = getWechatpaySerial(getConfig());
+    httpPost.addHeader(WECHATPAY_SERIAL, serialNumber);
     return this.requestV3(url, httpPost);
   }
 
@@ -243,9 +248,14 @@ public String requestV3(String url, HttpRequestBase httpRequest) throws WxPayExc
 
   @Override
   public String getV3(String url) throws WxPayException {
+    if (this.getConfig().isStrictlyNeedWechatPaySerial()) {
+      return getV3WithWechatPaySerial(url);
+    }
     HttpGet httpGet = new HttpGet(url);
     httpGet.addHeader(ACCEPT, APPLICATION_JSON);
     httpGet.addHeader(CONTENT_TYPE, APPLICATION_JSON);
+    String serialNumber = getWechatpaySerial(getConfig());
+    httpGet.addHeader(WECHATPAY_SERIAL, serialNumber);
     return this.requestV3(url, httpGet);
   }
 
@@ -255,7 +265,7 @@ public String getV3WithWechatPaySerial(String url) throws WxPayException {
     httpGet.addHeader(ACCEPT, APPLICATION_JSON);
     httpGet.addHeader(CONTENT_TYPE, APPLICATION_JSON);
     String serialNumber = getWechatpaySerial(getConfig());
-    httpGet.addHeader("Wechatpay-Serial", serialNumber);
+    httpGet.addHeader(WECHATPAY_SERIAL, serialNumber);
     return this.requestV3(url, httpGet);
   }
 
@@ -264,6 +274,8 @@ public InputStream downloadV3(String url) throws WxPayException {
     CloseableHttpClient httpClient = this.createApiV3HttpClient();
     HttpGet httpGet = new WxPayV3DownloadHttpGet(url);
     httpGet.addHeader(ACCEPT, ContentType.WILDCARD.getMimeType());
+    String serialNumber = getWechatpaySerial(getConfig());
+    httpGet.addHeader(WECHATPAY_SERIAL, serialNumber);
     try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
       //v3已经改为通过状态码判断200 204 成功
       int statusCode = response.getStatusLine().getStatusCode();
@@ -295,6 +307,8 @@ public String putV3(String url, String requestStr) throws WxPayException {
     httpPut.setEntity(entity);
     httpPut.addHeader(ACCEPT, APPLICATION_JSON);
     httpPut.addHeader(CONTENT_TYPE, APPLICATION_JSON);
+    String serialNumber = getWechatpaySerial(getConfig());
+    httpPut.addHeader(WECHATPAY_SERIAL, serialNumber);
     return requestV3(url, httpPut);
   }
 
@@ -303,6 +317,8 @@ public String deleteV3(String url) throws WxPayException {
     HttpDelete httpDelete = new HttpDelete(url);
     httpDelete.addHeader(ACCEPT, APPLICATION_JSON);
     httpDelete.addHeader(CONTENT_TYPE, APPLICATION_JSON);
+    String serialNumber = getWechatpaySerial(getConfig());
+    httpDelete.addHeader(WECHATPAY_SERIAL, serialNumber);
     return requestV3(url, httpDelete);
   }