2017-11-14 09:11:09 towtotow 阅读数 290
  • 微信开发之三素材管理-微信开发php版

    微信开发之素材管理是子恒老师《微信公众平台开发》视频教程的第三部。详细讲解了用php开发微信,对微信公众平台中的素材管理开发。内容包含微信临时素材,永久素材的上传,删除,获取素材的media_id等等。欢迎反馈,微信/QQ:68183131

    14269 人正在学习 去看看 秦子恒

我们在使用微信公众号时,

会看到公众号底部有三栏菜单,

用户点击菜单后,

可以跳转到网页或者调用其它的功能,

这就是微信菜单的效果。


微信自定义菜单开发案例


微信公众号的菜单,

最多可以有三个一级,

每个一级菜单最多可以有5个二级菜单。


我们后面实现的微信三级分销海报,

就需要用到微信菜单,

在微信开发第5部分,

子恒老师跟你分享微信菜单开发…

微信自定义菜单开发案例视频教程在线观看

http://edu.csdn.net/course/detail/2953/48649

2019-05-08 20:00:54 guobinhui 阅读数 592
  • 微信开发之三素材管理-微信开发php版

    微信开发之素材管理是子恒老师《微信公众平台开发》视频教程的第三部。详细讲解了用php开发微信,对微信公众平台中的素材管理开发。内容包含微信临时素材,永久素材的上传,删除,获取素材的media_id等等。欢迎反馈,微信/QQ:68183131

    14269 人正在学习 去看看 秦子恒

10万+IT人都在关注,史上最全面的微信开发实战教程:包含公众号,小程序,微信支付等开发案例

欢迎关注笔者个人博客:http://blogs.chenyunkeji.com/

首先,直接上图,看效果,如下,有三个根菜单,每个菜单上有不同类型的子菜单,点击子菜单可以实现用户和公众号实时交互

http://blogs.chenyunkeji.com

本案例技术栈:springboot,mysql,logback,mybatis

菜单创建请求接口:https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN

首先是菜单项(按钮)的基类,所有一级菜单、二级菜单都有一个相同的属性,那就是name。菜单项基类的封装代码如下:

public class Button {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

接着是子菜单项的封装。这里对子菜单是这样定义的:底部根菜单的二级菜单。这类子菜单项一定会包含三个属性:type、name和key,封装的代码如下

public class CommandButton extends Button{

    private String type;
    private String key;
    
    public String getType() {
	  return type;
    }
    public void setType(String type) {
	  this.type = type;
    }
    public String getKey() {
	  return key;
    }
    public void setKey(String key) {
	  this.key = key;
    }
}

 接着封装父菜单项。对父菜单项的定义:包含有二级菜单项的一级菜单。这类菜单项包含有二个属性:name和sub_button,而sub_button是一个子菜单项数组。父菜单项的封装代码如下:

public class ComplexButton extends Button{

    private Button[] sub_button;

    public Button[] getSub_button() {
        return sub_button;
    }

    public void setSub_button(Button[] sub_button) {
        this.sub_button = sub_button;
    }
}

最后是整个菜单对象的封装,菜单对象包含多个根菜单项(最多只能有3个),这些菜单项即可以是子菜单项(不含二级菜单的一级菜单),也可以是父菜单项(包含二级菜单的菜单项),如果能明白上面所讲的,再来看封装后的代码就很容易理解了:

public class Menu {
    private Button[] button;
    public Button[] getButton() {
        return button;
    }

    public void setButton(Button[] button) {
        this.button = button;
    }
}

 最后再封装一个链接类型的菜单,根据此处的名字也很好理解,不再赘述

public class ViewButton extends Button{

    private String type;
    private String url;
    
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
}

关于菜单实体类以及菜单对象的封装就介绍完了,下面根据微信接口创建自定义菜单。

一、封装菜单创建工具类

public class WeiXinMenuUtil {

    private static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";        private static Logger log = LoggerFactory.getLogger(WeiXinMenuUtil.class);
    public static int createMenu(Menu menu, String accessToken) {
        int result = 0;
        // 拼接创建菜单的url
        String url = menu_create_url .replace("ACCESS_TOKEN", accessToken);
        // 将菜单对象转换成json字符串
        String jsonMenu = JSON.toJSONString(menu);
        // 调用接口创建菜单
        JSONObject jsonObject = WeiXinUtil.httpPost(url, "POST", jsonMenu);
        if (null != jsonObject) {
            if (0 != (Integer)jsonObject.get("errcode")) {
                result = (Integer)jsonObject.get("errcode");
                log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.get("errcode"), jsonObject.getString("errmsg"));
            }
        }
        return result;
    }
    
    public static Menu initMenu(){
        //1.创建菜单
        Menu menu = new Menu();
        // 主菜单1
        ComplexButton cb1 = new ComplexButton();
        cb1.setName("技术干货");
        
        // 主菜单2
        ComplexButton cb2 = new ComplexButton();
        cb2.setName("交流合作");
        
        // 主菜单3
        ComplexButton cb3 = new ComplexButton();
        cb3.setName("演示功能");
        
        // 主菜单1下面的子菜单1
        ViewButton cb01 = new ViewButton();
        cb01.setName("微服务教程连载");
        cb01.setType("view");
        cb01.setUrl("https://blog.csdn.net/guobinhui/article/category/8739270");
        
        // 主菜单1下面的子菜单2
        ViewButton cb02 = new ViewButton();
        cb02.setName("公众号开发教程");
        cb02.setType("view");
        cb02.setUrl("https://blog.csdn.net/guobinhui/article/category/8534361");
        
        ViewButton cb03 = new ViewButton();
        cb03.setName("小程序开发教程");
        cb03.setType("view");
        cb03.setUrl("https://blog.csdn.net/guobinhui/article/category/7763266");
        
        ViewButton cb04 = new ViewButton();
        cb04.setName("JavaEE基础");
        cb04.setType("view");
        cb04.setUrl("https://blog.csdn.net/guobinhui");
        
        ViewButton cb05 = new ViewButton();
        cb05.setName("笔者博客");
        cb05.setType("view");
        cb05.setUrl("http://blogs.chenyunkeji.com/");
        cb1.setSub_button(new ViewButton[]{cb01,cb02,cb03,cb04,cb05});
        
        // 主菜单2下面的子菜单1
        CommandButton cb11 = new CommandButton();
        cb11.setType("click");
        cb11.setKey("联系我");
        cb11.setName("联系笔者");
        
        CommandButton cb12 = new CommandButton();
        cb12.setName("技术交流");
        cb12.setType("click");
        cb12.setKey("18629374628");
        cb2.setSub_button(new CommandButton[]{cb11,cb12});
        
        CommandButton cb21 = new CommandButton();
        cb21.setType("scancode_waitmsg");
        cb21.setKey("rselfmenu_0_0");
        cb21.setName("扫码带提示");
        
        CommandButton cb22 = new CommandButton();
        cb22.setType("pic_sysphoto");
        cb22.setKey("rselfmenu_1_0");
        cb22.setName("系统拍照发图");
        
        CommandButton cb23 = new CommandButton();
        cb23.setType("pic_photo_or_album");
        cb23.setKey("rselfmenu_1_1");
        cb23.setName("拍照或者相册发图");
        
        CommandButton cb24 = new CommandButton();
        cb24.setType("pic_weixin");
        cb24.setKey("rselfmenu_1_2");
        cb24.setName("微信相册发图");
        
        CommandButton cb25 = new CommandButton();
        cb25.setType("location_select");
        cb25.setKey("rselfmenu_2_0");
        cb25.setName("发送地理位置");
        cb3.setSub_button(new CommandButton[]{cb21, cb22,cb23, cb24,cb25});
        menu.setButton(new Button[] { cb1,cb2, cb3});
        return menu;        
    }
}

二、微信接口凭证access_token的获取以及缓存实现

access_token可以用各种缓存插件或者线程,定时任务,写入数据库等多种方式对access_token进行缓存7200秒,开发者可以依据自己的喜好选择其一,本案例策略采用IO流定时写入文件的方法缓存。首先获取access_token:

public static JSONObject getToken()throws IOException{

 private String GET_ACCESS_TOKEN= "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
 String url = GET_ACCESS_TOKEN.replace("APPID",WeixinConstant.APPID).replace("APPSECRET",WeixinConstant.APPSECRET);
   JSONObject tokenObj = HttpGet(url);
   return tokenObj;
}

接着缓存access_token,也就是每隔7200秒生成一次access_token,生成的缓存7200秒,这样其余用到access_token的从文件中读取的就是最新的,不会过期。

public static  Map <String,Object> cacheToken() throws IOException {
      Gson gson = new Gson();
      Map <String,Object> map = new HashMap <String,Object> ();
      String token = null;
      JSONObject tokenObj = null; //需要获取的access_token对象;
      String filePath = System.getProperty("user.dir")+"/src/main/resources/static/token.txt";
      File file = new File(filePath);//Access_token保存的位置
      if (!file.exists())
        file.createNewFile();
      // 如果文件大小等于0,说明第一次使用,存入Access_token
      if (file.length() == 0) {
        tokenObj = WeiXinUtil.getToken();
        token = (String)tokenObj.get("access_token");
        FileOutputStream fos = new FileOutputStream(filePath, false);// 不允许追加
        tokenObj.put("expires_in",System.currentTimeMillis()/1000+"");
        String json = gson.toJson(tokenObj);
        fos.write(json.getBytes());
        fos.close();
      }else {
        //读取文件内容
        @SuppressWarnings("resource")
        FileInputStream fis = new FileInputStream(file);
        byte[] b = new byte[2048];
        int len = fis.read(b);
        String jsonAccess_token = new String(b, 0, len);// 读取到的文件内容
        JSONObject access_token = gson.fromJson(jsonAccess_token,JSONObject.class);
        if (access_token.get("expires_in") != null) {
          String lastSaveTime = (String)access_token.get("expires_in");
          long nowTime = System.currentTimeMillis()/1000;
          long remianTime = nowTime - Long.valueOf(lastSaveTime);
          if (remianTime < WeixinConstant.EXPIRESIN_TIME) {
              JSONObject access = gson.fromJson(jsonAccess_token,JSONObject.class);
              token = (String)access.get("access_token");
          } else {
              tokenObj = WeiXinUtil.getToken();
              FileOutputStream fos = new FileOutputStream(file, false);// 不允许追加
              tokenObj.put("expires_in",System.currentTimeMillis()/1000+"");
              String json = gson.toJson(tokenObj);
              fos.write((json).getBytes());
              fos.close();
          }
      }
      }
      map.put("access_token",token);
      return map;
    }

最后在项目的启动入口文件的main方法调用菜单创建方法进行初始化,那么项目在启动的时候,公众号的菜单就进行了初始化,用户就能看到公众号的菜单。

@SpringBootApplication
@MapperScan(basePackages = "com.chenyun.cloud.dao")
public class HelloServiceApplication {
    private final static Logger logger= LoggerFactory.getLogger(HelloServiceApplication.class);
    
    public static void main(String[] args) {
         SpringApplication.run(HelloServiceApplication.class, args);
         Map<String, Object> map;
        try {
            map = WeiXinUtil.cacheToken();
             String accessToken = (String)map.get("access_token");
             logger.info("accessToken:"+accessToken);
             Menu menu = WeiXinMenuUtil.initMenu();
             System.out.println(JSON.toJSONString(menu));
             int result  = WeiXinMenuUtil.createMenu(menu,accessToken);
             if (0 == result){
                  logger.info("菜单创建成功!");
              }else{
                  logger.info("菜单创建失败,错误码:" + result);
              }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }    
}

启动项目后,打印的JSON格式的日志打就显示了创建的菜单结构。

下节内容为大家分享公众号菜单栏的各种点击事件开发案例,更多JavaEE资料请关注下面公众号,欢迎广大开发者朋友一起交流。更多微信公众号功能演示请扫码体验,笔者电话(微信):18629374628

2017-05-03 16:59:02 Luze_1226 阅读数 2547
  • 微信开发之三素材管理-微信开发php版

    微信开发之素材管理是子恒老师《微信公众平台开发》视频教程的第三部。详细讲解了用php开发微信,对微信公众平台中的素材管理开发。内容包含微信临时素材,永久素材的上传,删除,获取素材的media_id等等。欢迎反馈,微信/QQ:68183131

    14269 人正在学习 去看看 秦子恒

微信公众后台开发之素材管理

        最近应公司要求,对公司的微信公众号后台走升级,添加部分功能,其中就是需要在后台上传图片,而公众号回根据用户的按钮点击事件返回后台上传的图片。看着就是简单的需求,但是还是要先了解下微信开发文档,在来做开发微信开发文档
       看过文档后发现不是想象中的那么简单,这里涉及到三个系统的交互,一个是用户的收集,一个是自己的后台服务器,一个是微信服务器,做公众号的图片回复的时候,需要将图片上传到微信服务器,获取素材的media_id,然后使用media_id组装成微信规定的XML信息模板,当用户点击按钮的时候,返回给用户上传的图片。
       微信对上传的素材做了区分,分别为:临时素材和永久素材,他们上传的方式也不一样,同时也会有要求。对于永久素材,需要做删除操作。我使用PHP做开发,首先看看上传临时素材,文档给了我们URL和请求的方法。然后做编程。编程先把请求的方法包装下:
protected static function https_request($url, $data = null)
{
 //创建一个新cURL资源
 $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    if (!empty($data)){
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    $output = curl_exec($curl);
    curl_close($curl);
    return $output;
}
上包装了对请求的操作,接下来就是做上传素材了,微信不接受网络素材,只好是自己的本地图片做上传,这里写了一个方法来做上传临时素材:
//获取上传图片的medioId 添加临时素材
public function get_media_id($imgUrl){

     $TOKEN="idtbxhOnI4YZ8gFRHeUEU-MYk4T3XxVndEZKvx2jlx3dGteEWEyG6Twck9MTgsyXRl_MqyBhgYa4w73mjGnvXH17Nguhqs7Z2QCpCu7SvzUYIWjAHALVJ";
      $URL ='http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token='.$TOKEN.'&type=image';



    $filedata = array("media"  => "@".$imgUrl);

   $result =$this->https_request($URL,$filedata);
   echo var_dump($result).'<br>';
   $res = json_decode($result,true);
    return $res;
}
上面的TOKEN是微信自己公众号的accessToken,可以通过文档网页测试来获取做测试,也可以自己写方法获取,这里就不写了,通过给参数$imageUrl就可以获得media_id,在使用media_id就可以在公众号显示了,上传永久素材和上传临时素材是一样的,只是链接不一样:
 //添加永久素材
    public function uploadImg($imgUrl){

        $TOKEN="7ZT1cX_zIh0PFJnINPPaVew5yIDAU9N0umuwt5kmyuMwGVW2LCCTmokixxt99Rix0NixyKiQP-kB-T8KxYNllkRz7pZ7znWfIKOkK8bYUmsCFIgAFAFIL";
        $url = 'https://api.weixin.qq.com/cgi-bin/material/add_material?access_token='.$TOKEN.'&type=image';
//         $URL ='http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token='.$TOKEN.'&type=image';
        $data = array('media'=>'@'.$imgUrl);
        $result = $this->https_request($url,$data);
        $data = @json_decode($result,true);

        return $data['media_id'];

//         return $data;
    }

这是不是很简单,现在看看如何删永久素材,删除素材,首先要获取素材的media_id,在通过media_id来删除素材,这就需要我们自己先保存上传后的素材media_id,方便我们做删除操作。这里直接给出代码:
   public function del_media($media_id){
         $TOKEN="7ZT1cX_zIh0PFJnINPPaVew5yIDAU9N0umuwt5kmyuMwGVW2LCCTmokixxt99Rix0NixyKiQP-kB-T8KxYNllkRz7pZ7znWfIKOkK8bYUmsCFIgAFAFIL";
         $media_id = 'b6geinBHCE6Z3WrilwK0NEeVU4JZDlcdebGYQrYOy-k';
//          $media_id = 'b6geinBHCE6Z3WrilwK0NBO88W4Q5nNrhWQOiUKQouA';
         $url = 'https://api.weixin.qq.com/cgi-bin/material/del_material?access_token='.$TOKEN;
         $data = '{"media_id":"%s"
}';
         $data = sprintf($data,$media_id);
         $result = $this->https_request($url,$data);
         $res = json_decode($result,true);
         return $res;
     }

这里要注意下请求的参数的格式一定要多注意,否则会报错。


2017-11-03 09:40:06 towtotow 阅读数 485
  • 微信开发之三素材管理-微信开发php版

    微信开发之素材管理是子恒老师《微信公众平台开发》视频教程的第三部。详细讲解了用php开发微信,对微信公众平台中的素材管理开发。内容包含微信临时素材,永久素材的上传,删除,获取素材的media_id等等。欢迎反馈,微信/QQ:68183131

    14269 人正在学习 去看看 秦子恒

有了前面微信开发核心基础和微信后台开发的铺垫,

从微信素材开发这个系列教程开始,

我们就可以正式进入项目操作实战。


28sucai_file_huizong.jpg


首先我们把前面两个系列中的文件进行汇总,

由于这个非常重要,

建议你跟着视频操作一遍…

微信公众号开发素材管理,后台文件汇总视频教程在线观看

http://edu.csdn.net/course/detail/2860/48734

2018-11-06 09:38:05 qq_26507967 阅读数 391
  • 微信开发之三素材管理-微信开发php版

    微信开发之素材管理是子恒老师《微信公众平台开发》视频教程的第三部。详细讲解了用php开发微信,对微信公众平台中的素材管理开发。内容包含微信临时素材,永久素材的上传,删除,获取素材的media_id等等。欢迎反馈,微信/QQ:68183131

    14269 人正在学习 去看看 秦子恒
微信上传图片到本地服务器的流程
1.前端通过微信jssdk里面的图片上传功能,找到本地图片生成localid
2.将图片上传到微信临时素材中,是有有效期的生成serviceid
3.前端将serviceid传给后台,后台通过serviceid去微信下载临时素材保存到服务器
4.保存成功告诉前台保存成功


此处展示后台通过前台给的serviceid下载临时素材
/**
     * 微信下载临时素材  serviceid 为微信服务器上存放临时素材的标识
     */
    public function DownImage($serviceid){
        //获取临时素材
        $imageAll = $this->test($serviceid);
        $savename = md5(microtime(true));
        $savename = $savename.mt_rand(1,9999).".jpg";
        //图片保存到服务器
        $imgurl = $this->saveWeixinFile($savename,$imageAll['body']);
        return $imgurl;
    }
    /**
     * 从微信下载图片
     */
    public function test($serviceid){
        $wx = $this->getCacheToken();
        $url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=".$wx['value']."&media_id=".$serviceid;
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_HEADER, 0);    
        curl_setopt($ch, CURLOPT_NOBODY, 0);    //只取body头
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $package = curl_exec($ch);
        $httpinfo = curl_getinfo($ch);
        curl_close($ch);
        $imageAll = array_merge(array('header' => $httpinfo), array('body' => $package)); 
        return $imageAll;
    }

    //获取access_token   我的access_token存在了数据库里面,具体方法在文章jssdk里面
    private function getCacheToken()
    {
        $time = time();
        $where['name'] = ['=','access_token'];
        $where['expire_time'] = ['>',$time];
        $result = model('wx')->WxFind($where);
        return $result;
    }

    /**
     * 保存图片
     * @param  [type] $filename    [description]
     * @param  [type] $filecontent [description]
     * @return [type]              [description]
     */
    private function saveWeixinFile($filename,$filecontent)
    { 
        $path = "uploads/".date('Ymd');//路径
        $a = is_dir($path);
        if (!$a) {
            mkdir($path,0777,true);
        }
        $imageSrc = $path."/".$filename; //图片名字
        $imgpath = ROOT_PATH."public/".$imageSrc;
        $imgpath = str_replace("\\","/",$imgpath);
        $local_file = fopen($imgpath, 'w');
        if (false !== $local_file){
            if (false !== fwrite($local_file, $filecontent)) {
                $imageSrc = config('http_url')."/".$path."/".$filename;
                fclose($local_file);
                return $imageSrc;
            }
        }

    }

 

C#微信群发素材

博文 来自: u010773333

微信开发

阅读数 913

没有更多推荐了,返回首页