精华内容
参与话题
问答
  • 先创建几个实体类: public class Image { private String MediaId;//素材id public String getMediaId() { return MediaId; ... public void setMediaId(String mediaId) { MediaId = media...

    先创建几个实体类:

    public class Image {
        private String MediaId;//素材id
    
        public String getMediaId() {
            return MediaId;
        }
    
        public void setMediaId(String mediaId) {
            MediaId = mediaId;
        }
    }
    
    
    public class ImageMessage extends BaseMessage{
    
        private Image Image;//Image节点
    
        public com.naruto.huo.model.Image getImage() {
            return Image;
        }
    
        public void setImage(com.naruto.huo.model.Image image) {
            Image = image;
        }
    }
    
    
    
    
    public class BaseMessage {
        private String ToUserName;
        private String FromUserName;
        private long CreateTime;
        private String MsgType;
        private long MsgId;
    
        public String getToUserName() {
            return ToUserName;
        }
    
        public void setToUserName(String toUserName) {
            ToUserName = toUserName;
        }
    
        public String getFromUserName() {
            return FromUserName;
        }
    
        public void setFromUserName(String fromUserName) {
            FromUserName = fromUserName;
        }
    
        public long getCreateTime() {
            return CreateTime;
        }
    
        public void setCreateTime(long createTime) {
            CreateTime = createTime;
        }
    
        public String getMsgType() {
            return MsgType;
        }
    
        public void setMsgType(String msgType) {
            MsgType = msgType;
        }
    
        public long getMsgId() {
            return MsgId;
        }
    
        public void setMsgId(long msgId) {
            MsgId = msgId;
        }
    }

    1.创建common文件夹,里面放WeixinUtil:

    
    public class WeixinUtil {
        private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);
    
    
        /**
         * 开发者id
         */
        private static final String APPID = "****";
        /**
         * 开发者秘钥
         */
        private static final String APPSECRET="****";
    
        // 获取access_token的接口地址(GET) 限200(次/天)
        //        https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
        public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?"
                + "grant_type=client_credential&appid=APPID&secret=APPSECRET";
    
      //  public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APPSECRET&code=CODE&grant_type=authorization_code";
    
        /**
         * 发起https请求并获取结果
         *
         * @param requestUrl 请求地址
         * @param requestMethod 请求方式(GET、POST)
         * @param outputStr 提交的数据
         * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
         */
        public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
            JSONObject jsonObject = null;
            StringBuffer buffer = new StringBuffer();
            try {
                // 创建SSLContext对象,并使用我们指定的信任管理器初始化
                TrustManager[] tm = { new MyX509TrustManager() };
                SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
                sslContext.init(null, tm, new java.security.SecureRandom());
                // 从上述SSLContext对象中得到SSLSocketFactory对象
                SSLSocketFactory ssf = sslContext.getSocketFactory();
    
                URL url = new URL(requestUrl);
                HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
                httpUrlConn.setSSLSocketFactory(ssf);
    
                httpUrlConn.setDoOutput(true);
                httpUrlConn.setDoInput(true);
                httpUrlConn.setUseCaches(false);
                // 设置请求方式(GET/POST)
                httpUrlConn.setRequestMethod(requestMethod);
    
                if ("GET".equalsIgnoreCase(requestMethod))
                    httpUrlConn.connect();
    
                // 当有数据需要提交时
                if (null != outputStr) {
                    OutputStream outputStream = httpUrlConn.getOutputStream();
                    // 注意编码格式,防止中文乱码
                    outputStream.write(outputStr.getBytes("UTF-8"));
                    outputStream.close();
                }
    
                // 将返回的输入流转换成字符串
                InputStream inputStream = httpUrlConn.getInputStream();
                InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
    
                String str = null;
                while ((str = bufferedReader.readLine()) != null) {
                    buffer.append(str);
                }
                bufferedReader.close();
                inputStreamReader.close();
                // 释放资源
                inputStream.close();
                inputStream = null;
                httpUrlConn.disconnect();
                jsonObject = JSONObject.fromObject(buffer.toString());
            } catch (ConnectException ce) {
                log.error("Weixin server connection timed out.");
            } catch (Exception e) {
                log.error("https request error:{}", e);
            }
            return jsonObject;
        }
    
    
    
        /**
         * 获取access_token
         *
         * @param appid 凭证
         * @param appsecret 密钥
         * @return
         */
        public static AccessToken getAccessToken(String appid, String appsecret) {
            AccessToken accessToken = null;
    
            String requestUrl = ACCESS_TOKEN_URL.replace("APPID", appid).replace("APPSECRET", appsecret);
            JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
            // 如果请求成功
            if (null != jsonObject) {
                accessToken = new AccessToken();
                accessToken.setToken(jsonObject.getString("access_token"));
                accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
            }
            return accessToken;
        }
    
        /**
         * 处理doget请求
         * @param url
         * @return
         */
        public static JSONObject doGetstr(String url){
            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(url);
            JSONObject jsonObject = null;
            try {
                CloseableHttpResponse response = httpclient.execute(httpGet);
                HttpEntity entity = response.getEntity();
                if(entity!=null){
                    String result = EntityUtils.toString(entity);
                    jsonObject = JSONObject.fromObject(result);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return jsonObject;
    
        }
        /**
         * 处理post请求
         * @param url
         * @return
         */
        public static JSONObject doPoststr(String url,String outStr){
            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);
            JSONObject jsonObject = null;
            try {
                httpPost.setEntity(new StringEntity(outStr, "utf-8"));
                CloseableHttpResponse response = httpclient.execute(httpPost);
                String result = EntityUtils.toString(response.getEntity(),"utf-8");
                jsonObject =JSONObject.fromObject(result);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return jsonObject;
        }
    
        public static AccessToken getAccessToken(HttpSession session){
            System.out.println("从接口中获取");
    //        Jedis jedis  = RedisUtil.getJedis();
            AccessToken token = new AccessToken();
            String url = ACCESS_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET);
            JSONObject json = doGetstr(url);
            System.out.println("存储的json:"+json.toString());
            if(json!=null){
                token.setToken(json.getString("access_token"));
                token.setExpiresIn(json.getInt("expires_in"));
              /*  jedis.set("access_token", json.getString("access_token"));
                jedis.expire("access_token", 60*60*2);*/
                session.setAttribute("access_token",json.getString("access_token"));
                System.out.println("存储的access_token:"+json.getString("access_token"));
            }
    //        RedisUtil.returnResource(jedis);
            return token;
        }
    
        public static String  getAccess_Token(HttpSession session,HttpServletRequest request){
            System.out.println("从缓存中读取");
    //        Jedis jedis  = RedisUtil.getJedis();
    //        String access_token = jedis.get("access_token");
            Object access_token = request.getSession().getAttribute("access_token");
            System.out.println("SESSION里的access_token是否获取到:"+access_token);
            if(access_token==null){
                AccessToken token = getAccessToken(session);
                access_token = token.getToken();
            }
    //        RedisUtil.returnResource(jedis);
            return access_token.toString();
        }
    
    }
    

    2.创建一个uploadUtil:

    package com.naruto.huo.common;
    
    import net.sf.json.JSONObject;
    
    import java.io.*;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.security.KeyManagementException;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    
    public class UploadUtil {
        private static final String UPLOAD_URL ="https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
        /**
         * 文件上传
         * @param filePath
         * @param accessToken
         * @param type
         * @return
         * @throws IOException
         * @throws NoSuchAlgorithmException
         * @throws NoSuchProviderException
         * @throws KeyManagementException
         */
        public static String upload(String filePath, String accessToken,String type) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {
            File file = new File(filePath);
            if (!file.exists() || !file.isFile()) {
                throw new IOException("文件不存在");
            }
    
            String url = UPLOAD_URL.replace("ACCESS_TOKEN", accessToken).replace("TYPE",type);
    
            URL urlObj = new URL(url);
            //连接
            HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
    
            con.setRequestMethod("POST");
            con.setDoInput(true);
            con.setDoOutput(true);
            con.setUseCaches(false);
    
            //设置请求头信息
            con.setRequestProperty("Connection", "Keep-Alive");
            con.setRequestProperty("Charset", "UTF-8");
    
            //设置边界
            String BOUNDARY = "----------" + System.currentTimeMillis();
            con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
    
            StringBuilder sb = new StringBuilder();
            sb.append("--");
            sb.append(BOUNDARY);
            sb.append("\r\n");
            sb.append("Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n");
            sb.append("Content-Type:application/octet-stream\r\n\r\n");
    
            byte[] head = sb.toString().getBytes("utf-8");
    
            //获得输出流
            OutputStream out = new DataOutputStream(con.getOutputStream());
            //输出表头
            out.write(head);
    
            //文件正文部分
            //把文件已流文件的方式 推入到url中
            DataInputStream in = new DataInputStream(new FileInputStream(file));
            int bytes = 0;
            byte[] bufferOut = new byte[1024];
            while ((bytes = in.read(bufferOut)) != -1) {
                out.write(bufferOut, 0, bytes);
            }
            in.close();
    
            //结尾部分
            byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");//定义最后数据分隔线
    
            out.write(foot);
    
            out.flush();
            out.close();
    
            StringBuffer buffer = new StringBuffer();
            BufferedReader reader = null;
            String result = null;
            try {
                //定义BufferedReader输入流来读取URL的响应
                reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
                String line = null;
                while ((line = reader.readLine()) != null) {
                    buffer.append(line);
                }
                if (result == null) {
                    result = buffer.toString();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (reader != null) {
                    reader.close();
                }
            }
    
            JSONObject jsonObj = JSONObject.fromObject(result);
            String typeName = "media_id";
            if("thumb".equals(type)){
                typeName = type + "_media_id";
            }
            String mediaId = jsonObj.getString(typeName);
            return mediaId;
        }
    }
    

    3.在之前(一)的controller加一个图片判断:

    @Component
    public class MessageDispatcher {
        public static String processMessage(Map<String, String> map, HttpSession session, HttpServletRequest request) throws FileNotFoundException {
            String openid = map.get("FromUserName"); //用户 openid
            String mpid = map.get("ToUserName");   //公众号原始 ID
            String content = map.get("Content");
            if (map.get("MsgType").equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
                //普通文本消息
                TextMessage txtmsg = new TextMessage();
                txtmsg.setToUserName(openid);
                txtmsg.setFromUserName(mpid);
                txtmsg.setCreateTime(new Date().getTime());
                txtmsg.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
                if("接收".equals(content)){
                    txtmsg.setContent("接收到了!没错~");
                }else if("图片".equals(content)){
                    MessageUtil util = new MessageUtil();
                    return util.initMessage(openid, mpid,session,request);
                }else{
                    txtmsg.setContent("您输入的是:"+content);
                }
                return MessageUtil.textMessageToXml(txtmsg);
            }
        /*    else if (map.get("MsgType").equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
                // 图片消息
                respContent = "您发送的是图片消息!";
                respXml = WeChatUtil.sendTextMsg(requestMap, respContent);
            }*/
            return null;
        }
        public String processEvent(Map<String, String> map) {
            //在这里处理事件
            return "123";
        }
    }

    4.在(一)的messageUtil里面加代码:

    
        /*处理图片*/
        /**
         * 将信息转为xml格式
         */
        public String messageToxml(ImageMessage imageMessage) {
            XStream xtream = new XStream();
            xtream.alias("xml", imageMessage.getClass());
            xtream.alias("Image", new Image().getClass());
            System.out.println("xtream.toString():"+xtream.toString());
            return xtream.toXML(imageMessage);
        }
        /**
         * 封装信息
         */
        public String initMessage(String FromUserName, String ToUserName,HttpSession session, HttpServletRequest request) throws FileNotFoundException {
            Image image = new Image();
            image.setMediaId(getmediaId(session,request));
            log.info("MediaId:"+image.getMediaId());
            ImageMessage message = new ImageMessage();
            message.setFromUserName(ToUserName);
            message.setToUserName(FromUserName);
            message.setCreateTime(new Date().getTime());
            message.setImage(image);
            log.info("ToUserName:"+ToUserName);
            log.info("FromUserName:"+FromUserName);
            message.setMsgType("image");
            log.info("message:"+message.toString());
            return messageToxml(message);
        }
    
        @Value("${config.extPath}")
        private String extPath;
    
        /**
         * 获取Media
         * @return
         */
        public String getmediaId(HttpSession session, HttpServletRequest request) throws FileNotFoundException {
            //获取classes目录绝对路径
            //ResourceUtils.getURL("classpath:").getPath();
            //String path = request.getSession().getServletContext().getRealPath("/static/pic/feng.png");
    
            //String path = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/images/feng.png";
            String path = request.getServletContext().getRealPath("/")  + "WEB-INF/classes/static/images/feng.png";
            log.info("path:"+path);
            String accessToken = WeixinUtil.getAccess_Token(session,request);
            String mediaId = null;
            try {
                mediaId = UploadUtil.upload(path, accessToken.toString(), "image");
    
            } catch (KeyManagementException | NoSuchAlgorithmException
                    | NoSuchProviderException | IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            return mediaId;
        }
    
    /*处理结束*/

    5.最后成功之后则为

    展开全文
  • 主要为大家详细介绍了php微信公众号开发图片回复,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • java微信公众号自动回复文字加图片

    千次阅读 2019-06-29 20:23:39
    java微信公众号自动回复文字加图片开发流程详细流程,附上代码:第一步服务器(url)接口配置服务器(url)接口配置,此步骤就是微信授权接口的过程,如果域名都不改变,微信只会校验一次。此请求微信文档中说明了是...

    前提:第一次发布文章,如有写的不好的地方请指正或代码上可以优化的地方也请各路大神多多指教。顺带想吐槽下微信开发文档真的太恶心了,第一次接触下来让人头晕眼花,通过查阅各种资料后理清了思路,在此写上总结。

    开发流程

    1. 服务器(url)接口配置
    2. 发送文字(根据微信公众号文档“接收事件推送”事件接口编写代码)
    3. 生成二维码(账号管理下的“生成带参数的二维码”事件接口编写代码)
    4. 根据UI的图组合微信头像、微信名字、公众号二维码并调用素材管理下的“新增临时素材”接口上传图片
    5. 发送图片(调用消息管理下的客服消息下的客服接口-发消息(图片)接口)
    6. 进行裂变(调用“扫描带参数二维码事件”)(此步骤还未开发完,需根据业务需求变动)

    详细流程,附上代码:

    第一步服务器(url)接口配置

    服务器(url)接口配置,此步骤就是微信授权接口的过程,如果域名都不改变,微信只会校验一次。此请求微信文档中说明了是get请求。
    /**
         * 微信消息接收和token验证
         * @param request
         * @param response
         */
        @RequestMapping(value = "/weChatToken", method = RequestMethod.GET)
        public void weChatToken(HttpServletRequest request, HttpServletResponse response){
            boolean isGet = request.getMethod().toLowerCase().equals("get");
            if (isGet) {
                // 微信加密签名
                String signature = request.getParameter("signature");
                // 时间戳
                String timestamp = request.getParameter("timestamp");
                // 随机数
                String nonce = request.getParameter("nonce");
                // 随机字符串
                String echostr = request.getParameter("echostr");
    
                // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
                if (signature != null && WeChatUtil.checkSignature(signature, timestamp, nonce)) {
                    try {
                        PrintWriter print = response.getWriter();
                        print.write(echostr);
                        print.flush();
                    } catch (IOException e) {
                        log.error("微信消息接收和token验证异常",e);
                    }
                }
            }
        }
    

    第二步发送文字

    我这边的需求是发送的文字中要带上微信名称,所以还需要调用微信的获取accessToken接口跟获取用户信息接口。获取用户信息接口中需要openId,在用户点击关注微信公众号时,微信会自动发送过来。微信为什么会知道咱们的接口呢,因为咱们已经在第一步授权了接口,微信会以默认post请求的方式调用相同的路由,所以我们还得写一个post请求的接口。注:finally中是发送图片的动作。调用事件中运用了抽象工厂的设计模式,此处还有待优化。

    2.1 接口详解

    /**
         * 微信公众号 -->
         *   消息管理 -->
         *     接收普通消息、接收事件推送、被动回复用户消息
         *
         * @param request
         * @return
         */
        @ResponseBody
        @RequestMapping(value = "/weChatToken", method = RequestMethod.POST)
        public String responseEvent(HttpServletRequest request){
            WeChatMsgService weChatMsgService = null;
            Map<String, String> requestMessageMap = null;
            try {
                // 获取到请求参数
                requestMessageMap = XMLUtil.xmlToMap(request);
                log.info("获取到参数为:{}",requestMessageMap);
    
                // 判断请求参数中 MsgType的值或判断Event值
                String returnMessage = "";
                if (WeChatUtil.REQ_MESSAGE_TYPE_EVENT.equals(requestMessageMap.get("MsgType"))) {
                    // 如果后期有取消订阅事件,此处方法可以去除if
                    if (WeChatUtil.EVENT_TYPE_SUBSCRIBE.equals(requestMessageMap.get("Event"))) {
                        weChatMsgService = getType(requestMessageMap.get("Event"));
                        returnMessage = weChatMsgService.getReturnMessage(requestMessageMap);
                    }
                }
    
                return returnMessage;
            } catch (Exception e) {
                log.error("微信公众号自动回复异常",e);
            }finally {
                if (WeChatUtil.EVENT_TYPE_SUBSCRIBE.equals(requestMessageMap.get("Event"))) {
                    weChatMsgService = weChatCustomerServiceImgMessageServiceImpl;
                    weChatMsgService.getReturnMessage(requestMessageMap);
                }
    
            }
    
            return "";
        }
    

    2.1.2 使用设计模式调用不同的业务逻辑(default有待修改)
    此处注入了业务层
    @Autowired
    private WeChatMsgService weChatTextMessageServiceImpl;

    /**
         *  根据类型选择所需的业务处理逻辑
         * @param type
         */
        private WeChatMsgService getType(String type){
            switch (type) {
                case WeChatUtil.EVENT_TYPE_SUBSCRIBE:
                    return weChatTextMessageServiceImpl;
                default:
                    return null;
            }
        }
    

    2.1.3 调用业务层组合返回的信息(微信文档要求返回的信息为xml的形式)

    @Service
    @Slf4j
    public class WeChatTextMessageServiceImpl implements WeChatMsgService {
    
        @Autowired
        private WeiXinService weiXinService;
    
        @Override
        public String getReturnMessage(Map<String,String> requestMessageMap) {
    
            // 获取access_token
            WeiXinAccessTokenDto accessToken = weiXinService.getAccessToken();
            //获取用户信息
            WeiXinUserInfoDto userInfo = null;
            if (accessToken.getAccess_token() != null) {
                userInfo = weiXinService.getUnionID(accessToken.getAccess_token(), requestMessageMap.get("FromUserName"));
            }
    
            TextMessageResponseVo textMessageResponseVo = new TextMessageResponseVo();
            textMessageResponseVo.setFromUserName(requestMessageMap.get("ToUserName"));
            textMessageResponseVo.setToUserName(requestMessageMap.get("FromUserName"));
            textMessageResponseVo.setMsgType("text");
            textMessageResponseVo.setCreateTime(System.currentTimeMillis());
            textMessageResponseVo.setContent("欢迎" + userInfo.getNickname() + "11111");
    
            String result = WeChatUtil.messageToXml(textMessageResponseVo);
            return result;
        }
    
    }
    

    2.2 调用微信获取accessToken 的接口(业务层涉及到其他逻辑,所以就不全部粘出来了)

    @Override
        public WeiXinAccessTokenDto getAccessToken() {
            Map<String,String> reqParams = new HashMap<>();
            reqParams.put("appid","appid");
            reqParams.put("secret","secret");
            reqParams.put("grant_type","client_credential");
    
            String result = HttpUtil.sendGetJoint(accessTokenUrl, reqParams);
            // 将返回的字符串转为对象
            WeiXinAccessTokenDto weiXinAccessTokenDto = JSON.parseObject(result, WeiXinAccessTokenDto.class);
            return weiXinAccessTokenDto;
        }
    

    2.3 通过微信接口获取用户信息(微信获取用户信息的接口有三种,此处只举例一种)

    @Override
        public WeiXinUserInfoDto getUnionID(String accessToken, String openId) {
            Map<String,String> reqParams = new HashMap<>();
            reqParams.put("lang","zh_CN");
            reqParams.put("access_token",accessToken);
            reqParams.put("openid",openId);
    
            String result = HttpUtil.sendGetJoint(unionIDUrl, reqParams);
            log.info("获取微信用户信息为:{}",result);
            // 将返回的字符串转为对象
            WeiXinUserInfoDto weiXinUserInfoDto = JSON.parseObject(result, WeiXinUserInfoDto.class);
            return weiXinUserInfoDto;
        }
    

    2.4 返回信息实体类(此处用了Swagger,不用的童鞋可以删除注解。还要引入lombok)

    /**
     * @author: hugh_lin
     * @date: 2019/06/26 18:53
     * @Description: 微信公众号返回消息公共实体类
     * @Modifed:
     **/
    @Getter
    @Setter
    public class BaseWeChatResponseVo {
    
        @ApiModelProperty("开发者微信号")
        private String ToUserName;
    
        @ApiModelProperty("发送方帐号(一个OpenID)")
        private String FromUserName;
    
        @ApiModelProperty("消息创建时间 (整型)")
        private Long CreateTime;
    
        @ApiModelProperty("消息类型,event或text、image、voice、video、music、news")
        private String MsgType;
    
    }
    
    /**
     * @author: hugh_lin
     * @date: 2019/06/26 18:58
     * @Description: 微信公众号返回消息实体
     * @Modifed:
     **/
    @Getter
    @Setter
    public class TextMessageResponseVo extends BaseWeChatResponseVo{
    
        @ApiModelProperty("文本消息内容")
        private String Content;
    
    }
    

    2.5 微信工具类

    import com.thoughtworks.xstream.XStream;
    import com.thoughtworks.xstream.core.util.QuickWriter;
    import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
    import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
    import com.thoughtworks.xstream.io.xml.XppDriver;
    import com.youchengjvhe.weishangketang.model.vo.wechat.TextMessageResponseVo;
    import lombok.extern.slf4j.Slf4j;
    
    import java.io.*;
    import java.net.URL;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Arrays;
    import java.util.Formatter;
    
    /**
     * @author: hugh_lin
     * @date: 2019/06/26 15:45
     * @Description: 微信消息处理工具类
     * @Modifed:
     **/
    @Slf4j
    public class WeChatUtil {
    
        //请求消息的类型------------------------------------------
        /**
         *  文本
         */
        public static final String REQ_MESSAGE_TYPE_TEXT = "text";
    
        /**
         *  图片
         */
        public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
    
        /**
         *  语音
         */
        public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
    
        /**
         *  视频
         */
        public static final String REQ_MESSAGE_TYPE_VIDEO = "video";
    
        /**
         *  小视频
         */
        public static final String REQ_MESSAGE_TYPE_SHORTVIDEO = "shortvideo";
    
        /**
         *  地理位置
         */
        public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
    
        /**
         *  链接
         */
        public static final String REQ_MESSAGE_TYPE_LINK = "link";
    
        /**
         *  事件推送
         */
        public static final String REQ_MESSAGE_TYPE_EVENT = "event";
    
        /**
         *  事件类型--订阅
         */
        public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
    
        /**
         *  取消订阅
         */
        public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
    
        /**
         *  已关注用户扫描带参数二维码
         */
        public static final String EVENT_TYPE_SCAN = "SCAN";
    
        /**
         *  上报地理位置
         */
        public  static final String EVENT_TYPE_LOCATION = "LOCATION";
    
        /**
         *  自定义菜单事件
         */
        public static final String EVENT_TYPE_CLICK = "CLICK";
    
        //响应消息类型
        /**
         *  文本
         */
        public static final String RESP_MESSAGE_TYPE_TEXT = "text";
    
        /**
         *  图片
         */
        public static final String RESP_MESSAGE_TYPE_IMAGE = "image";
    
        /**
         *  语音
         */
        public static final String RESP_MESSAGE_TYPE_VOICE = "voice";
    
        /**
         *  视频
         */
        public static final String RESP_MESSAGE_TYPE_VIDEO = "video";
    
        /**
         *  音乐
         */
        public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
    
        /**
         *  图文
         */
        public static final String RESP_MESSAGE_TYPE_ARTICLE = "news";
    
        //---------------------------------------------------------------------
    
        /**
         *  与测试账号接口配置信息中的Token要一致
         *  测试token,微信公众号内可自行配置
         */
        private static String token = "******";
    
        /**
         * 验证签名
         * @param signature
         * @param timestamp
         * @param nonce
         * @return
         */
        public static boolean checkSignature(String signature, String timestamp, String nonce) {
            String[] arr = new String[] { token, timestamp, nonce };
            // 将token、timestamp、nonce三个参数进行字典序排序
            Arrays.sort(arr);
            StringBuilder content = new StringBuilder();
            for (int i = 0; i < arr.length; i++) {
                content.append(arr[i]);
            }
            MessageDigest md = null;
            String tmpStr = null;
    
            try {
                md = MessageDigest.getInstance("SHA-1");
                // 将三个参数字符串拼接成一个字符串进行sha1加密
                byte[] digest = md.digest(content.toString().getBytes());
                tmpStr = byteToHex(digest );
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
            return tmpStr != null ? tmpStr.equals(signature) : false;
        }
    
        /**
         * 十六进制字节数组转为字符串
         * @param hash
         * @return
         */
        private static String byteToHex(final byte[] hash) {
            Formatter formatter = new Formatter();
            for (byte b : hash) {
                formatter.format("%02x", b);
            }
            String result = formatter.toString();
            formatter.close();
            return result;
        }
    
        /**
         * 扩展xstream使其支持CDATA
         */
        private static XStream xstream = new XStream(new XppDriver() {
            @Override
            public HierarchicalStreamWriter createWriter(Writer out) {
                return new PrettyPrintWriter(out) {
                    // 对所有xml节点的转换都增加CDATA标记
                    boolean cdata = true;
    
                    @Override
                    @SuppressWarnings("unchecked")
                    public void startNode(String name, Class clazz) {
                        super.startNode(name, clazz);
                    }
    
                    @Override
                    protected void writeText(QuickWriter writer, String text) {
                        if (cdata) {
                            writer.write("<![CDATA[");
                            writer.write(text);
                            writer.write("]]>");
                        } else {
                            writer.write(text);
                        }
                    }
                };
            }
        });
    
        /**
         * 文本消息转换成xml
         */
        public static String messageToXml(TextMessageResponseVo textMessageResponseVo) {
            xstream.alias("xml", textMessageResponseVo.getClass());
            return xstream.toXML(textMessageResponseVo);
        }
    
        /**
         * 链接url下载图片
         * @param urlList
         * @param path
         */
        public static void downloadPicture(String urlList,String path) {
            URL url = null;
            try {
                url = new URL(urlList);
                DataInputStream dataInputStream = new DataInputStream(url.openStream());
    
                FileOutputStream fileOutputStream = new FileOutputStream(new File(path));
                ByteArrayOutputStream output = new ByteArrayOutputStream();
    
                byte[] buffer = new byte[1024];
                int length;
    
                while ((length = dataInputStream.read(buffer)) > 0) {
                    output.write(buffer, 0, length);
                }
                fileOutputStream.write(output.toByteArray());
                dataInputStream.close();
                fileOutputStream.close();
            } catch (Exception e) {
                log.error("根据url下载图片异常",e);
            }
        }
    }
    
    

    第三步组合图片与文字信息并返回

    3、4、5步骤是在一个代码块中,所以此处进行详细分解。注:调用方式已在第二步说明

    3.1 整体方法(一些注入的路径,可以自行查阅微信公众号文档)

    /**
     * @author: hugh_lin
     * @date: 2019/06/28 16:37
     * @Description: 公众号客服消息(回复图片)
     * @Modifed:
     **/
    @Service
    public class WeChatCustomerServiceImgMessageServiceImpl implements WeChatMsgService {
    
        /**
         * 图片请求路径
         */
        @Value("${test.imgFileUrl}")
        private String imgFileUrl;
        /**
         * 图片生成路径
         */
        @Value("${test.imgFilePath}")
        private String imgFilePath;
        @Value("${weixin.getDownloadQrCodeUrl}")
        private String downloadQrCodeUrl;
    
        @Autowired
        private WeiXinService weiXinService;
    
        @Override
        public String getReturnMessage(Map<String, String> requestMessageMap) {
    
            // 获取accessToken
            WeiXinAccessTokenDto accessToken = weiXinService.getAccessToken();
            //获取用户信息
            WeiXinUserInfoDto userInfo = null;
            if (accessToken.getAccess_token() != null) {
                userInfo = weiXinService.getUnionID(accessToken.getAccess_token(), requestMessageMap.get("FromUserName"));
            }
    
            // 生成微信公众号二维码
            WeChatQrCodeDto qrCode = weiXinService.getQrCode(accessToken.getAccess_token(), userInfo.getOpenid());
    
            /* 下载二维码图片 */
            // 1.生成下载地址
            StringBuffer qrCodeUrl = new StringBuffer();
            qrCodeUrl.append(downloadQrCodeUrl);
            qrCodeUrl.append("?ticket=");
            qrCodeUrl.append(qrCode.getTicket());
            // 2.生成文件名并生成下载到本地的路径
            StringBuffer imgPath = new StringBuffer();
            imgPath.append("D:\\");
            imgPath.append(UUID.randomUUID());
            imgPath.append(".jpg");
            WeChatUtil.downloadPicture(qrCodeUrl.toString(),imgPath.toString());
    
            // 合成图片
            ImageUtil.generateCompositeImages("D:\\aaa.jpg",userInfo.getHeadimgurl(),imgPath.toString(),userInfo.getNickname());
    
            // 上传到微信公众号素材库,将数据转成json格式并取出需要的数据
            String weChatMedia = weiXinService.getWeChatMediaId(accessToken.getAccess_token(), imgPath.toString(), "image");
            JSONObject media = JSONObject.parseObject(weChatMedia);
    
            // 发送客服消息
            weiXinService.sendCustomerServiceMessage(accessToken.getAccess_token(),userInfo.getOpenid(),"image","media_id",media.getString("media_id"));
    
            return null;
        }
    }
    
    

    3.2 生成公众号二维码(此处为什么要调用微信接口生成呢,因为如果进行裂变的话,需要调用微信扫描二维码事件,所以更方便)

    @Override
        public WeChatQrCodeDto getQrCode(String accessToken, String content) {
    
            // 拼接url
            StringBuffer sb = new StringBuffer();
            sb.append(qrCodeUrl);
            sb.append("?access_token=");
            sb.append(accessToken);
    
            // 生成json数据进行请求
            JSONObject sceneStrJson = new JSONObject();
            sceneStrJson.put("scene_str",content);
            JSONObject sceneJson = new JSONObject();
            sceneJson.put("scene",sceneStrJson);
    
            JSONObject reqJson = new JSONObject();
            reqJson.put("action_name","QR_LIMIT_STR_SCENE");
            reqJson.put("action_info",sceneJson);
    
            String result = HttpUtil.sendPost(sb.toString(), reqJson.toString());
            log.info("获取微信公众号二维码信息为:{}",result);
            // 将返回的字符串转为对象
            WeChatQrCodeDto weChatQrCodeDto = JSON.parseObject(result, WeChatQrCodeDto.class);
            return weChatQrCodeDto;
        }
    

    3.3下载二维码图片到本地(因为要组合图片,需要用到。如何获取微信开发文档中有提及,此处就不多说了。此处调用的是WeChatUtil,在第二步中已写上)

    3.4合成图片(因为调用了Graphics画图工具,组合的图片大小及位置可自行根据UI图进行调整)

    /**
     * @author: hugh_lin
     * @date: 2019/06/28 09:52
     * @Description: 图片工具类
     * @Modifed:
     **/
    @Slf4j
    public class ImageUtil {
    
        /**
         * 生成组合图片(此处根据需求需要组成三张图片)
         * @param args
         *         args[0] backgroundImage 背景图路径
         *         args[1] weChatAvatar 微信头像路径
         *         args[2] qrCode 二维码路径
         *         args[3] 微信名
         */
        public static void generateCompositeImages(String... args){
            try {
                //创建初始图片
                BufferedImage img = new BufferedImage(1242, 2208, BufferedImage.TYPE_INT_RGB);
                //读取本地图片
                BufferedImage backgroundImage = ImageIO.read(new File(args[0]));
                //读取微信头像图片
                BufferedImage weChatAvatar = ImageIO.read(new URL(args[1]));
                //读取本地图片
                BufferedImage qrCode = ImageIO.read(new File(args[2]));
    
                //开启画图
                Graphics g = img.getGraphics();
    
                //将微信头像跟二维码设置为圆角(根据需求变更)
                weChatAvatar = setClip(weChatAvatar,100);
                qrCode = setClip(qrCode, 100);
    
                // 绘制缩小后的图
                g.drawImage(backgroundImage.getScaledInstance(1242,2208, Image.SCALE_DEFAULT), 0, 0, null);
                g.drawImage(weChatAvatar.getScaledInstance(85, 85, Image.SCALE_DEFAULT), 93, 35, null);
                g.drawImage(qrCode.getScaledInstance(370, 370, Image.SCALE_DEFAULT), 203, 1800, null);
    
                g.setColor(Color.black);
                g.setFont(new Font("微软雅黑", Font.PLAIN, 24));
                //绘制文字
                g.drawString(args[3], 214, 58);
    
                g.dispose();
                ImageIO.write(img, "jpg", new File(args[2]));
    
            } catch (Exception e) {
                log.error("生成组合图片异常",e);
            }
        }
    
        /**
         * 图片设置圆角
         * @param srcImage
         * @return
         * @throws IOException
         */
        private static BufferedImage setRadius(BufferedImage srcImage) throws IOException{
            int radius = (srcImage.getWidth() + srcImage.getHeight()) / 6;
            return setRadius(srcImage, radius, 2, 5);
        }
    
        /**
         * 图片设置圆角
         * @param srcImage
         * @param radius
         * @param border
         * @param padding
         * @return
         * @throws IOException
         */
        private static BufferedImage setRadius(BufferedImage srcImage, int radius, int border, int padding) throws IOException{
            int width = srcImage.getWidth();
            int height = srcImage.getHeight();
            int canvasWidth = width + padding * 2;
            int canvasHeight = height + padding * 2;
    
            BufferedImage image = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_ARGB);
            Graphics2D gs = image.createGraphics();
            gs.setComposite(AlphaComposite.Src);
            gs.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            gs.setColor(Color.WHITE);
            gs.fill(new RoundRectangle2D.Float(0, 0, canvasWidth, canvasHeight, radius, radius));
            gs.setComposite(AlphaComposite.SrcAtop);
            gs.drawImage(setClip(srcImage, radius), padding, padding, null);
            if(border !=0){
                gs.setColor(Color.GRAY);
                gs.setStroke(new BasicStroke(border));
                gs.drawRoundRect(padding, padding, canvasWidth - 2 * padding, canvasHeight - 2 * padding, radius, radius);
            }
            gs.dispose();
            return image;
        }
    
        /**
         * 图片切圆角
         * @param srcImage
         * @param radius
         * @return
         */
        private static BufferedImage setClip(BufferedImage srcImage, int radius){
            int width = srcImage.getWidth();
            int height = srcImage.getHeight();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D gs = image.createGraphics();
    
            gs.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            gs.setClip(new RoundRectangle2D.Double(0, 0, width, height, radius, radius));
            gs.drawImage(srcImage, 0, 0, null);
            gs.dispose();
            return image;
        }
    
    }
    
    

    3.5上传到微信公众号素材库(因为调用发送客服图片信息接口时需要用到参数,所以只能先上传到素材库)

     @Override
        public String getWeChatMediaId(String accessToken, String imgPath, String type) {
            try {
                File file=new File(imgPath);
                if (!file.exists() || !file.isFile()) {
                    return null;
                }
    
                // 拼接请求地址
                StringBuffer sb = new StringBuffer();
                sb.append(mediaUrl);
                sb.append("?access_token=");
                sb.append(accessToken);
                sb.append("&type=");
                sb.append(type);
    
                String result = HttpUtil.weChatFodderPost(sb.toString(), file);
    
                return result;
            } catch (Exception e) {
                log.error("素材流关闭异常",e);
            }
    
            return null;
        }
    

    3.6发送客服图片消息

    /**
         *  客服接口-发消息(此方法目前只支持:
         *                               发送文本消息、发送图片消息、发送语音消息、发送视频消息、发送音乐消息)
         * @param args
         * args[0] accessToken
         * args[1] OPENID
         * args[2] msgtype
         * args[3] content、media_id.....
         * args[4] 内容
         */
    @Override
        public void sendCustomerServiceMessage(String... args) {
            // 拼接url
            StringBuffer sb = new StringBuffer();
            sb.append(customerServiceUrl);
            sb.append("?access_token=");
            sb.append(args[0]);
    
            // 生成json数据进行请求
            JSONObject contentJson = new JSONObject();
            contentJson.put(args[3],args[4]);
    
            JSONObject reqJson = new JSONObject();
            reqJson.put("touser",args[1]);
            reqJson.put("msgtype",args[2]);
            reqJson.put(args[2],contentJson);
    
            HttpUtil.sendPost(sb.toString(), reqJson.toString());
    
        }
    

    最后,遇到个bug,因为需求是先返回文字再返回图片。测试的时候,偶然发生了先返回图片再返回文字的情况。从我的认知角度讲,会先执行finally块,再执行return,也是先返回return的消息,再返回finally中的消息。遇到此问题是否由网络延迟或等原因造成的还有待考究。

    最后附上个人微信:a373011739 ,谢谢各位大佬的观看,鞠躬。

    展开全文
  • 微信公众号开发6图片回复

    千次阅读 2017-01-11 16:16:42
    // 分类获取不同的输入信息,然后可用回复不同的信息, 这里直接简单回复文字 if($input_type=="image"){ $msgType="text"; $contentStr="你发送图片干嘛"; $resultStr=sprintf($textTpl,$fromUsername,$to...

    这里使用  $input_type=$postObj->MsgType;// 分类获取不同的输入信息,然后可用回复不同的信息, 这里直接简单回复文字

    if($input_type=="image"){

    $msgType="text";

    $contentStr="你发送图片干嘛";

    $resultStr=sprintf($textTpl,$fromUsername,$toUsername,$time,$msgType,$contentStr);

    echo$resultStr;

    }


    具体实现代码就放在开源中国里面 ,有什么疑问的话欢迎留言交流, 知无不言.

    https://Git.oschina.NET/RoseKissYou/wechat_subscribe/attach_files

    展开全文
  • 实现功能:发送文字回复文字,发送图片回复图片、token验证、获取access_token等相关功能。 如图: 微信后台接口配置 ,此为测试账号,正式设置也是一样的 项目地址:https://github.com/huyande/wxMessage ...

    开发语言:java

    实现功能:发送文字回复文字,发送图片回复图片、token验证、获取access_token等相关功能。

    如图:

    微信后台接口配置 ,此为测试账号,正式设置也是一样的

    项目地址:https://github.com/huyande/wxMessage

    使用项目前 请先给star!

    展开全文
  • 微信公众号开发

    2018-10-17 11:05:48
    微信公众号开发微信公众号开发1.自定义菜单代码2.素材管理3.被动回复消息(包括文字,图片,图文消息) 微信公众号开发 1.自定义菜单代码 1.在文本编辑器中按照微信公众号平台-&amp;amp;gt;开发者工具-&amp;...
  • 关于微信接入第三方域名进行业务开发的相关说明已在另外一篇做了说明,这里不做赘述,接入步骤请移步 https://blog.csdn.net/qq_43638176/article/details/88915436 本篇示范微信交互过程中的几个基础事件,主要...
  • java 微信开发 被动回复图片消息中,已经获得在微信服务器上该图片的mediaId了(因为 根据该mediaId可以从微信服务器上下载下来),但是被动回复该图片就是不能显示出来, 而是提示:"该公众号暂时无法提供服务,请...
  • java版的微信开发源码,包括如何获得access_token,如何回复文本,图片等wlx
  • 由于项目的需要,本人开始研究上传图片到素材库,于是实验成功,拿来分享下 直接看代码 //服务器入口地址 ...//这里通过关键词回复获取公众号发送的图片,这里可自由定义事件 public function responseMs...
  • 首先,应该建立一个消息与图片的实体,看一下微信公众号的文档: 回复文本消息 <xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[from...
  • 先讲回复图片,语音类似。...按照开发文档https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html,被动回复图片消息格式如下: <xml> ...
  • 避免小伙伴们在接入微信开发后,不知道如何实现微信开发者文档上面的一些API功能,今天带来的主题是: SpringBoot+WxJava开发微信公众号图片消息回复,,如果不太了解被动回复用户文本信息的小伙伴,可以先看一下...
  • JAVA 开发微信公众号,已经能收到用户消息,并且封装好回复的消息为xml,但是公众号 就是没有回复给用户,具体代码如下: ![图片说明](https://img-ask.csdn.net/upload/201801/08/1515401934_819663.png) 然后...
  • 这段时间一直想给家里搞个常用工具集,比如撸羊毛推荐,图片识别,图片OCR,在线桌游等。只要联网就能用。于是搜索了一下公有云,搞了台host。除了等备案然后serve网站,想想反正大家都在用微信,不如搭一个类似于小...
  • 微信服务器向开发者的URL推送消息 根据官方文档描述,当普通微信用户向公众账号发消息时,微信服务器将POST消息的...被动回复用户图片消息(开发者向微信服务器推送消息) 推送的数据包结构如下 这里要注意的是:M...
  • 图片回复 随机函数: rand(1,10) ![这里写图片描述]...
  • '这是asp微信公众号自动回复开发案列之新闻查询机器人 '可以对任意输入都提示内容及发送使用说明 '比如发送图片,语音,定位信息,文字信息等都会回复信息。 '是各网页爱好者初学微信公众号接口开发的最佳案列 '是...
  • java开发微信公众号

    2017-12-09 12:27:54
    采用springboot框架开发微信公众号,实现自动回复图片回复,消息交互,创建自定义菜单,采用百度翻译接口实现智能翻译等等,采用合理结构,便于二次开发
  • 微信公众号平台也有自定义回复消息,比如我在公众号里发送关注你,我们在微信公众号平台设置关键字关注你(就是 有人发送这个关键字就要回复什么内容)设置成回复:你好,java!适用于这种固定信息,如果我发送...
  • 相信对于大多数的微信公众号开发的初学者来说,由于微信提供的文档过于简洁,所以这无疑是对我们的巨大考验。 但是,苦心人,天不负。在强烈的“我能行”这一自我暗示下,经过在各大网站上的查询、电子书籍类的读阅...
  • 允许你的粉丝在后台回复图片, 你可以通过公众平台提供的api接口, 获取到图片media_id, 然后把图片下载过来… 微信公众号开发接收图片消息视频教程在线观看 http://edu.csdn.net/cour

空空如也

1 2 3 4 5 ... 10
收藏数 197
精华内容 78
关键字:

微信开发公众号回复图片