微信服务号Java开发(一)

发送模板消息

1. 服务器配置

  • 解析:微信发送一个get请求,并携带4个参数:signature、timestamp、nonce、echostr。开发者需要验证该请求是否来源于微信,验证方法:

    1)将token、timestamp、nonce三个参数进行字典序排序

    2)将三个参数字符串拼接成一个字符串进行sha1加密

    3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

1.1. 配置官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
1.2. sha1 加密:(Service)
	/**
	 * sha1加密
	 * @param str
	 * @return
	 */
	private static String sha1(String str) {
		try {
			//获取一个加密对象
			MessageDigest md = MessageDigest.getInstance("sha1");
			//加密
			byte[] digest = md.digest(str.getBytes());
			//处理加密结果
			char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
		    StringBuffer sb = new StringBuffer();
		    for (byte b : digest) {
				sb.append(chars[(b>>4) & 15]);
				sb.append(chars[b & 15]);
			}
		    return sb.toString();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return null;
	}
1.3. 检验signature:(Service)
	/**
	 * 配置服务器时检验signature
	 * @param timestamp
	 * @param nonce
	 * @param signature
	 * @return
	 */
	private static final String TOKEN = "bpa";
	public static boolean check(String timestamp,String nonce,String signature) {
		//1. 将token、timestamp、nonce三个参数进行字典排序
		String[] strs = new String[] {TOKEN, timestamp, nonce };
		Arrays.sort(strs);
		//2.将三个参数字符串拼接成一个字符串进行sha1加密
		String str = strs[0] + strs[1] + strs[2];
		String mysig = sha1(str);
		//3.开发者获得加密后的字符串可与signature对比,标识该请求源于微信
		return mysig.equals(signature);
	}
1.6. servlet的get方法:处理微信发送的数据(servlet)
	//配置服务器
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		/*
	    signature	微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
		timestamp	时间戳
		nonce	        随机数
		echostr	        随机字符串	 
		*/
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		
		System.out.println(signature);
		System.out.println(timestamp);
		System.out.println(nonce);
		System.out.println(echostr);
		
		//验证请求来自微信
		if(WxService.check(timestamp,nonce,signature)){
			System.out.println("接入成功!");
			PrintWriter out = response.getWriter();
			//原样返回echostr参数
			out.print(echostr);
			out.flush();
			out.close();
		}
		else{
			System.out.println("接入失败!");
		}
	}
1.7. 提交

在这里插入图片描述

2. 获取AccessToken

1553172154104

2.1. 向指定地址发送get请求(util)
/**
 * 向指定的地址发送get请求
 * 
 * @param url
 * @return
 */
public static String get(String url) {
	try {
		URL urlObj = new URL(url);
		// 开链接
		URLConnection connection = urlObj.openConnection();
		InputStream is = connection.getInputStream();
		byte[] b = new byte[1024];
		int len;
		StringBuilder sb = new StringBuilder();
		while ((len = is.read(b)) != -1) {
			sb.append(new String(b, 0, len));
		}
		return sb.toString();

	} catch (Exception e) {

		e.printStackTrace();
	}
	return null;
}
2.2. AccessToken类
package entity;
public class AccessToken {
	private String accessToken;
	private long expireTime;//过期时间
	public String getAccessToken() {
		return accessToken;
	}
	public void setAccessToken(String accessToken) {
		this.accessToken = accessToken;
	}
	public long getExpireTime() {
		return expireTime;
	}
	public void setExpireTime(long expireTime) {
		this.expireTime = expireTime;
	}
	
	public AccessToken(String accessToken, String expireIn) {
		super();
		this.accessToken = accessToken;
		this.expireTime = System.currentTimeMillis()+Integer.parseInt(expireIn)*1000;
	}
	
	/**
	 * 判断token是否过期
	 * @return
	 */
	public boolean isExpire() {
		return System.currentTimeMillis() > expireTime; 
	}
}

2.3. 导json jar包

在这里插入图片描述

2.4. 获取AccessToken (service):
private static final String GET_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
private static final String APPID = "wx8820c0d640b18647";
private static final String APPSECRET = "2bb4d6c310395e17c47e75384ba80c43";
// 用于存储token
private static AccessToken at;
/**
 * 获取token
 */
private static void getToken() {
	String url = GET_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET);
	String tokenStr = Util.get(url);
	// System.out.println(tokenStr);//获取到的是一个JSON数据
	// 将JSON数据的值取出来,封装到AccessToken类中
	JSONObject jsonObject = JSONObject.fromObject(tokenStr);
	String token = jsonObject.getString("access_token");
	String expiresIn = jsonObject.getString("expires_in");
	// 创建token对象,并存起来
	at = new AccessToken(token, expiresIn);
}

/**
 * 向外暴露的获取token的方法
 * 
 * @return
 */
public static String getAccessToken() {
	if (at == null || at.isExpire()) {
		getToken();
	}
	return at.getAccessToken();
}

3.获取用户信息

4. 发送模板消息

3.1.首先看一下模板消息运营规范

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751288

3.2.新增模板

在这里插入图片描述

3.3. 设置行业信息
  • 向指定地址发送一个携带json数据的post请求

  • JSON数据格式

    {
        "industry_id1":"1",
        "industry_id2":"4"
    }
    
  • 向指定地址发送post请求(util)

    	/**
    	 * 向指定的地址发送一个post请求,带着json数据
    	 * 
    	 * @param url
    	 * @param data
    	 * @return
    	 */
    	public static String post(String url, String data) {
    		try {
    			URL urlObj = new URL(url);
    			URLConnection connection = urlObj.openConnection();
    			// 要发送数据出去,必须设置为可发送数据状态
    			connection.setDoOutput(true);
    
    			OutputStream os = connection.getOutputStream();
    			// 写出数据
    			os.write(data.getBytes(Charset.forName("utf-8")));
    			os.close();
    			// 获取输入流
    			InputStream is = connection.getInputStream();
    			byte[] b = new byte[1024];
    			int len;
    			StringBuilder sb = new StringBuilder();
    			while ((len = is.read(b)) != -1) {
    				sb.append(new String(b, 0, len));
    			}
    			return sb.toString();
    
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    
    
  • 设置行业信息以及获取行业信息

    	/**
    	 * 设置行业
    	 */
    	@Test
    	public void setHy() {
    		String at = WxService.getAccessToken();
    		String url = "https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=ACCESS_TOKEN";
    		url = url.replace("ACCESS_TOKEN", at);
    		String data = "{\r\n" + "    \"industry_id1\":\"1\",\r\n" + "    \"industry_id2\":\"4\"\r\n" + "}";
    
    		String result = Util.post(url, data);
    		System.out.println(result);
    	}
    
    	/**
    	 * 获取行业信息
    	 */
    	@Test
    	public void getHy() {
    		String at = WxService.getAccessToken();
    		String url = "https://api.weixin.qq.com/cgi-bin/template/get_industry?access_token=ACCESS_TOKEN";
    		url = url.replace("ACCESS_TOKEN", at);
    		String result = Util.get(url);
    		System.out.println(result);
    	}
    
    
3.4.发送模板消息:
3.4.1.解析
  • 向微信地址发送一个携带JSON数据的post请求

    https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
    
  • JSON数据格式

     {
               "touser":"o8WIn57l7aU_km1WGlYo64CPB0rM",
               "template_id":"fnuSPVY0RYEYxmKbmj9aL6VVU1A1LYKKUBZmaCZz9rY",
               "url":"http://weixin.qq.com/download",            
               "data":{
                       "first": {
                           "value":"您好!您投递的简历有新的反馈!",
                           "color":"#173177"
                       },
                       "company":{
                           "value":"北京58同城信息技术有限公司",
                           "color":"#173177"
                       },
                       "time": {
                           "value":"2014-06-24",
                           "color":"#173177"
                       },
                       "result": {
                           "value":"产品经理",
                           "color":"#173177"
                       },
                       "remark":{
                           "value":"反馈结果请和本公司人事联系!",
                           "color":"#173177"
                       }
               }
    }
    

在这里插入图片描述

3.4.2.向指定地址发送post 请求
	/**
	 * 向指定的地址发送一个post请求,带着json数据
	 * 
	 * @param url
	 * @param data
	 * @return
	 */
	public static String post(String url, String data) {
		try {
			URL urlObj = new URL(url);
			URLConnection connection = urlObj.openConnection();
			// 要发送数据出去,必须设置为可发送数据状态
			connection.setDoOutput(true);

			OutputStream os = connection.getOutputStream();
			// 写出数据
			os.write(data.getBytes(Charset.forName("utf-8")));
			os.close();
			// 获取输入流
			InputStream is = connection.getInputStream();
			byte[] b = new byte[1024];
			int len;
			StringBuilder sb = new StringBuilder();
			while ((len = is.read(b)) != -1) {
				sb.append(new String(b, 0, len));
			}
			return sb.toString();

		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
3.4.2 封装该POST数据
  • 导jar包:应用@XStreamAlias(“data”)注解。

    在这里插入图片描述

  • 将value、color属性封装成一个类 DataBase

    public class DataBase {
    
    	@XStreamAlias("value")
    	private String value;
    	
    	@XStreamAlias("color")
    	private String color;
    
    	public String getValue() {
    		return value;
    	}
    
    	public void setValue(String value) {
    		this.value = value;
    	}
    
    	public String getColor() {
    		return color;
    	}
    
    	public void setColor(String color) {
    		this.color = color;
    	}
    
    	public DataBase(Map<String, String> map) {
    		this.value = map.get("value");
    		this.color = map.get("color");
    	}	
    }
    
    
  • 将first、company、time、result、remark封装成类,类继承DataBase

    @XStreamAlias("first")
    public class First extends DataBase{
    	public First(Map<String, String> map) {
    		super(map);
    	}
    }
    
    @XStreamAlias("company")
    public class Company extends DataBase{
    	public Company(Map<String, String> map) {
    		super(map);
    	}
    }
    
    @XStreamAlias("time")
    public class Time extends DataBase{
    
    	public Time(Map<String, String> map) {
    		super(map);
    	}
    }
    
    @XStreamAlias("result")
    public class Result extends DataBase{
    
    	public Result(Map<String, String> map) {
    		super(map);
    	}
    }
    
    @XStreamAlias("remark")
    public class Remark extends DataBase{
    	public Remark(Map<String, String> map) {
    		super(map);
    	}
    }
    
  • 封装data类:类属性为:First、Company、Time、Result、Remark类的对象

    @XStreamAlias("data")
    public class Data {
    	private First first;
    	private Company company;
    	private Time time;
    	private Result result;
    	private Remark remark;
    	public First getFirst() {
    		return first;
    	}
    	public void setFirst(First first) {
    		this.first = first;
    	}
    	public Company getCompany() {
    		return company;
    	}
    	public void setCompany(Company company) {
    		this.company = company;
    	}
    	public Time getTime() {
    		return time;
    	}
    	public void setTime(Time time) {
    		this.time = time;
    	}
    	public Result getResult() {
    		return result;
    	}
    	public void setResult(Result result) {
    		this.result = result;
    	}
    	public Remark getRemark() {
    		return remark;
    	}
    	public void setRemark(Remark remark) {
    		this.remark = remark;
    	}
    	public Data(First first, Company company, Time time, Result result, Remark remark) {
    		super();
    		this.first = first;
    		this.company = company;
    		this.time = time;
    		this.result = result;
    		this.remark = remark;
    	}	
    }
    
  • 整个要发送的数据对象Message

    
    @XStreamAlias("xml")
    public class Message {
    	
    	@XStreamAlias("touser")
    	private String touser;
    	@XStreamAlias("template_id")
    	private String template_id;
    	@XStreamAlias("url")
    	private String url;
    	
    	private Data data;
    
    	public String getTouser() {
    		return touser;
    	}
    
    	public void setTouser(String touser) {
    		this.touser = touser;
    	}
    
    	public String getTemplate_id() {
    		return template_id;
    	}
    
    	public void setTemplate_id(String template_id) {
    		this.template_id = template_id;
    	}
    
    	public String getUrl() {
    		return url;
    	}
    
    	public void setUrl(String url) {
    		this.url = url;
    	}
    
    	public Data getData() {
    		return data;
    	}
    
    	public void setData(Data data) {
    		this.data = data;
    	}
    
    	public Message(String touser, String template_id, String url, Data data) {
    		super();
    		this.touser = touser;
    		this.template_id = template_id;
    		this.url = url;
    		this.data = data;
    	}	
    }
    
3.4.3.配置文件template.properties
post_url=https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
touser=o8WIn57l7aU_km1WGlYo64CPB0rM
template_id=fnuSPVY0RYEYxmKbmj9aL6VVU1A1LYKKUBZmaCZz9rY
click_url=https://www.baidu.com
first_value=您好!你有新的报平安任务!
first_color=#173177
company_value=任务名称
company_color=#173177
time_value=发布时间
time_color=#173177
result_value=发布人
result_color=#173177
remark_value=请及时上报任务!
remark_color=#173177
3.4.4 .实现将xml转为json的方法
  • 导包

    在这里插入图片描述

  • 方法

	/**
	 * 将xml数据转为JSON数据字符串
	 * 
	 * @param xml
	 * @return
	 * @throws JDOMException
	 * @throws IOException
	 */
	public static String xmlToJSON(String xml) {
		XMLSerializer xmlSerializer = new XMLSerializer();
		// 将xml转为json(注:如果是元素的属性,会在json里的key前加一个@标识)
		JSON jsonObject = xmlSerializer.read(xml);
		return jsonObject.toString();
	}
3.4.5.发送模板消息
	public void sendTemplateMessage() {
		try {
			// 加载模板
			InputStream is = SendMsg.class.getResourceAsStream("/template.properties");
			Properties pro = new Properties();
			pro.load(is);
			// 获取AccessToken
			String at = WxService.getAccessToken();
			System.out.println(at);
			// 从模板中获取post的参数url
			String url = pro.getProperty("post_url");
			url = url.replace("ACCESS_TOKEN", at);

			// 获取post参数:data
			// first
			Map<String, String> map_first = new HashMap<>();
			map_first.put("value", pro.getProperty("first_value"));
			map_first.put("color", pro.getProperty("first_color"));
			First first = new First(map_first);

			// company
			Map<String, String> map_company = new HashMap<>();
			map_company.put("value", pro.getProperty("company_value"));
			map_company.put("color", pro.getProperty("company_color"));
			Company company = new Company(map_company);

			// time
			Map<String, String> map_time = new HashMap<>();
			map_time.put("value", pro.getProperty("time_value"));
			map_time.put("color", pro.getProperty("time_color"));
			Time time = new Time(map_time);

			// result
			Map<String, String> map_result = new HashMap<>();
			map_result.put("value", pro.getProperty("result_value"));
			map_result.put("color", pro.getProperty("result_color"));
			Result result = new Result(map_result);

			// remark
			Map<String, String> map_remark = new HashMap<>();
			map_remark.put("value", pro.getProperty("remark_value"));
			map_remark.put("color", pro.getProperty("remark_color"));
			Remark remark = new Remark(map_remark);

			// data
			Data dataMsg = new Data(first, company, time, result, remark);

			// touser:先从配置文件获取,之后要获取用户openid存到数据库
			String touser = pro.getProperty("touser");

			// template_id
			String template_id = pro.getProperty("template_id");

			// 点击后跳转的链接
			String click_url = pro.getProperty("click_url");

			// 整个要发送的数据
			Message msg = new Message(touser, template_id, click_url, dataMsg);

			// XStream stream = new XStream();当属性带有下划线"_"转成XML时会变成双下划线"__"
			XStream stream = new XStream(new Xpp3Driver(new NoNameCoder()));
			// 处理需要@XStream注解的类
			stream.processAnnotations(Message.class);
			stream.processAnnotations(Data.class);
			stream.processAnnotations(First.class);
			stream.processAnnotations(Company.class);
			stream.processAnnotations(Time.class);
			stream.processAnnotations(Result.class);
			stream.processAnnotations(Remark.class);

			// 将Java类转为xml
			String xml = stream.toXML(msg);
			System.out.println(xml);

			// 将xml数据转为json
			String data = WxUtils.xmlToJSON(xml);
			System.out.println(data);

			// 发送post请求
			String rst = WxUtils.post(url, data);
			System.out.println(rst);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值