微信公众号客服接口给指定用户openid发送消息

微信开发文档:

 

客服接口-发消息

 

接口调用请求说明

http请求方式: POST
https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN

各消息类型所需的JSON数据包如下:

发送文本消息

{
    "touser":"OPENID",
    "msgtype":"text",
    "text":
    {
         "content":"Hello World"
    }
}

创建封装实体类:

import java.util.Map;

/**
 * 客户接口消息发送实体
 *
 * @author 
 * @date 2018-2-6 11:00:30
 */
public class TestMessage {

    //openid
    private String touser;

    //消息类型
     private String msgtype;

     //消息内容
     private Map<String,Object> text ;


    public String getTouser() {
        return touser;
    }

    public void setTouser(String touser) {
        this.touser = touser;
    }

    public String getMsgtype() {
        return msgtype;
    }

    public void setMsgtype(String msgtype) {
        this.msgtype = msgtype;
    }

    public Map<String, Object> getText() {
        return text;
    }

    public void setText(Map<String, Object> text) {
        this.text = text;
    }
}

 

 

 

后台controller代码:

 

 
 
/**
 * 状态修改为测试中
 *
 * @param id 要测试的ID
 * @param request
 * @return 内容展示页面
 */
@ResponseBody
@RequestMapping(value = "/service/test", method = RequestMethod.PUT)
public ResponseVO ContentTest(Long id, HttpServletRequest request) {

    ResponseVO vo=new ResponseVO();
    if(id!=null){
        //根据接收的ID查询相应的内容实体
        WeixinContent weixinContent = weixinContentService.selectById(id);
     //判断查询到的对象的合法性
    if (weixinContent!=null&&(weixinContent.getState() == 1||weixinContent.getState()==4)) {
        //修改内容实体状态为测试中
        weixinContent.setState(2);

        //将内容实体进行保存操作
        weixinContentService.updateById(weixinContent);
        //获得内容静态页面的访问路径
       String templatesUrl= weixinContent.getTemplatesUrl();
        //拼接访问的完整路径
        String saveUrl =fileuploadPrefix + "/" + templatesUrl;
        //获得内容信息标题
        String title = weixinContent.getTitle();
        //拼接发送的消息内容
        String content="你好!标题("+title+")<a href='"+saveUrl+"'>点我测试</a>";
        //创建微信用户查询条件
        Wrapper<WeixinUser> wrapper=new EntityWrapper<>();
        wrapper.where("tagid_list={0}","[101]");
        //获得满足条件的集合
        List<WeixinUser> weixinUsers = weixinUserService.selectList(wrapper);
        //遍历用户集合调用业务层进行消息发送
        for (WeixinUser weixinUser : weixinUsers) {
            String openid = weixinUser.getOpenid();
            //调用业务层进行发送消息
            wxContentTextService.contentTest(openid,content);
        }

        vo.setSuccess(true);
    } else {
        //不是未测试状态所以不能进行状态修改
        vo.setSuccess(false);
    }

    }
    return vo;
}

后台service代码:

 
/**
 * <p>
 * 菜单信息 服务实现类
 * </p>
 *
 * @author 
 * @date 2018/01/15
 */
@Service
public class WxContentTextService {

    private static Logger log = LoggerFactory.getLogger(WxContentTextService.class);

    /**
     * 客服接口给用户发送消息接口
     */
    public static String  content_openid="https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN";

    @Autowired
    private TokenFeignService tokenFeignService;

    @Autowired
    private WeixinPortalService weixinPortalService;

    /**
     *
     * @param openid   openid
     * @param saveUrl   静态页面访问地址
     * @return
     */
    public ResponseVO contentTest(String openid,String saveUrl){
        //获得令牌
        String accessToken = tokenFeignService.getToken();

        //创建返回实体对象
        ResponseVO vo = new ResponseVO();
        //替换token
        String url=content_openid.replace("ACCESS_TOKEN", accessToken);

        TestMessage testMessage=new TestMessage();
        //设置消息的类型
        testMessage.setMsgtype("text");
        //设置要发送的openid集合
        testMessage.setTouser(openid);
        //创建集合
        Map<String,Object> map=new HashMap<>();
        //设置发送内容
        map.put("content",saveUrl);
        testMessage.setText(map);
        //将测试消息对象转成json
        String jsonTestMessage = JSONObject.toJSONString(testMessage);
        //调用接口进行发送
        JSONObject jsonObject = httpRequest(url, "POST", jsonTestMessage);

        log.error("分组群发消息失败 errcode:{" + jsonObject.getInteger("errcode")+"} " +
                "errmsg:{"+jsonObject.getString("errmsg")+"} ");
        Integer errcode = jsonObject.getInteger("errcode");
        String errorCodeText = ErrorCodeText.errorMsg(errcode);

        if (errcode == 0){
            vo.setSuccess(true);
        }else{
            vo.setSuccess(false);
        }
        vo.setCode(errcode);
        vo.setText(errorCodeText);
        return vo;

    }
}

获取token的业务层:

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 进行请求分发
 *
 */
@FeignClient(value = "weixin-2")
public interface TokenFeignService {

    /**
     * 进行token请求
     * @param
     * @return
     */
    @RequestMapping(value = "/getToken",method = RequestMethod.GET)
    String getToken();
}

微信请求工具类utils

 
public class WeixinHttpUtil {

    private static Logger log = LoggerFactory.getLogger(WeixinHttpUtil.class);

    /**
     * 描述:  发起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.parseObject(buffer.toString());
        } catch (ConnectException ce) {
            log.error("Weixin server connection timed out.");
        } catch (Exception e) {
            log.error("https request error:{}", e);
        }
        return jsonObject;
    }
}
 

应网友要求贴出获取token部分代码,首先要配置公众号相关配置

1.IP白名单

2.配置开发模式

3.在自己配置的白名单服务器就可以获取token,根据自己配置的服务器接口就可以监听所有公众号的操作,从而得到操作用户信息和具体操作内容

3.1这个就是通过springCloud远程调用获取token接口

@Controller
@RequestMapping("")
public class WeixinTokenController {

    @Autowired
    private WeixinAccessTokenTask weixinAccessTokenTask;

    @RequestMapping("getToken")
    @ResponseBody
    public String getToken(){
        AccessToken token = weixinAccessTokenTask.getLastAccessToken();
        return token.getAccessToken();
    }

}

3.2具体获取token业务

@Component
public class WeixinAccessTokenTask implements ApplicationListener {

    protected final static Logger logger = LoggerFactory.getLogger(WeixinAccessTokenTask.class);

    private static boolean isStart = false;

    /**
     * 微信Access_Token刷新地址
     */
    private String uri = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    /**
     * 存放Access_Token的标识符
     */
    private String tokenKey = "WEIXIN_ACCESS_TOKEN";
    /**
     *  最近一次的Access_Token
     */
    private AccessToken lastAccessToken;

    /**
     * 微信分配的appID
     */
    @Value("${app.id}")
    private String appID;
    /**
     * 微信分配的appsecret
     */
    @Value("${app.secrect}")
    private String appsecrect;

    private long lastRunTime;

    /**
     * 刷新Access_Token
     * @return boolean 刷新是否成功
     */
    @Scheduled(cron="0 0/5 * * * ?")
    public boolean refresh(){
        boolean refresh = this.refresh(false);
        //重置最后一次定时器运行时间
        lastRunTime = System.currentTimeMillis();
        return refresh;
    }


    /**
     * 刷新Access_Token
     * @param forced 是否强制
     * @return boolean 刷新是否成功
     */
    public boolean refresh(boolean forced){
        if(!(forced || this.isNeedRefresh())){
            return false;
        }

        try {
            AccessToken token = this.getWeixinAccessToken();
            //把token存入lastAccessToken,便于下次检验token是否有效
            lastAccessToken = token;
            return true;
        } catch (IOException e){
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 请求微信接口获取最新的access_token信息
     * @return AccessToken
     */
    public AccessToken getWeixinAccessToken() throws IOException{
        String uri = this.uri.replace("APPID",
                this.getAppID()).replace("APPSECRET",
                this.getAppsecrect());
        URL url = new URL(uri);

        HttpURLConnection conn = null;
        BufferedReader reader = null;
        StringBuffer buffer = new StringBuffer();
        try{
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.connect();
            reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));

            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
        }finally {
            if(reader != null){
                reader.close();
            }

            if(conn != null){
                conn.disconnect();
            }
        }
        //返回的参数是json格式
        JSONObject jsonObject = JSONObject.parseObject(buffer.toString());
        AccessToken token = new AccessToken();
        if (!jsonObject.containsKey("access_token")) {//如果没拿到token,肯定发生了问题,打印错误日志
            logger.info(jsonObject.toJSONString());
        }
        String accessToken = jsonObject.getString("access_token");
        String expiresInStr = jsonObject.getString("expires_in");
        int expiresIn = Integer.parseInt(expiresInStr);
        token.setAccessToken(accessToken);
        token.setExpiresIn(expiresIn);
        //设置token的更新时间
        token.setUpdateTime(new Date());
        logger.info("最新的token>>>> "+ AesUtil.aesEncrypt(accessToken));
        return token;
    }

    /**
     *  是否需要刷新
     *
     *  @return boolean 判断是否需要刷新
     */
    private boolean isNeedRefresh(){
        AccessToken token = this.getLastAccessToken();
        /*如果上次会话不存在,肯定是需要刷新缓存的*/
        if(null == token){
            return true;
        }
        //当前系统时间
        long now = System.currentTimeMillis();
        //此次运行和上次运行的时间间隔,5min
        long interval = now - this.lastRunTime;
        //上次token的更新时间
        long lastTimeMillis = this.getLastTimeMillis();
        //此处在微信规定7200秒的基础上减去1800秒,即度过1h30m的时间,就认为token已失效,以此保证token的有效性
        int expiresIn = 5400*1000;
        /*如果时间间隔不足以支撑到下次运算时的超时时间,则会话会在本次被刷新*/
//        logger.info("判断是否需要刷新开始---------");
//        logger.info("                   此时此刻 now            ---------" + now);
//        logger.info("此次运行和上次运行的时间间隔 interval       ---------" + interval);
//        logger.info("        上次token的更新时间 lastTimeMillis ---------" + lastTimeMillis);
//        logger.info("               token有效期  expiresIn      ---------" + expiresIn);
//        logger.info("计算表达式(lastTimeMillis + expiresIn) <= (now + interval)---------" + ((lastTimeMillis + expiresIn) <= (now + interval)));
        if((lastTimeMillis + expiresIn) <= (now + interval)){
            return true;
        }
        return false;
    }

    private String getAppID() {
        return appID;
    }

    public void setAppID(String appID) {
        this.appID = appID;
    }

    private String getAppsecrect() {
        return appsecrect;
    }

    public void setAppsecrect(String appsecrect) {
        this.appsecrect = appsecrect;
    }

    public AccessToken getLastAccessToken(){
        if(this.lastAccessToken == null){
            return null;
        }
        return this.lastAccessToken;
    }

    //获得token有效期的时间戳
    private long getLastTimeMillis(){
        AccessToken token = this.getLastAccessToken();
        Date updateTime = token.getUpdateTime();
        if(updateTime == null){
            return 0L;
        }
        long millis = updateTime.getTime();
        return millis;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        if (!isStart) {
            isStart = true;
            logger.info("启动token刷新服务..........");
            this.refresh();
        }
    }
}

 

  • 6
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 28
    评论
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值