精华内容
下载资源
问答
  • Java微信小程序

    2018-05-23 11:16:10
    微信商城小程序
  • java微信小程序支付

    2018-04-18 17:27:41
    java微信小程序支付java微信小程序支付java微信小程序支付
  • java 微信小程序demo

    2018-03-16 14:45:14
    java 微信小程序demo 为初学者提供参考 java 微信小程序demo 为初学者提供参考
  • 详解java微信小程序开发中加密解密算法一、概述微信推出了小程序,很多公司的客户端应用不仅具有了APP、H5、还接入了小程序开发。但是,小程序中竟然没有提供Java版本的加密数据解密算法。这着实让广大的Java开发...

    详解java微信小程序开发中加密解密算法

    一、概述

    微信推出了小程序,很多公司的客户端应用不仅具有了APP、H5、还接入了小程序开发。但是,小程序中竟然没有提供Java版本的加密数据解密算法。这着实让广大的Java开发人员蛋疼。

    微信小程序提供的加密数据解密算法链接

    我们下载的算法示例如下:

    木有Java!! 木有Java!! 木有Java!!

    那么如何解决这个问题,我们一起来实现Java版本的微信小程序加密数据解密算法。

    二、实现Java版本的微信小程序加密数据解密算法

    1、创建项目

    这里,我们创建一个Maven工程,具体创建步骤略。

    2、配置pom.xml

    我们在pom.xml中加入如下配置。

    org.bouncycastle

    bcprov-jdk16

    1.46

    commons-codec

    commons-codec

    1.4

    net.sf.json-lib

    json-lib

    2.2.3

    jdk15

    3、实现AES类

    package com.chwl.medical.crypto.wx;

    import java.security.AlgorithmParameters;

    import java.security.InvalidAlgorithmParameterException;

    import java.security.InvalidKeyException;

    import java.security.Key;

    import java.security.NoSuchAlgorithmException;

    import java.security.NoSuchProviderException;

    import java.security.Security;

    import javax.crypto.BadPaddingException;

    import javax.crypto.Cipher;

    import javax.crypto.IllegalBlockSizeException;

    import javax.crypto.NoSuchPaddingException;

    import javax.crypto.spec.IvParameterSpec;

    import javax.crypto.spec.SecretKeySpec;

    import org.bouncycastle.jce.provider.BouncyCastleProvider;

    /**

    * AES加密

    * @author liuyazhuang

    *

    */

    public class AES {

    public static boolean initialized = false;

    /**

    * AES解密

    *

    * @param content

    * 密文

    * @return

    * @throws InvalidAlgorithmParameterException

    * @throws NoSuchProviderException

    */

    public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {

    initialize();

    try {

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

    Key sKeySpec = new SecretKeySpec(keyByte, "AES");

    cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化

    byte[] result = cipher.doFinal(content);

    return result;

    } catch (NoSuchAlgorithmException e) {

    e.printStackTrace();

    } catch (NoSuchPaddingException e) {

    e.printStackTrace();

    } catch (InvalidKeyException e) {

    e.printStackTrace();

    } catch (IllegalBlockSizeException e) {

    e.printStackTrace();

    } catch (BadPaddingException e) {

    e.printStackTrace();

    } catch (NoSuchProviderException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    } catch (Exception e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    return null;

    }

    public static void initialize() {

    if (initialized)

    return;

    Security.addProvider(new BouncyCastleProvider());

    initialized = true;

    }

    // 生成iv

    public static AlgorithmParameters generateIV(byte[] iv) throws Exception {

    AlgorithmParameters params = AlgorithmParameters.getInstance("AES");

    params.init(new IvParameterSpec(iv));

    return params;

    }

    }

    4、实现WxPKCS7Encoder类

    package com.chwl.medical.crypto.wx;

    import java.nio.charset.Charset;

    import java.util.Arrays;

    /**

    * 微信小程序加解密

    * @author liuyazhuang

    *

    */

    public class WxPKCS7Encoder {

    private static final Charset CHARSET = Charset.forName("utf-8");

    private static final int BLOCK_SIZE = 32;

    /**

    * 获得对明文进行补位填充的字节.

    *

    * @param count

    * 需要进行填充补位操作的明文字节个数

    * @return 补齐用的字节数组

    */

    public static byte[] encode(int count) {

    // 计算需要填充的位数

    int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);

    if (amountToPad == 0) {

    amountToPad = BLOCK_SIZE;

    }

    // 获得补位所用的字符

    char padChr = chr(amountToPad);

    String tmp = new String();

    for (int index = 0; index < amountToPad; index++) {

    tmp += padChr;

    }

    return tmp.getBytes(CHARSET);

    }

    /**

    * 删除解密后明文的补位字符

    *

    * @param decrypted

    * 解密后的明文

    * @return 删除补位字符后的明文

    */

    public static byte[] decode(byte[] decrypted) {

    int pad = decrypted[decrypted.length - 1];

    if (pad < 1 || pad > 32) {

    pad = 0;

    }

    return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);

    }

    /**

    * 将数字转化成ASCII码对应的字符,用于对明文进行补码

    *

    * @param a

    * 需要转化的数字

    * @return 转化得到的字符

    */

    public static char chr(int a) {

    byte target = (byte) (a & 0xFF);

    return (char) target;

    }

    }

    5、实现WXCore类

    这个类主要是对具体算法的封装,统一对外提供方法。

    package com.chwl.medical.crypto.wx;

    import org.apache.commons.codec.binary.Base64;

    import net.sf.json.JSONObject;

    /**

    * 封装对外访问方法

    * @author liuyazhuang

    *

    */

    public class WXCore {

    private static final String WATERMARK = "watermark";

    private static final String APPID = "appid";

    /**

    * 解密数据

    * @return

    * @throws Exception

    */

    public static String decrypt(String appId, String encryptedData, String sessionKey, String iv){

    String result = "";

    try {

    AES aes = new AES();

    byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));

    if(null != resultByte && resultByte.length > 0){

    result = new String(WxPKCS7Encoder.decode(resultByte));

    JSONObject jsonObject = JSONObject.fromObject(result);

    String decryptAppid = jsonObject.getJSONObject(WATERMARK).getString(APPID);

    if(!appId.equals(decryptAppid)){

    result = "";

    }

    }

    } catch (Exception e) {

    result = "";

    e.printStackTrace();

    }

    return result;

    }

    public static void main(String[] args) throws Exception{

    String appId = "wx4f4bc4dec97d474b";

    String encryptedData = "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew==";

    String sessionKey = "tiihtNczf5v6AKRyjwEUhQ==";

    String iv = "r7BXXKkLb8qrSNn05n0qiA==";

    System.out.println(decrypt(appId, encryptedData, sessionKey, iv));

    }

    }

    三、测试

    1、运行Java版微信小程序加密数据解密算法

    这里我们就直接运行WXcore类的main方法,这里的测试数据都是从Python版微信小程序加密数据解密算法的示例程序中提出来的。我们的运行结果如下:

    代码如下:

    {"openId":"oGZUI0egBJY1zhBYw2KhdUfwVJJE","nickName":"Band","gender":1,"language":"zh_CN","city":"Guangzhou","province":"Guangdong","country":"CN","avatarUrl":"http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0","unionId":"ocMvos6NjeKLIBqg5Mr9QjxrP1FA","watermark":{"timestamp":1477314187,"appid":"wx4f4bc4dec97d474b"}}

    2、运行Python版微信小程序加密数据解密算法

    这里我们在python环境中直接运行微信官方提供的Python版小程序加密数据解密算法,结果如下:

    代码如下:

    {u'province': u'Guangdong', u'openId': u'oGZUI0egBJY1zhBYw2KhdUfwVJJE', u'language': u'zh_CN', u'city': u'Guangzhou', u'gender': 1, u'avatarUrl': u'http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0', u'watermark': {u'timestamp': 1477314187, u'appid': u'wx4f4bc4dec97d474b'}, u'country': u'CN', u'nickName': u'Band', u'unionId': u'ocMvos6NjeKLIBqg5Mr9QjxrP1FA'}

    通过对比以上结果可知,我们自行使用Java实现的Java版微信小程序加密数据解密算法与微信官方提供的Python版小程序加密数据解密算法结果一致。

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持码农之家。

    微信小程序登录状态java后台解密

    一、登录流程图

    二、微信小程序端

    doLogin:function(callback = () =>{}){

    let that = this;

    wx.login({

    success:function(loginRes){

    if(loginRes){

    //获取用户信息

    wx.getUserInfo({

    withCredentials:true,//非必填 默认为true

    success:function(infoRes){

    console.log(infoRes,'>>>');

    //请求服务端的登录接口

    wx.request({

    url: api.loginUrl,

    data:{

    code:loginRes.code,//临时登录凭证

    rawData:infoRes.rawData,//用户非敏感信息

    signature:infoRes.signature,//签名

    encrypteData:infoRes.encryptedData,//用户敏感信息

    iv:infoRes.iv//解密算法的向量

    },

    success:function(res){

    console.log('login success');

    res = res.data;

    if(res.result==0){

    that.globalData.userInfo = res.userInfo;

    wx.setStorageSync('userInfo',JSON.stringify(res.userInfo));

    wx.setStorageSync('loginFlag',res.skey);

    console.log("skey="+res.skey);

    callback();

    }else{

    that.showInfo('res.errmsg');

    }

    },

    fail:function(error){

    //调用服务端登录接口失败

    // that.showInfo('调用接口失败');

    console.log(error);

    }

    });

    }

    });

    }else{

    }

    }

    });

    }

    微信小程序端发起登录请求,携带的参数主要有:

    code:loginRes.code,//临时登录凭证

    rawData:infoRes.rawData,//用户非敏感信息

    signature:infoRes.signature,//签名

    encrypteData:infoRes.encryptedData,//用户敏感信息

    iv:infoRes.iv//解密算法的向量

    需要的数据主要有:

    result、userInfo和skey

    result用来判断是否登录成功,userInfo是用户的一些信息,保存在缓存中,不用每次都从后台获取,skey是用户登录态标识,也放在缓存中,如果skey存在就直接登录,维护用户的登录状态,具有时效性

    三、Java后台

    @ResponseBody

    @RequestMapping("/login")

    public Map doLogin(Model model,

    @RequestParam(value = "code",required = false) String code,

    @RequestParam(value = "rawData",required = false) String rawData,

    @RequestParam(value = "signature",required = false) String signature,

    @RequestParam(value = "encrypteData",required = false) String encrypteData,

    @RequestParam(value = "iv",required = false) String iv){

    log.info( "Start get SessionKey" );

    Map map = new HashMap( );

    System.out.println("用户非敏感信息"+rawData);

    JSONObject rawDataJson = JSON.parseObject( rawData );

    System.out.println("签名"+signature);

    JSONObject SessionKeyOpenId = getSessionKeyOrOpenId( code );

    System.out.println("post请求获取的SessionAndopenId="+SessionKeyOpenId);

    String openid = SessionKeyOpenId.getString("openid" );

    String sessionKey = SessionKeyOpenId.getString( "session_key" );

    System.out.println("openid="+openid+",session_key="+sessionKey);

    User user = userService.findByOpenid( openid );

    //uuid生成唯一key

    String skey = UUID.randomUUID().toString();

    if(user==null){

    //入库

    String nickName = rawDataJson.getString( "nickName" );

    String avatarUrl = rawDataJson.getString( "avatarUrl" );

    String gender = rawDataJson.getString( "gender" );

    String city = rawDataJson.getString( "city" );

    String country = rawDataJson.getString( "country" );

    String province = rawDataJson.getString( "province" );

    user = new User();

    user.setUid( openid );

    user.setCreateTime( new Date( ) );

    user.setSessionkey( sessionKey );

    user.setUbalance( 0 );

    user.setSkey( skey );

    user.setUaddress( country+" "+province+" "+city );

    user.setUavatar( avatarUrl );

    user.setUgender( Integer.parseInt( gender ) );

    user.setUname( nickName );

    user.setUpdateTime( new Date( ) );

    userService.insert( user );

    }else {

    //已存在

    log.info( "用户openid已存在,不需要插入" );

    }

    //根据openid查询skey是否存在

    String skey_redis = (String) redisTemplate.opsForValue().get( openid );

    if(StringUtils.isNotBlank( skey_redis )){

    //存在 删除 skey 重新生成skey 将skey返回

    redisTemplate.delete( skey_redis );

    }

    // 缓存一份新的

    JSONObject sessionObj = new JSONObject( );

    sessionObj.put( "openId",openid );

    sessionObj.put( "sessionKey",sessionKey );

    redisTemplate.opsForValue().set( skey,sessionObj.toJSONString() );

    redisTemplate.opsForValue().set( openid,skey );

    //把新的sessionKey和oppenid返回给小程序

    map.put( "skey",skey );

    map.put( "result","0" );

    JSONObject userInfo = getUserInfo( encrypteData, sessionKey, iv );

    System.out.println("根据解密算法获取的userInfo="+userInfo);

    userInfo.put( "balance",user.getUbalance() );

    map.put( "userInfo",userInfo );

    return map;

    }

    获取openid和sessionKey方法

    public static JSONObject getSessionKeyOrOpenId(String code){

    //微信端登录code

    String wxCode = code;

    String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";

    Map requestUrlParam = new HashMap( );

    requestUrlParam.put( "appid","你的小程序appId" );//小程序appId

    requestUrlParam.put( "secret","你的小程序appSecret" );

    requestUrlParam.put( "js_code",wxCode );//小程序端返回的code

    requestUrlParam.put( "grant_type","authorization_code" );//默认参数

    //发送post请求读取调用微信接口获取openid用户唯一标识

    JSONObject jsonObject = JSON.parseObject( UrlUtil.sendPost( requestUrl,requestUrlParam ));

    return jsonObject;

    }

    解密用户敏感数据获取用户信息

    public static JSONObject getUserInfo(String encryptedData,String sessionKey,String iv){

    // 被加密的数据

    byte[] dataByte = Base64.decode(encryptedData);

    // 加密秘钥

    byte[] keyByte = Base64.decode(sessionKey);

    // 偏移量

    byte[] ivByte = Base64.decode(iv);

    try {

    // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要

    int base = 16;

    if (keyByte.length % base != 0) {

    int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);

    byte[] temp = new byte[groups * base];

    Arrays.fill(temp, (byte) 0);

    System.arraycopy(keyByte, 0, temp, 0, keyByte.length);

    keyByte = temp;

    }

    // 初始化

    Security.addProvider(new BouncyCastleProvider());

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");

    SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");

    AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");

    parameters.init(new IvParameterSpec(ivByte));

    cipher.init( Cipher.DECRYPT_MODE, spec, parameters);// 初始化

    byte[] resultByte = cipher.doFinal(dataByte);

    if (null != resultByte && resultByte.length > 0) {

    String result = new String(resultByte, "UTF-8");

    return JSON.parseObject(result);

    }

    } catch (NoSuchAlgorithmException e) {

    log.error(e.getMessage(), e);

    } catch (NoSuchPaddingException e) {

    log.error(e.getMessage(), e);

    } catch (InvalidParameterSpecException e) {

    log.error(e.getMessage(), e);

    } catch (IllegalBlockSizeException e) {

    log.error(e.getMessage(), e);

    } catch (BadPaddingException e) {

    log.error(e.getMessage(), e);

    } catch (UnsupportedEncodingException e) {

    log.error(e.getMessage(), e);

    } catch (InvalidKeyException e) {

    log.error(e.getMessage(), e);

    } catch (InvalidAlgorithmParameterException e) {

    log.error(e.getMessage(), e);

    } catch (NoSuchProviderException e) {

    log.error(e.getMessage(), e);

    }

    return null;

    }

    四、流程

    1.小程序端发起请求并携带主要参数

    2.java后台接到/login请求后,根据code去调用微信接口获取用户唯一标识openid和sessionKey

    3.根据openid查询mysql数据库,判断该用户是否存在,如果不存在将用户非敏感信息和其他初始化数据存入到数据库中,如果已存在,不操作

    4.根据openid查询redis数据库,判断openid对应的skey是否存在,如果存在则删除原来老的skey以及对应的openid和sessionKey

    5.通过uuid生成唯一的skey,用openid做键,skey做值,存入到redis中

    6.然后把skey做键,openid和sessionKey的json串做值也重新存入到redis中

    7.根据解密算法,参数有encryptedData、sessionKey和iv,获取用户信息userInfo,如果userInfo字段不满足需要,可通过userInfo.put( “balance”,user.getUbalance() );添加所需要的字段和值

    8.将微信小程序需要的数据封装到map中,返回给小程序端

    map.put( "skey",skey );

    map.put( "result","0" );

    map.put( "userInfo",userInfo );

    return map;

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持码农之家。

    以上就是本次给大家分享的关于java的全部知识点内容总结,大家还可以在下方相关文章里找到相关文章进一步学习,感谢大家的阅读和支持。

    展开全文
  • java微信小程序加密数据解密 可以直接使用可以直接使用可以直接使用可以直接使用可以直接使用可以直接使用
  • 微信小程序 开放数据校验与解密Java版 Java微信小程序获取用户信息和手机号码解密Java版 一、依赖pom <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec --> <dependency> ...

    微信小程序 开放数据校验与解密Java版 Java微信小程序获取用户信息和手机号码解密Java版

     

    一、依赖pom

     <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.15</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16 -->
    	<dependency>
    	    <groupId>org.bouncycastle</groupId>
    	    <artifactId>bcprov-jdk16</artifactId>
    	    <version>1.46</version>
    	</dependency>

    二、代码如下

    
    import java.security.AlgorithmParameters;
    import java.security.Key;
    import java.security.Security;
    
    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.apache.commons.codec.binary.Base64;
    
    
    /**
     * description: 微信小程序 --- 获取用户信息解密
     * @version v1.0
     * @author w
     * @date 2020年9月24日下午4:00:15
     * @see 
     **/
    
    public class WechatUtils {
    	
    	public static final String AES = "AES";
    	public static final String AES_CBC_PADDING = "AES/CBC/PKCS7Padding";
    
    	/**
         *开放数据校验与解密 <br/>
         *对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充<br/>
         *对称解密的目标密文:encrypted=Base64_Decode(encryptData)<br/>
         *对称解密秘钥:key = Base64_Decode(session_key),aeskey是16字节<br/>
         *对称解密算法初始向量:iv = Base64_Decode(iv),同样是16字节<br/>
         *@param encrypted 目标密文
         *@param session_key 会话ID
         *@param iv 加密算法的初始向量
         *@see https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html
         */
        public static String wxDecrypt(String encrypted, String session_key, String iv) {
            String result = null;
            byte[] encrypted64 = Base64.decodeBase64(encrypted);
            byte[] key64 = Base64.decodeBase64(session_key);
            byte[] iv64 = Base64.decodeBase64(iv);
            try {
                init();
                result = new String(decrypt(encrypted64, key64, generateIV(iv64)));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    	    
       
    	    
        /**
         * description: 初始化密钥
         * @throws Exception
         * @return void
         * @version v1.0
         * @author w
         * @date 2020年9月9日 下午5:07:04
         */
        public static void init() throws Exception {
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            KeyGenerator.getInstance(AES).init(128);
        }
    
        /**
         * description: 生成iv
         * @param iv
         * @throws Exception
         * @return AlgorithmParameters
         * @version v1.0
         * @author w
         * @date 2020年9月10日 下午3:50:35
         */
        public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
            // iv 为一个 16 字节的数组,这里采用和 iOS 端一样的构造方法,数据全为0
            // Arrays.fill(iv, (byte) 0x00);
            AlgorithmParameters params = AlgorithmParameters.getInstance(AES);
            params.init(new IvParameterSpec(iv));
            return params;
        }
    
        /**
         * description: 执行解密操作
         * @param encryptedData  加密后的字符串
         * @param keyBytes  密钥key
         * @param iv  便宜向量iv
         * @throws Exception
         * @return byte[]
         * @version v1.0
         * @author w
         * @date 2020年9月10日 下午3:51:10
         */
        public static byte[] decrypt(byte[] encryptedData, byte[] keyBytes, AlgorithmParameters iv)throws Exception {
            Key key = new SecretKeySpec(keyBytes, AES);
            Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);
            // 设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, key, iv);
            return cipher.doFinal(encryptedData);
        }
        	  
    }

     

    三、测试

    1、加密数据来源:微信提供的官方解密示例代码中点击下载

     

     

    2、测试代码如下:

    public static void main(String[] args) {
    		String appid = "wx4f4bc4dec97d474b";
    		String sessionKey = "tiihtNczf5v6AKRyjwEUhQ==";
    		String encryptedData = "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZM"+
    							"QmRzooG2xrDcvSnxIMXFufNstNGTyaGS"+
    							"9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+"+
    							"3hVbJSRgv+4lGOETKUQz6OYStslQ142d"+
    							"NCuabNPGBzlooOmB231qMM85d2/fV6Ch"+
    							"evvXvQP8Hkue1poOFtnEtpyxVLW1zAo6"+
    							"/1Xx1COxFvrc2d7UL/lmHInNlxuacJXw"+
    							"u0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn"+
    							"/Hz7saL8xz+W//FRAUid1OksQaQx4CMs"+
    							"8LOddcQhULW4ucetDf96JcR3g0gfRK4P"+
    							"C7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB"+
    							"6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns"+
    							"/8wR2SiRS7MNACwTyrGvt9ts8p12PKFd"+
    							"lqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYV"+
    							"oKlaRv85IfVunYzO0IKXsyl7JCUjCpoG"+
    							"20f0a04COwfneQAGGwd5oa+T8yO5hzuy"+
    							"Db/XcxxmK01EpqOyuxINew==" ;
    						
    		String iv = "r7BXXKkLb8qrSNn05n0qiA==";
    		
    		String wxDecrypt = wxDecrypt(encryptedData, sessionKey, iv);
    		System.out.println(wxDecrypt);
    	}

     

    3、解密结果如下:

     

     

    和官方解密结果一致,解密成功~

     

     

    参考资料:JAVA 微信小程序获取用户信息和手机号码解密

     

     

    展开全文
  • JAVA微信小程序商城源码+完整后台 架构:springmvc+mybatis+spring+maven+mysql 前端h5+css3 后台boostrap-ace技术 功能介绍: 商品发布 物流管理 评价系统 优惠券 运费系统 在线客服 在线支付 在线退款 微信管理等
  • Java微信小程序母婴用品商城 大学生毕业设计教学视频 讲解如何发布小程序商城的后台、如何设置、如何发布小程序和设置小程序、功能演示包含界面和开发讲解;主要讲解移动商城首页、商城分类、商城购物车、产品分类、...
  • java微信小程序长按识别太阳码(偶尔得到的,不是我写的),可以截取长方形头像图片剪切成圆形头像。详情见源码。
  • 主要介绍了Java微信小程序oss图片上传的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 一个关于Java微信小程序支付的demo基础包 SpringBoot,xStream,hutool工具类,lombok,自定义异常模块XStreamhutool 工具类 基础包 SpringBoot,xStream,hutool工具类,lombok,自定义异常模块 XStream <...

    基础包 SpringBoot,xStream,hutool工具类,lombok,自定义异常模块

    XStream

    	<dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.11.1</version>
        </dependency>
    

    hutool 工具类

    	<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.4</version>
        </dependency>
    

    下面我们开始写一个微信小程序支付的demo
    1.新建三个对象用于接收微信返回xml报文的解析内容
    ①.WxPayNotifyReq

     /**
     * 支付结果通知报文
     * @author wuhx  2020-05-14 11:55:56
     */	 
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class WxPayNotifyReq {
        @XStreamAlias("appid")
        private String appId;
        
    	@XStreamAlias("bank_type")
        private String bankType;
    
        @XStreamAlias("cash_fee")
        private float cashFee;
    
        @XStreamAlias("fee_type")
        private String feeType;
    
        @XStreamAlias("is_subscribe")
        private String isSubscribe;
    
        @XStreamAlias("mch_id")
        private String mchId;
    
        @XStreamAlias("nonce_str")
        private String nonceStr;
    
        @XStreamAlias("openid")
        private String openId;
    
        @XStreamAlias("out_trade_no")
        private String outTradeNo;
    
        @XStreamAlias("return_code")
        private String resultCode;
    
        @XStreamAlias("result_code")
        private String returnCode;
    
        @XStreamAlias("sign")
        private String sign;
    
        @XStreamAlias("time_end")
        private String timeEnd;
    
        @XStreamAlias("total_fee")
        private String totalFee;
    
        @XStreamAlias("trade_type")
        private String tradeType;
    
        @XStreamAlias("transaction_id")
        private String transactionId;
    }
    

    ②WxPayNotifyResp

    /**
     * 支付异步通知报文
     * @author wuhx  2020-05-14 13:54:50
     */
    @Data
    public class WxPayNotifyResp {
    
        private String returnCode;
        private String returnMsg;
    
    }
    

    ③WxPayResp

    	/**
    	 * 解析预支付(统一下单接口)
    	 * 具体字段参数见 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1
    	 * XStreamAlias的原因,解析XML的参数只能多不能少
    	 * @author wuhx  2020-05-14 15:46:37
    	 */
    	@Data
    	@NoArgsConstructor
    	@AllArgsConstructor
    	@XStreamAlias("xml")
    	public class WxPayResp {
    
        @XStreamAlias("err_code")
        private String errCode;
    
        @XStreamAlias("err_code_des")
        private String errCodeDes;
    
        @XStreamAlias("code_url")
        private String codeUrl;
    
        @XStreamAlias("device_info")
        private String deviceInfo;
    
        @XStreamAlias("openid")
        private String openId;
    
        @XStreamAlias("result_code")
        private String resultCode;
    
    
        @XStreamAlias("return_code")
        private String returnCode;
    
        @XStreamAlias("return_msg")
        private String returnMsg;
        /**
         * 随机字符串
         */
        @XStreamAlias("nonce_str")
        private String noticeStr;
    
        /**
         * 预支付交易会话标识
         */
        @XStreamAlias("prepay_id")
    	private String prepayId;
    
        @XStreamAlias("sign")
        private String sign;
    
        @XStreamAlias("appid")
        private String appId;
    
        @XStreamAlias("mch_id")
        private String mchId;
    
        /**
         * 交易类型
         */
        @XStreamAlias("trade_type")
        private String tradeType;
    
    }	
    

    2.编写配置文件信息
    用于接收配置文件中的小程序信息在这里插入图片描述
    3.自定义异常模块(用自己的也行,只要能捕抓到异常)
    在这里插入图片描述
    在这里插入图片描述

    /**
     * @author wuhx  2020-05-12 13:48:44
     */
    public class BaseError {
    		
    	public enum ErrorCodeEnum{
    
            SYS_ERROR("10001","系统错误,请重试"),
            UNKNOWN_ERROR("10002","未知异常,请重试"),
            /*用户错误*/
            USER_NOT_LOGGED_IN("20001", "用户未登录,请先登录"),
            USER_LOGIN_ERROR("20002", "账号不存在或密码错误"),
            /*HTTP异常*/
            HTTP_SEND_GET_ERROR("30001","发送GET请求失败"),
            HTTP_SEND_POST_ERROR("30002","发送POST请求失败"),
            /* 权限错误:70001-79999 */
            PERMISSION_UNAUTHENTICATED("70001","此操作需要登陆系统!"),
            PERMISSION_UNAUTHORISE("70002","权限不足,无权操作!"),
            PERMISSION_EXPIRE("70003","登录状态过期!"),
            PERMISSION_TOKEN_EXPIRED("70004", "token已过期"),
            PERMISSION_LIMIT("70005", "访问次数受限制"),
            PERMISSION_TOKEN_INVALID("70006", "无效token"),
            PERMISSION_SIGNATURE_ERROR("70007", "签名失败"),
            PERMISSION_TOKEN_NULL("70008","token为空"),
            ILLEGAL_ARGS("70009","参数异常,请检查参数"),
            /*微信返回的错误 80001-89999*/
            WX_MSG_ERROR("80001","获取微信信息异常"),
            WX_SYS_ERROR("80002","系统繁忙"),
            WX_PAY_SENDXML_ERROR("80003","报文发送失败"),
            WX_PAY_READRESP_ERROR("80004","解析响应内容失败"),
            WX_PAY_ERROR("80005","微信支付请求失败"),
            WX_PAY_SIGN_ERROR("80006","签名失败"),
            /*XML错误 90001-99999*/
            XML_PARSE_ERROR("90001","XML解析错误")
            ;
            private String code;
            private String desc;
    
            public String getCode() {
                return code;
            }
    
            public String getDesc() {
                return desc;
            }
            public void setDesc(String desc) {
                this.desc = desc;
            }
    
            ErrorCodeEnum(String code,String desc){
                this.code = code;
                this.desc = desc;
            }
    
            public static ErrorCodeEnum getEnumByCode(String code){
                for (ErrorCodeEnum result : values()){
                    if (StrUtil.equals(result.getCode(),code)){
                        return result;
                    }
                }
                return null;
            }
        }
    }
    

    最后调用就行了

    import cn.hutool.core.util.RandomUtil;
    import cn.hutool.core.util.StrUtil;
    import cn.hutool.core.util.XmlUtil;
    import cn.hutool.crypto.SecureUtil;
    import cn.hutool.http.HttpUtil;
    import com.thoughtworks.xstream.XStream;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import zhiyan.applets.base.execption.BaseError;
    import zhiyan.applets.base.execption.HttpException;
    import zhiyan.applets.base.execption.WxPayException;
    import zhiyan.applets.base.execption.XmlException;
    import zhiyan.applets.base.utils.LogUtils;
    import zhiyan.applets.entity.HttpResult;
    import zhiyan.applets.tencent.login.model.WxInfo;
    import zhiyan.applets.tencent.pay.model.WxPayResp;
    
    import java.util.*;
    
    /**
     * @author wuhx  2020-05-14 14:01:34
     */
    public class WxPay {
    
        private static final Logger log = LoggerFactory.getLogger(WxPay.class);
        /**
         * 下单地址
         */
        private static final String URL_UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    
        private static final String SUCCESS = "SUCCESS";
        /**
         * 加密方式 默认 md5
         */
        private static final String SIGN_TYPE = "MD5";
    
        private final XStream xStream;
    
        public WxPay(XStream xStream) {
            this.xStream = xStream;
        }
    
    
        /**
         * 下单(预支付)
         * @param orderNumber 订单编号
         * @param payMoney 金额 单位分
         * @param body 描述
         * @param openId 用户openid
         * @param notifyUrl 异步回调地址(配合内网穿透使用)
         * @param ip ip地址
         * @param wxInfo 微信小程序配置信息
         * @return wxPayResp
         */
        public WxPayResp unifiedOrder(String orderNumber, Double payMoney, String body, String openId, String notifyUrl,String ip, WxInfo wxInfo){
            Map<String, String> map = new HashMap<>(11);
            map.put("appid",wxInfo.getAppId());
            map.put("mch_id", wxInfo.getMchId());
            map.put("nonce_str", RandomUtil.randomString(16));
            map.put("body",wxInfo.getPayTitle()+body);
            map.put("out_trade_no", orderNumber);
            map.put("total_fee", StrUtil.toString(payMoney));
            map.put("spbill_create_ip",ip);
            map.put("notify_url",notifyUrl);
            map.put("trade_type","JSAPI");
            map.put("sign",sign(map,wxInfo.getAppKey()));
            try {
                String result = HttpUtil.post(URL_UNIFIED_ORDER, XmlUtil.mapToXmlStr(map));
                return (WxPayResp) xStream.fromXML(result);
            }catch (WxPayException e){
                log.error(LogUtils.text(e));
                throw new WxPayException(BaseError.ErrorCodeEnum.WX_PAY_ERROR);
            }catch (XmlException e){
                log.error(LogUtils.text(e));
                throw new XmlException(BaseError.ErrorCodeEnum.XML_PARSE_ERROR);
            }catch (HttpException e){
                log.error(LogUtils.text(e));
                throw new HttpException(BaseError.ErrorCodeEnum.HTTP_SEND_POST_ERROR);
            }
        }
    
        /**
         * 支付
         * @param wxPayResp
         * @return
         */
        public HttpResult wxPay(WxPayResp wxPayResp){
            Map<String,Object> resMap = new HashMap<>();
            if (StrUtil.equalsIgnoreCase(wxPayResp.getReturnCode(),SUCCESS)){
                //注意 这个I 要大写
                resMap.put("appId",wxPayResp.getAppId());
                resMap.put("nonceStr",wxPayResp.getNoticeStr());
                resMap.put("package","prepay_id="+wxPayResp.getPrepayId());
                resMap.put("signType",SIGN_TYPE);
                resMap.put("timeStamp", System.currentTimeMillis());
                resMap.put("paySign",wxPayResp.getSign());
                return HttpResult.mapSuccess(resMap);
            }
            return HttpResult.error("微信请求支付失败");
        }
    
    
        /**
         * 按照微信规定格式签名
         *
         * @author lingting 2019-08-06 15:23:54
         */
        private static String sign(Map<String, String> map,String appKey) {
            // 对参数的 key 按照指定规则排序
            String[] keys = asciiSort(map.keySet());
            // 按照排序后的key拼接成字符串
            String mapString = join(map, keys,appKey);
            // 获取签名
            String sign = SecureUtil.md5(mapString).toUpperCase();
            if (StrUtil.isNotEmpty(sign)) {
                return sign;
            } else {
                throw new WxPayException(BaseError.ErrorCodeEnum.WX_PAY_SIGN_ERROR);
            }
        }
    
        private static String join(Map<String, String> map, String[] keys,String appKey) {
            StringBuilder str = new StringBuilder();
            for (String key : keys) {
                str.append(key).append("=").append(map.get(key)).append("&");
            }
            // 拼接秘钥
            str.append("key=").append(appKey);
            return str.toString();
        }
    
        /**
         * 按照 首字符 ASCII 码排序
         *
         * @author wuhx 2020-05-14 14:37
         */
        public static String[] asciiSort(Set<String> set) {
            return asciiSort(set.toArray(new String[0]));
        }
    
        public static String[] asciiSort(String[] keys) {
            List<String> list = new ArrayList<>(Arrays.asList(keys));
            Collections.sort(list);
            return list.toArray(new String[0]);
        }
    }
    

    接下来最后一步就是写异步回调地址,如果线上测试的话不需要内网穿透,本地测试的话要有内网穿透。并且这个接口不能有任何的权限(POST),然后根据解析的WxPayNotifyReq 内容,处理你的
    业务逻辑就行了。

    /**
     * 回调处理
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    public WxPayNotifyReq asyNotice(HttpServletRequest request, HttpServletResponse response) throws IOException {
        try (PrintWriter writer = response.getWriter()) {
            String result = parseRequest(request);
            log.info(LogUtils.text("通知报文:" + result));
            //结果返回,微信要求如果成功需要返回return_code "SUCCESS"
            return (WxPayNotifyReq) xStream.fromXML(result);
        } catch (WxPayException e) {
            throw new WxPayException(BaseError.ErrorCodeEnum.WX_MSG_ERROR);
        }
    }
    
    public static String parseRequest(HttpServletRequest request) throws UnsupportedEncodingException {
        request.setCharacterEncoding("utf-8");
        String body = "";
        try {
            ServletInputStream inputStream = request.getInputStream();
            // 设置编码格式“utf-8”否则获取中文为乱码
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            while (true) {
                String info = br.readLine();
                if (info == null) {
                    break;
                }
                if (StrUtil.isNotEmpty(body)) {
                    body = info;
                } else {
                    body += info;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return body;
    }
    

    最后处理完业务逻辑后给微信返回return_code “SUCCESS”

    展开全文
  • Java微信小程序商城

    2018-06-01 16:05:38
    微信小程序商城api接口 platform-common 公共模块 platform-framework 系统WEB合并 platform-gen 代码生成 platform-schedule 定时任务 platform-shiro 登陆权限相关 platform-shop 商城...
  • springboot 写的微信小程序后台上传 包含了文件上传 和下载 由于文件是在整个后台中拿出来的,所以返回参数 可以根据自己需求进行修改。文件主要是在微信小程序 生成录音文件 或选择文件时 调用 wx.upload 方法上传...
  • 牛逼的uniapp+Java微信小程序商城来了 减少重复造轮子,开源微信小程序商城(前后端开源:uniapp+Java),秒杀、优惠券、多商户、直播卖货、分销等功能。快速搭建一个属于自己的微信小程序商城。 码云开源地址: ...

    牛逼的uniapp+Java微信小程序商城来了
    减少重复造轮子,开源微信小程序商城(前后端开源:uniapp+Java),秒杀、优惠券、多商户、直播卖货、分销等功能。快速搭建一个属于自己的微信小程序商城。
    码云开源地址:

    https://gitee.com/fuyang_lipengjun/platform
    

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    注意
    Entity里提示报错不是缺少get、set方法,Eclipse、IDEA请先安装lombok插件

    使用须知
    ✅允许
    个人学习使用

    允许用于学习、毕设等

    允许进行商业使用,请自觉遵守使用协议,如需要商业使用推荐购买商业版(进群联系群主)

    请遵守 Apache License2.0 协议,再次开源请注明出处

    推荐Watch、Star项目,获取项目第一时间更新,同时也是对项目最好的支持

    希望大家多多支持原创作品

    如何交流、反馈、参与贡献?

    官方社区:http://fly2you.cn

    gitee仓库:https://gitee.com/fuyang_lipengjun/platform

    github仓库:https://github.com/lipengjun92/platform-wxshop

    Watch、Star项目,进群联系群主获取《微同开源商城启动部署手册.docx》

    技术讨论、二次开发等咨询、问题和建议,请移步到官方社区,我会在第一时间进行解答和回复!

    微信扫码并关注公众号,获得项目最新动态及更新提醒

    开发计划
    1 使用uniapp重构小程序端所有页面

    2 修复所以已知bug,使用遇到bug请给我们提交issues

    3 后台使用SpringBoot重构

    4 适配H5、IOS、Android端

    5 接入支付宝支付

    6 出配套视频教程

    微同商城商业版

    微信小程序商城(Java版)

    git:https://gitee.com/fuyang_lipengjun/platform

    代码生成工具IDEA插件

    git:https://gitee.com/fuyang_lipengjun/platform-gen

    技术选型
    1 后端使用技术

    1.1 springframework4.3.7.RELEASE

    1.2 mybatis3.1.0、MyBatis-Plus 3.1.0

    1.3 shiro1.3.2

    1.4 servlet3.1.0

    1.5 druid1.0.28

    1.6 slf4j1.7.19

    1.7 fastjson1.2.30

    1.8 poi3.15

    1.9 velocity1.7

    1.10 quartz2.2.3

    1.11 mysql5.1.39

    1.12 swagger2.4

    1.13 j2cache2.3.22-release

    1.14 weixin-java-mp3.2.0

    1.15 MybatisPlus3.1.0

    1.16 lombok

    2 前端使用技术

    2.1 Vue2.5.1

    2.2 iview

    2.3 layer3.0.3

    2.4 jquery2.2.4

    2.5 bootstrap3.3.7

    2.6 jqgrid5.1.1

    2.7 ztree3.5.26

    2.8 froala_editor1.2.2

    项目结构

    platform
    |--platform-admin 后台管理
    |--platform-api 微信小程序商城api接口
    |--platform-common 公共模块
    |--platform-framework 系统WEB合并,请打包发布此项目
    |--platform-gen 代码生成
    |--platform-mp 微信公众号模块
    |--platform-schedule 定时任务
    |--platform-shop 商城后台管理
    |--uni-mall uniapp版商城
    |--wx-mall 微信小程序原生商城
    

    实现功能
    一:会员管理

    a 会员管理

    b 会员等级

    c 收货地址管理

    d 会员优惠劵

    e 会员收藏

    f 会员足迹

    g 搜索历史

    h 购物车

    二:商城配置

    a 区域配置

    b 商品属性种类

    c 品牌制造商

    d 商品规格

    e 订单管理

    f 商品类型

    g 渠道管理

    h 商品问答

    i 反馈

    j 关键词

    三:商品编辑

    a 所有商品

    b 用户评论

    c 产品设置

    d 商品规格

    e 商品回收站

    四:推广管理

    a 广告列表

    b 广告位置

    c 优惠劵管理

    d 专题管理

    e 专题分类

    五:订单管理

    a 所有订单管理

    六:系统管理

    a 管理员列表

    b 角色管理

    c 菜单管理

    d SQL监控

    e 定时任务

    f 参数管理

    g 代码生成器

    h 系统日志

    i 文件上传

    j 通用字典表

    七:短信服务平台

    http://域名:端口/api/sendSms?mobile=13000000000,15209831990&content=发送的短信内容
    安全起见,需配置有效IP地址。platform.properties -> sms.validIp
    

    安装教程
    配置环境(推荐jdk1.8、maven3.3、tomcat8、mysql5.7、redis4.0.1)

    创建数据库

    依次初始化sql脚本

    /_sql/platform.sql

    /_sql/sys_region.sql

    导入项目到IDE中

    导入支付证书至/platform-shop/src/main/resources/cert/目录下(申请商户号、开通微信支付、下载支付证书)

    修改配置文件 /platform-admin/src/main/resources/dev/platform.properties

    jdbc.url

    jdbc.username

    jdbc.password

    wx.appId

    wx.secret

    wx.mchId

    wx.paySignKey

    wx.notifyUrl

    sms.validIp

    mp.appId

    mp.secret

    mp.token

    mp.aesKey

    修改配置文件 /platform-admin/src/main/resources/j2cache.properties

    redis.hosts

    redis.password

    启动redis服务

    启动后台项目(参照开发文档)

    打开微信开发者工具

    导入 /wx-mall填写appId

    修改 /wx-mall/config/api.js里API_BASE_URL的值

    使用eclipse启动项目后默认访问路径

    http://localhost:8080/platform-framework

    使用idea启动项目后默认访问路径

    http://localhost:8080

    页面展示
    登录页面
    在这里插入图片描述
    首页
    在这里插入图片描述
    发送短信

    在这里插入图片描述

    捐赠
    在这里插入图片描述

    小程序首页
    在这里插入图片描述
    专题

    在这里插入图片描述

    分类
    在这里插入图片描述

    购物车
    在这里插入图片描述
    登录授权
    在这里插入图片描述

    优惠券
    在这里插入图片描述

    小程序并联手机
    在这里插入图片描述

    uniapp版本
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    开发文档目录

    展开全文
  • JAVA微信小程序/公众号推送微信官方文档解读模板申请添加消息推送接口消息推送设计 微信官方文档解读 首先说一下小程序:小程序现在都是订阅消息了,小程序模板消息接口已经被废弃。其中订阅消息分为两种。 第一种:...
  • 微信小程序对接微信支付 前些天因为业务需要需要微信小程序对接微信支付,话不多少直接搞起 1首先去微信支付的官方文档阅读官方的api链接:...
  • java微信小程序商城

    2018-09-05 21:26:47
    专门针对微信服务号开发的一套微信商城,微信分销商城,支持商品多规格,支持按地区设置邮费,支持限时打折,订单返现,满减送,满包邮,支持订单打印,订单打印模板自定义,发货单打印,发货单打印模板自定义,支持...
  • java微信小程序开发

    2018-03-22 14:27:11
    java开发小程序源码,有需要的可以下载学习交流。多个案例
  • 登录流程时序登录流程时序 具体的登录说明查看 小程序官方API项目的结构图: springboot项目搭建使用idea作为开发工具,由gradle构建项目,搭建springboot项目,对这块儿不熟悉的可以自行去学习,此处不多赘述。...
  • 讲解如何发布小程序商城的后台、如何设置、如何发布小程序和设置小程序、功能演示 包含界面和开发讲解;...请购买套餐,套餐包含 ...10-微信小程序javaweb商城接口源代码 11-微信小程序商城实战  
  • 带 计算机毕设 JavaWed 网站 App 微信小程序。 springboot
  • 微信小程序授权 获取用户信息里也做了说明 以下代码也已经做了更改 -------------------------------------------------------------------------------------------------- 在实际的小程序开发中,往往需要用户....
  • 讲解如何发布小程序商城的后台、如何设置、如何发布小程序和设置小程序、功能演示 包含界面和开发讲解;... ... 02-Java入门必学:开发环境和工具 intellij idea2020 ... 03-Java基础语法知识... 11-微信小程序商城实战
  • 讲解如何发布小程序商城的后台、如何设置、如何发布小程序和设置小程序、功能演示 包含界面和开发讲解;...请购买套餐,套餐包含 01-JSP运行环境的搭建 02-Java入门必学:开发环境和工具 intellij...11-微信小程序商城实战
  • 针对微信小程序的支付和退款的服务端功能开发,java语言
  • 讲解如何发布小程序商城的后台、如何设置、如何发布小程序和设置小程序、功能演示 包含界面和开发讲解;...  请购买套餐,套餐包含 ...10-微信小程序javaweb商城接口源代码 11-微信小程序商城实战  
  • 讲解如何发布小程序商城的后台、如何设置、如何发布小程序和设置小程序、功能演示 包含界面和开发讲解;...  请购买套餐,套餐包含 ...10-微信小程序javaweb商城接口源代码 11-微信小程序商城实战  
  • java微信小程序参数二维码生成带背景图加字体开发教程

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,771
精华内容 1,908
关键字:

java微信小程序

java 订阅
微信小程序 订阅