`
空指针异常
  • 浏览: 22598 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类

微信开发

wx 
阅读更多
参考文章
http://www.cnblogs.com/txw1958/p/weixin-qrcode-with-parameters.html
http://tuposky.iteye.com/blog/2082230
https://github.com/caspar-chen/WechatSDK

@Action("wxAction")
public class WeixinAction extends ActionSupport {
	public static final Logger logger = Logger.getLogger(WeixinAction.class);
	
	@Autowired
	private WXUserService wxUserService;

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public String execute() throws Exception {
		HttpServletRequest req = ServletActionContext.getRequest();
		PrintWriter out = ServletActionContext.getResponse().getWriter();
		String method = req.getMethod();
		if (WXConstants.METHOD_GET.equals(method)) {
			// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数
			String signature = req.getParameter("signature");
			// 时间戳
			String timestamp = req.getParameter("timestamp");
			// 随机数
			String nonce = req.getParameter("nonce");
			// 随机字符串
			String echostr = req.getParameter("echostr");

			// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
			if (SignUtil.checkSignature(signature, timestamp, nonce)) {
				out.print(echostr);
			}
		} else if (WXConstants.METHOD_POST.equals(method)) {
			// xml请求解析
			Map<String, String> reqMap = MessageUtil.parseXml(req);

			// 消息类型
			String msgType = reqMap.get("MsgType");
			if (msgType.equals(WXConstants.REQ_MESSAGE_TYPE_EVENT)) {
				String eventType = reqMap.get("Event");
				String openID = reqMap.get("FromUserName");
				String ticket = reqMap.get("Ticket");
				// 获取用户基本信息
				String nickname = WXInterfaceUtil.getNickname(openID);
				// 用户未关注时
				if (eventType.equals(WXConstants.EVENT_TYPE_SUBSCRIBE)) {
					logger.info("新关注用户openID:" + openID);
				}
				// 用户已关注
				else if (eventType.equals(WXConstants.EVENT_TYPE_SCAN)) {
					logger.info("已关注用户openID:" + openID);
				}
				// 更新数据库
				wxUserService.updateUserInfoByTicket(ticket, nickname, openID);
			}
		}

		out.close();
		out = null;
		return null;
	}
}


@Action("qrcodeCreateAction")
public class QrcodeCreateAction extends ActionSupport {
	@Autowired
	private WXUserService wxUserService;
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -7930634700220791363L;
	
	@Override
	public String execute() throws Exception {
		PrintWriter out = ServletActionContext.getResponse().getWriter();
		// 获取传输的参数SN
		String sn = ServletActionContext.getRequest().getParameter("sn");
		
		// 生成临时二维码,每次生成二维码时ticket不一样,当用户扫描二维码时,可根据ticket更新关联的记录
		// 不能用永久二维码,因为永久二维码每次产生的ticket每次都一样
		String accessToken = WXInterfaceUtil.getAccessToken();
		String ticket = WXInterfaceUtil.createTempQrcode(accessToken);
		if(null == ticket){
			WXInterfaceUtil.access_token = null;
			accessToken = WXInterfaceUtil.getAccessToken();
			ticket = WXInterfaceUtil.createTempQrcode(accessToken);
		}
		
		//将当前请求的数据存入数据库,如果当前sn在数据库中已有记录,更新ticket,如果没有,新增一条记录
		wxUserService.saveOrUpdateUserInfo(sn, ticket);
		
		JSONObject obj = new JSONObject();
		//如果取ticket失败
		if(null == ticket){
			obj.put("errcode", "99");
			obj.put("errmsg", "failure");
		}else{
			//组装生成二维码URL,get请求
			String qrCodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;
			obj.put("qrCodeUrl", qrCodeUrl);
			obj.put("errcode", "0");
			obj.put("errmsg", "success");
		}
		out.print(obj.toString());
		return null;
	}
}


@Service
public class WXUserServiceImpl implements WXUserService {
	
	@Autowired
	private WXUserDao wxUserDao;
	/**
	 * 当安卓客户端请求二维码时,如果当前请求的盒子信息没有保存在数据库中,则新增数据至数据库。
	 * 如果当前盒子已经请求过二维码,将ticket更新,并且清空用户信息
	 * 
	 * @param sn
	 * @param ticket
	 */
	public void saveOrUpdateUserInfo(String sn,String ticket){
		WXUser user = wxUserDao.getBySN(sn);
		//如果用户不存在
		if(null == user){
			WXUser u = new WXUser();
			u.setSn(sn);
			u.setTicket(ticket);
			u.setCreateTime(new Date());
			wxUserDao.save(u);
		}
		//用户已存在,更新ticket,清空用户信息
		else{
			user.setTicket(ticket);
			user.setCreateTime(new Date());
			user.setNickname("");
			user.setOpenId("");
			user.setLastLoginTime(null);
			user.setFlag(0);
			wxUserDao.update(user);
		}
	}
	
	/**
	 * 用户扫描二维码,用户根据ticket更新用户信息
	 * 
	 * @param ticket
	 * @param nickname
	 * @param openId
	 */
	public void updateUserInfoByTicket(String ticket,String nickname,String openId){
		WXUser user = wxUserDao.getByTicket(ticket);
		user.setNickname(nickname);
		user.setOpenId(openId);
		user.setLastLoginTime(new Date());
		wxUserDao.update(user);
	}
}


public class MessageUtil {
    /**
     * 解析微信发来的请求(XML)
     * 
     * @param request
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
        // 将解析结果存储在HashMap中
        Map<String, String> map = new HashMap<String, String>();

        // 从request中取得输入流
        InputStream inputStream = request.getInputStream();
        // 读取输入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        // 得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子节点
        List<Element> elementList = root.elements();

        // 遍历所有子节点
        for (Element e : elementList)
                map.put(e.getName(), e.getText());

        // 释放资源
        inputStream.close();
        inputStream = null;

        return map;
    }
}

public class ReqUtil {
	private static final Logger logger = Logger.getLogger(ReqUtil.class);
	
	/**
	 * POST 请求
	 * 
	 * @param reqUrl
	 * @param reqParams
	 * @return String
	 */
	public static String post(String reqUrl, String params) {
		logger.info("POST Request,Url:" + reqUrl);
		DataOutputStream outStream = null;
		HttpURLConnection conn = null;
		String result = "";
		try {
			byte[] data = params.toString().getBytes();
			URL realUrl = new URL(reqUrl);
			conn = (HttpURLConnection) realUrl
					.openConnection();
			conn.setDoOutput(true);// 发送POST请求必须设置允许输出
			conn.setUseCaches(false);// 不使用Cache
			conn.setRequestMethod(WXConstants.METHOD_POST);
			conn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
			conn.setRequestProperty("Charset", "UTF-8");
			conn.setRequestProperty("Content-Length",
					String.valueOf(data.length));
			conn.setRequestProperty("Content-Type",
					"application/x-www-form-urlencoded");
			outStream = new DataOutputStream(
					conn.getOutputStream());
			outStream.write(data);
			outStream.flush();
			if (conn.getResponseCode() == 200) {
				result = readData(conn.getInputStream(), "UTF-8");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			if(null != outStream){
				try {
					outStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if(null != conn){
				conn.disconnect();
			}
		}
		return result;
	}

	/**
	 * Get 请求
	 * 
	 * @param reqUrl
	 * @return String
	 */
	public static String get(String reqUrl) {
		logger.info("GET Request,Url:" + reqUrl);
		InputStream is = null;
		HttpURLConnection conn = null;
		String result = "";
		try {
			URL url = new URL(reqUrl);
			conn = (HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(5 * 1000);// 设置连接超时
			conn.setRequestMethod(WXConstants.METHOD_GET);// 以get方式发起请求
			if (conn.getResponseCode() != 200)
				throw new RuntimeException("请求url失败");
			is = conn.getInputStream();// 得到网络返回的输入流
			result = readData(is, "UTF-8");
			conn.disconnect();
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			if(null != is){
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if(null != conn){
				conn.disconnect();
			}
		}
		return result;
	}

	/**
	 * 第一个参数为输入流,第二个参数为字符集编码
	 * 
	 * @param inSream
	 * @param charsetName
	 * @return String
	 * @throws Exception
	 */
	private static String readData(InputStream inSream, String charsetName)
			throws Exception {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = -1;
		while ((len = inSream.read(buffer)) != -1) {
			outStream.write(buffer, 0, len);
		}
		byte[] data = outStream.toByteArray();
		outStream.close();
		inSream.close();
		return new String(data, charsetName);
	}
}


public class SignUtil {
	// Token可由开发者任意填写,用作生成签名
	private static final String token = "test";
	
	/**
	 * 检验signature对请求进行校验,确认此次GET请求来自微信服务器
	 * 
	 * @param signature
	 * @param token
	 * @param timestamp
	 * @param nonce
	 * @return boolean
	 */
	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(String str : arr){
			content.append(str);
		}
		
		// sha1加密
		MessageDigest md = null;
		String tmpStr = null;
		try {
			md = MessageDigest.getInstance("SHA-1");
			// 将三个参数字符串拼接成一个字符串进行sha1加密
			byte[] digest = md.digest(content.toString().getBytes());
			tmpStr = byteToStr(digest);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		
		content = null;
		// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
		return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
	}
	
	/**
	 * 将字节数组转换为十六进制字符串
	 * 
	 * @param byteArray
	 * @return String
	 */
	private static String byteToStr(byte[] byteArray) {
		StringBuilder strDigest = new StringBuilder();
		for (int i = 0; i < byteArray.length; i++) {
			strDigest.append(byteToHexStr(byteArray[i]));
		}
		return strDigest.toString();
	}
	
	/**
	 * 将字节转换为十六进制字符串
	 * 
	 * @param mByte
	 * @return String
	 */
	private static String byteToHexStr(byte mByte) {
		char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
		char[] tempArr = new char[2];
		tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
		tempArr[1] = Digit[mByte & 0X0F];

		String s = new String(tempArr);
		return s;
	}
}

public class WXInterfaceUtil {
	private static final Logger logger = Logger
			.getLogger(WXInterfaceUtil.class);

	/**
	 * access_token有效期为7200秒,不需要每次都去调用
	 */
	public static String access_token = null;

	/**
	 * 获取access_token
	 * 
	 * @return String
	 */
	public static String getAccessToken() {
		if (null == access_token) {
			// 获取ACCESS_TOKEN
			String reqUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
					+ WXConstants.APPID + "&secret=" + WXConstants.APPSECRET;
			String result = ReqUtil.get(reqUrl);
			logger.info("get access token,result:" + result);
			JSONObject obj = JSONObject.fromObject(result);
			access_token = (String) obj.get("access_token");
			logger.info("access_token: " + access_token);
		}
		return access_token;
	}

	/**
	 * 获取用户呢称
	 * 
	 * @param openID
	 * @return String
	 */
	public static String getNickname(String openID) {
		String reqUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="
				+ getAccessToken() + "&openid=" + openID + "&lang=zh_CN";
		String result = ReqUtil.get(reqUrl);
		logger.info("get nickname,result:" + result);
		JSONObject obj = JSONObject.fromObject(result);
		String nickname = (String) obj.get("nickname");
		
		logger.info("nickname: " + nickname);
		return nickname;
	}

	/**
	 * 创建临时二维码
	 * 
	 * @return String
	 */
	public static String createTempQrcode(String accessToken) {
		String reqUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="
				+ accessToken;
		String params = "{\"expire_seconds\": " + WXConstants.EXPIRE_SECONDS
				+ ", \"action_name\": \"" + WXConstants.ACTION_NAME
				+ "\", \"action_info\": {\"scene\": {\"scene_id\": "
				+ WXConstants.SCENE_ID + "}}}";
		String result = ReqUtil.post(reqUrl, params);
		logger.info("create temp qrcode,result:" + result);
		JSONObject obj = JSONObject.fromObject(result);
		String ticket = (String)obj.get("ticket");
		logger.info("ticket: " + ticket);
		return ticket;
	}
}
分享到:
评论

相关推荐

    微信开发学习总结(二)——微信开发环境准备(2)项目源码

    为微信开发学习总结(二)——微信开发环境准备(2)博客讲解中附带源码。 参考博客: 微信开发学习总结(二)——微信开发环境准备(2) https://blog.csdn.net/qq_29914837/article/details/82896861

    企业微信开发实操考试.pdf

    企业微信开发实操考试涉及的具体知识点涵盖了企业微信的部署、API接口调用、通讯录管理、OAuth2认证流程、以及JS-SDK接口实现等多个方面。以下是对知识点的详细说明: 1. 企业微信私有化部署与CA数据中心集成: - ...

    微信开发视频教程文档【50集】

    本套微信开发视频教程系统的讲解了微信开发的机制以及一些比较实用的案例,如:天气预报、附近酒店、刮刮乐、百度翻译、快递查询、会员卡、航班查询。下载文件中包括了视频和相关源代码。

    Java微信开发教程

    Java微信开发入门,主要介绍大微信公众号介绍、开发这环境的一个搭建、发送消息自定回复、企业实战中的微信开发

    WeChatDeveloper微信开发工具包 v1.2.54.zip

    WeChatDeveloper微信开发工具包 v1.2.54.zip

    微信开发调试工具 小程序源代码

    微信开发调试工具 小程序源代码微信开发调试工具 小程序源代码微信开发调试工具 小程序源代码微信开发调试工具 小程序源代码微信开发调试工具 小程序源代码微信开发调试工具 小程序源代码微信开发调试工具 小程序源...

    微信开发实例 微信公众平台开发 之微信接口前期准备

    微信开发实例 微信公众平台开发教程-深入浅出微信公众平台实战开发(微网站、LBS云、Api接口调用、服务号高级接口)1.微信接口前期准备。由北风网提供,微信开发实例微信公众平台基础篇: 1)微信公众平台简介:开发...

    完整的微信开发项目

    java开发微信的web项目.百分百可以运行,自己测试过的.适合微信开发初学者.完全参照微信开发者文档规范开发的java微信web项目

    微信开发文档

    微信开发即微信公众平台开发,将企业信息、服务、活动等内容通过微信网页的方式进行表现,用户通过简单的设置,就能生成微信3G网站。通过微信公众平台将企业品牌展示给微信用户,减少宣传成本,建立企业与消费者、...

    微信开发包sdk(含demo)

    微信开发包SDK是一个针对微信平台的开发者工具,它包含了丰富的接口文档、示例代码和开发指南,便于开发者进行微信相关的功能集成。以下是对这个开发包的详细解释: 1. **微信支付**:微信支付是微信提供的移动支付...

    C#微信开发模板

    简单的C#的微信开发,很适合刚开始微信开发的人士。

    【ASP.NET编程知识】.NET微信开发之PC 端微信扫码注册和登录功能实现.docx

    【ASP.NET编程知识】.NET微信开发之PC 端微信扫码注册和登录功能实现.docx

    微信开发的小程序项目代码.zip

    微信开发的小程序项目代码.zip微信开发的小程序项目代码.zip微信开发的小程序项目代码.zip微信开发的小程序项目代码.zip微信开发的小程序项目代码.zip微信开发的小程序项目代码.zip微信开发的小程序项目代码.zip微信...

    微信开发jar包

    微信开发需要用的jar包总结和归纳微信开发需要用的jar包总结和归纳微信开发需要用的jar包总结和归纳微信开发需要用的jar包总结和归纳微信开发需要用的jar包总结和归纳微信开发需要用的jar包总结和归纳微信开发需要用...

    微信开发教程 c#版

    微信开发教程 c#版 详细介绍如何使用C#进行微信开发的详细步骤,希望对大家有帮助

    微信开发工具类

    微信开发工具类,里面包含了微信用的http和https通信协议公共类,http里头又有很多构造方法,基本满足微信开发需求,完全可以直接调用...完成可以直接调用,本人目前在做微信开发,有需要的可以下载,记得好评额,谢谢

    微信开发工具

    微信开发工具 这是由腾讯张小龙所打造的一个跨时代的工具

    C#微信开发教程.rar

    C#微信公众平台开发基础教程教程里附源码对微信开发入门者很有帮助,欢迎下载使用。 文中指导怎样申请微信开发的环境及部分源码可作为参考。

    php微信开发心得

    相信很多人都需要这样一份有关微信开发的资料,从基本功能到通用,curl都有说道。可以互相交流

    Python微信开发神器-视频(2)

    学习用Python开发微信 ,了解微信开发原理,接入微信开发接口。

Global site tag (gtag.js) - Google Analytics