SpringCloud implements WeChat message push

overview

WeChat public platform test account: https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
WeChat push document: https://mp.weixin.qq.com/debug /cgi-bin/readtmpl?t=tmplmsg/faq_tmpl
Baidu map open platform: https://lbsyun.baidu.com/apiconsole/center#/home
weather service interface document: https://lbs.baidu.com/index. php?title=webapi/weather

achieve effect

message template

{
    
    {
    
    date.DATA}} {
    
    {
    
    week.DATA}} 
{
    
    {
    
    city.DATA}}的天气:{
    
    {
    
    temp.DATA}} 
最低气温:{
    
    {
    
    low.DATA}}度 
最高气温:{
    
    {
    
    high.DATA}}

Implementation code

nacos configuration

wechat:
  # 微信公众号账号
  mappid:  wx6269*************
  # 微信公众号密码
  msecret: d931f8205f1***************
  # 微信公众账号原始ID
  original_id: gh_6*******
weather:
  data_type: all
  ak: o5ewfdqWFAkk********
   # 区号,例如广州市天河区
  district_id: 440106

WechatProperties

/**
 * @author lanys
 * @author Think
 * @title: WechatProperties
 * @projectName material_cloud
 * @description: YML 微信配置信息映射
 * @date 2022/12/20 11:09
 */
@Getter
@Setter
@Component
@ConfigurationProperties("wechat")
public class WechatProperties {
    
    

    private String mappid;

    private String msecret;

    private String originalId;
}

Weather

/**
 * @author lanys
 * @author Think
 * @title: Weather
 * @projectName maku-cloud
 * @description: 获取百度天气数据
 * @date 2022/12/29 12:20
 */
@Getter
@Setter
@Component
@ConfigurationProperties("weather")
public class Weather {
    
    

    private String districtId;

    private String dataType;

    private String ak;
}

AccessToken

/**
 * 微信通用接口凭证
 * @author lanys
 */
public class AccessToken implements java.io.Serializable{
    
    

	  
	private static final long serialVersionUID = -4240357901925120079L;

	/** 获取到的凭证 */ 
	private String token;

	/** 凭证有效时间,单位:秒 */ 
	private int expiresIn;

	public AccessToken() {
    
    
	}

	public AccessToken(String token, int expiresIn) {
    
    
		this.token = token;
		this.expiresIn = expiresIn;
	}

	public String getToken() {
    
    
		return token;
	}

	public void setToken(String token) {
    
    
		this.token = token;
	}

	public int getExpiresIn() {
    
    
		return expiresIn;
	}

	public void setExpiresIn(int expiresIn) {
    
    
		this.expiresIn = expiresIn;
	}
}

WeatherModel

/**
 * @author lanys
 * @author Think
 * @title: Weather
 * @projectName maku-cloud
 * @description: 天气
 * @date 2022/12/30 12:06
 */
@Setter@Getter
@AllArgsConstructor
@NoArgsConstructor
public class WeatherModel {
    
    

    /** 省 */
    private String province;
    /** 市 */
    private String city;
    /** 区 */
    private String name;
    /** 天气 */
    private String text;
    /** 级 */
    private String wind_class;
    /** 风向 */
    private String wind_dir;

    private String textNight;
    /** 最高温度 */
    private String high;
    /** 最低温度 */
    private String low;
    /** 日期 */
    private String date;
    /** 星期几 */
    private String week;
    /** 当前温度 */
    private String temp;

}

RedisCache

@Component
public class RedisCache {
    
    
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 默认过期时长为24小时,单位:秒
     */
    public final static long DEFAULT_EXPIRE = 60 * 60 * 24L;
    /**
     * 过期时长为1小时,单位:秒
     */
    public final static long HOUR_ONE_EXPIRE = 60 * 60 * 1L;
    /**
     * 过期时长为6小时,单位:秒
     */
    public final static long HOUR_SIX_EXPIRE = 60 * 60 * 6L;
    /**
     * 不设置过期时长
     */
    public final static long NOT_EXPIRE = -1L;

    public void set(String key, Object value, long expire) {
    
    
        redisTemplate.opsForValue().set(key, value);
        if (expire != NOT_EXPIRE) {
    
    
            expire(key, expire);
        }
    }

    public void set(String key, Object value) {
    
    
        set(key, value, DEFAULT_EXPIRE);
    }

    public Object get(String key, long expire) {
    
    
        Object value = redisTemplate.opsForValue().get(key);
        if (expire != NOT_EXPIRE) {
    
    
            expire(key, expire);
        }
        return value;
    }

    public Object get(String key) {
    
    
        return get(key, NOT_EXPIRE);
    }
}

HttpUtils

/**
 * @Author: Lanys
 * @Description: https 调用工具
 * @Date: Create in 21:51 2022/12/21
 */
@Slf4j
@Component
@AllArgsConstructor
public class HttpUtils {
    
    

    private final RedisCache redisCache;

    private final WechatProperties wechatProperties;

    private final Weather weather;

    /** 获取access_token的接口地址(GET) 限2000(次/天) */
    public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
    /** 获取关注用户id */
    public final static String USER_GET_URL = "https://api.weixin.qq.com/cgi-bin/user/get?access_token={0}";
    /** 获取天气情况 */
    public final static String WEATHER = "https://api.map.baidu.com/weather/v1/?data_type={0}&ak={1}&district_id={2}";

    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
    
    
        log.debug("[发起https请求]requestUrl=" + requestUrl);
        log.debug("[发起https请求]requestMethod=" + requestMethod);
        log.debug("[发起https请求]outputStr=" + outputStr);
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();
        try {
    
    
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = {
    
    new X509TrustManager() {
    
    
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    
    

                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    
    

                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
    
    
                    return new X509Certificate[0];
                }
            }};
            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();
            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
     * @return
     * @throws Exception
     */
    public AccessToken getAccessToken() throws Exception{
    
    
        String appid = wechatProperties.getMappid();
        String secret = wechatProperties.getMsecret();
        AccessToken accessToken = null;
        String requestUrl = ACCESS_TOKEN_URL.replace("{0}",appid).replace("{1}",secret);
        JSONObject jsonObject=null;
        if(null== redisCache.get(appid)){
    
    
            //access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
            //获取access_token 每日限额 2000次,注:如各个业务逻辑点各自去刷新access_token,那么就可能会产生冲突,导致服务不稳定
            jsonObject = httpsRequest(requestUrl, "GET", null);
            log.info("[(刷新)获取access_token]jsonObject="+jsonObject);
            //CacheUtil.put(appid, jsonObject, jsonObject.getInt("expires_in")-7000<200?jsonObject.getInt("expires_in"):200 );//简易定时器 ,200秒内值缓存
            redisCache.set(appid, jsonObject.toString(), jsonObject.getInteger("expires_in")-7000<200?jsonObject.getInteger("expires_in"):200);
        }
        jsonObject = JSONObject.parseObject((String) redisCache.get(appid));

        if (null != jsonObject) {
    
    
            try {
    
    
                accessToken = new AccessToken(jsonObject.getString("access_token"), jsonObject.getInteger("expires_in"));
            } catch (JSONException e) {
    
    
                log.error("获取token失败 errcode:{} errmsg:{}"+jsonObject.getInteger("errcode")+"errmsg:"+jsonObject.getString("errmsg"),e);
            }
        }
        log.info("[获取access_token]jsonObject="+jsonObject);
        log.info("[获取access_token]accessToken="+accessToken.getToken());
        return accessToken;
    }

    /**
     * 获取关注用户
     * @return
     */
    public List<String> getUsers() {
    
    
        try {
    
    
            log.info("------------ [获取用户信息] ---------------");
            String appid = wechatProperties.getMappid();
             String token = null;
            if(null== redisCache.get(appid)){
    
    
                AccessToken accessToken = this.getAccessToken();
                if (accessToken != null) {
    
    
                    token = accessToken.getToken();
                }
            } else {
    
    
                JSONObject jsonObject = JSONObject.parseObject((String) redisCache.get(appid));
                token = jsonObject.getString("access_token");
            }
            if (token != null) {
    
    
                String requestUrl = USER_GET_URL.replace("{0}",token);
                JSONObject jsonObject = HttpUtils.httpsRequest(requestUrl, "GET", null);
                String dataJson = jsonObject.getString("data");
                JSONObject data = JSONObject.parseObject(dataJson);
                JSONArray openid = data.getJSONArray("openid");
                List<String> list = new ArrayList<>();
                if (openid != null && openid.size() > 0) {
    
    
                    for (int i = 0; i < openid.size(); i++) {
    
    
                        Object obj = openid.get(i);
                        if (obj != null) {
    
    
                            list.add(obj.toString());
                        }
                    }
                }
                return list;
            }
        } catch (Exception e) {
    
    
            log.error("[获取关注用户信息]数据异常:",e);
        }
        return null;
    }

    /**
     * 获取天气
     * @return
     */
    public WeatherModel getWeather(){
    
    
        try{
    
    
            log.info("------------ [获取天气] ------------");
            String requestUrl = WEATHER.replace("{0}", weather.getDataType()).replace("{1}", weather.getAk())
                    .replace("{2}", weather.getDistrictId());
            JSONObject jsonObject = HttpUtils.httpsRequest(requestUrl, "GET", null);
            if (jsonObject != null) {
    
    
                WeatherModel weather = new WeatherModel();
                JSONObject jsonObj = jsonObject.getJSONObject("result");
                JSONObject object = jsonObj.getJSONObject("location");
                if (object != null) {
    
    
                    weather.setProvince(object.getString("province"));
                    weather.setCity(object.getString("city"));
                    weather.setName(object.getString("name"));
                }
                object = jsonObj.getJSONObject("now");
                if (object != null) {
    
    
                    weather.setText(object.getString("text"));
                    weather.setWind_class(object.getString("wind_class"));
                    weather.setWind_dir(object.getString("wind_dir"));
                    weather.setTemp(object.getString("temp"));
                }
                JSONArray forecasts = jsonObj.getJSONArray("forecasts");
                if (!CollectionUtils.isEmpty(forecasts)) {
    
    
                    Map<String, Object> obj = (Map<String,Object>)forecasts.get(0);
                    if (obj != null) {
    
    
                        weather.setTextNight(obj.get("text_night").toString());
                        weather.setHigh(obj.get("high") != null ? obj.get("high").toString():null);
                        weather.setLow(obj.get("low") != null ? obj.get("low").toString():null);
                        weather.setDate(obj.get("date").toString());
                        weather.setWeek(obj.get("week").toString());
                    }
                }
                return weather;
            }
        } catch (Exception e) {
    
    
            log.error("[获取天气信息]数据异常:",e);
        }
        return null;
    }

}

timed task

/**
 * @Author: Lanys
 * @Description: 定时推送任务
 * @Date: Create in 22:05 2022/12/21
 */
@Slf4j
@Service
public class WechatPush {
    
    

    @Resource
    public HttpUtils httpUtils;

    public void run(String params) throws Exception {
    
    
        //默认都是用正式模板
        String templateId = "BaKzfhFvinVpNPV2xVo1zkIWMWrBlazt9cMzxkry-5U";
        String messageTemplate = "{\"touser\":\"{0}\",\"template_id\":\""+templateId+"\","
                + "\"data\":{\"date\": {\"value\":\"{1}\",\"color\":\"#00BFFF\"},\"week\":{\"value\":\"{2}\",\"color\":\"#00FFFF\"},"
                + "\"city\": {\"value\":\"{3}\",\"color\":\"#173177\"},\"temp\": {\"value\":\"{4}\",\"color\":\"#EE212D\"},"
                + "\"low\":{\"value\":\"{5}\",\"color\":\"#FF6347\"},"
                + "\"high\":{\"value\":\"{6}\",\"color\":\"#173177\"}}}";
        // 获取token
        AccessToken accessToken = httpUtils.getAccessToken();
        String URL_TEMPLATE_MSG_SEND = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}";
        String sendUrl = URL_TEMPLATE_MSG_SEND.replace("{0}", accessToken.getToken());
        // 获取关注用户
        List<String> users = httpUtils.getUsers();
        if (users != null && users.size() > 0) {
    
    
            // 获取天气
            WeatherModel weather = httpUtils.getWeather();
            // 并行遍历推送
            users.stream().parallel().forEach(x->{
    
    
                if (x != null) {
    
    
                    String postData = messageTemplate.replace("{0}", x)
                            .replace("{1}", weather.getDate())
                            .replace("{2}", weather.getWeek())
                            .replace("{3}", weather.getCity())
                            .replace("{4}", weather.getText())
                            .replace("{5}", weather.getLow())
                            .replace("{6}", weather.getHigh());
                    log.info("[发送模板信息]sendTemplateMessage:"+postData);
                    JSONObject jsonObject = HttpUtils.httpsRequest(sendUrl, "POST", postData);
                    log.info("[发送模板信息] sendTemplateMessage result:"+jsonObject);
                }
            });
        }
    }
}

insert image description here

application process

WeChat public testing platform

basic personal information

Address: WeChat public testing platform
insert image description here

Follow users and templates

insert image description here

interface documentation

Process: Obtain the token first before pushing the message
insert image description here

Baidu map open platform

Address: Baidu Map Open Platform

Process introduction

You need to apply for an account to enter the open platform. After entering the open platform, you need to apply for a developer or use a company to apply. After the application is completed, it will be fine.
insert image description here

Guess you like

Origin blog.csdn.net/qq_44697754/article/details/128035736