如果微信服务号或者订阅号一旦接入了开发者模式,微信的后台自动回复后台的配置就会消失,菜单配置也会消失,这时候就需要开发人员写代码来维护!第一步:填写服务器配置
1.可以参照微信官方文档点击打开链接 基本上不会错唯一注意的是url 一定要是外网的地址而且端口是80或者443
第二步:验证消息的确来自微信服务器
@RequestMapping(value="/service",method={RequestMethod.GET})
@ResponseBody
public void index(HttpServletRequest request,HttpServletResponse response) throws Exception{
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
String result = "";
if(StringUtil.isNotEmpty(echostr)){
String[] arr = new String[] {TOKEN, timestamp, nonce};
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
Arrays.sort(arr);
Boolean checkFlag = content ==null ? false : signature.equals(EncryptUtils.SHA1(content.toString()));
result = echostr;
}else{
Map<String,String> map = WeixinFormatXmlProcess.parseXml(request);
String content = map.get("Content");
String ToUserName = map.get("ToUserName");
String FromUserName = map.get("FromUserName");
String replayMessage = WeixinFormatXmlProcess.formatXmlAnswer(ToUserName, FromUserName,content);
result = replayMessage;
}
PrintWriter pw = response.getWriter();
response.setContentType("text/plain");
pw.write(result);
pw.flush();
pw.close();
}
第三步:依据接口文档实现业务逻辑
/**
*
* @Title: index1
* @Description:
* @param @param request
* @param @param response
* @param @throws Exception
* @return void
*/
@RequestMapping(value="/service",method={RequestMethod.POST})
@ResponseBody
public void index1(HttpServletRequest request,HttpServletResponse response) throws Exception{
logger.debug(" request service wx qq ... ");
WxMessage modelInfo = new WxMessage();
modelInfo.setWx_service_type("2");
String replayMessage = wxMessageService.getWeiXinReplayMessage(request, modelInfo);
logger.debug(" replayMessage is ... {}",replayMessage);
if(StringUtil.isNotEmpty(replayMessage)){
wirteRespose(response, replayMessage);
}
}
@Override
public String getWeiXinReplayMessage(HttpServletRequest request,WxMessage modelInfo) throws Exception{
String replayMessage ="";
Map<String,String> map = WeixinFormatXmlProcess.parseXml(request);
String eventType = map.get("Event");
String toUserName = map.get("ToUserName");
String fromUserName = map.get("FromUserName");
String content = map.get("Content");
//关注事件
if ("subscribe".equals(eventType)) {
modelInfo.setWx_reply_type("1");
replayMessage = getWeiXinReplayMessage(fromUserName,toUserName,getWxMessageByModel(modelInfo));
}
else {
List<WxMessage> listWxMessage = getListWxMessageByModel(modelInfo);
if (null!=listWxMessage && listWxMessage.size()>0) {
for(WxMessage model: listWxMessage){
if(content.trim().equals(model.getWx_key_words())){
replayMessage = getWeiXinReplayMessage(fromUserName,toUserName,model);
}
}
}
}
return replayMessage ;
}
/**
* 封装文字类的返回消息
* @param to
* @param from
* @param content
* @return
*/
public static String formatXmlAnswer(String to, String from, String content) {
StringBuffer sb = new StringBuffer();
Date date = new Date();
sb.append("<xml><ToUserName><![CDATA[");
sb.append(to);
sb.append("]]></ToUserName><FromUserName><![CDATA[");
sb.append(from);
sb.append("]]></FromUserName><CreateTime>");
sb.append(date.getTime());
sb.append("</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[");
sb.append(content);
sb.append("]]></Content>");
/*sb.append("<MsgId>");
sb.append(msgid);
sb.append("</MsgId>");*/
sb.append("</xml>");
return sb.toString();
}
/**
*
* @Title: formatXmlImage
* @Description: 回复图片消息
* @param @param to
* @param @param from
* @param @param content
* @param @param media_id
* @param @return
* @return String
*/
public static String formatXmlImage(String to, String from, String content,Object media_id) {
StringBuffer sb = new StringBuffer();
Date date = new Date();
sb.append("<xml><ToUserName><![CDATA[");
sb.append(to);
sb.append("]]></ToUserName><FromUserName><![CDATA[");
sb.append(from);
sb.append("]]></FromUserName><CreateTime>");
sb.append(date.getTime());
sb.append("</CreateTime>");
sb.append("<MsgType><![CDATA[image]]></MsgType>");
sb.append("<Image><MediaId><![CDATA[");
sb.append(media_id);
sb.append("]]></MediaId></Image>");
sb.append("</xml>");
return sb.toString();
}
/**
*
* @Title: formatXmlImageAndText
* @Description: 回复图文消息
* @param @param to
* @param @param from
* @param @param model
* @param @return
* @return String
*/
public static String formatXmlImageAndText(String to, String from,WxMessage model) {
StringBuffer sb = new StringBuffer();
int wxArticleCount = model.getWx_article_count();
String wxArticleTitle = model.getWx_article_title();
String [] wxArticleTitleArray =new String[wxArticleCount];
if(StringUtil.isNotEmpty(wxArticleTitle)){
for(int i=0;i<wxArticleTitle.split(WEIXIN_SPLIT).length;i++){
wxArticleTitleArray[i] = wxArticleTitle.split(WEIXIN_SPLIT)[i];
}
}
String wxPicUrl= model.getWx_pic_url();
String [] wxPicUrlArray = new String[wxArticleCount];
if(StringUtil.isNotEmpty(wxPicUrl)){
for(int i=0;i<wxPicUrl.split(WEIXIN_SPLIT).length;i++){
wxPicUrlArray[i] = wxPicUrl.split(WEIXIN_SPLIT)[i];
}
}
String wxArticleUrl= model.getWx_article_url();
String [] wxArticleUrlArray = new String[wxArticleCount];
if(StringUtil.isNotEmpty(wxArticleUrl)){
for(int i=0;i<wxArticleUrl.split(WEIXIN_SPLIT).length;i++){
wxArticleUrlArray[i] = wxArticleUrl.split(WEIXIN_SPLIT)[i];
}
}
String wxMessageDesc= model.getWx_message_desc();
String [] wxMessageDescArray = new String[wxArticleCount];
if(StringUtil.isNotEmpty(wxMessageDesc)){
for(int i=0;i<wxMessageDesc.split(WEIXIN_SPLIT).length;i++){
wxMessageDescArray[i] = wxMessageDesc.split(WEIXIN_SPLIT)[i];
}
}
Date date = new Date();
sb.append("<xml><ToUserName><![CDATA[");
sb.append(to);
sb.append("]]></ToUserName><FromUserName><![CDATA[");
sb.append(from);
sb.append("]]></FromUserName><CreateTime>");
sb.append(date.getTime());
sb.append("</CreateTime>");
sb.append("<MsgType><![CDATA[news]]></MsgType>");
sb.append("<ArticleCount>"+wxArticleCount+"</ArticleCount>");
sb.append("<Articles>");
for(int i=0;i<wxArticleCount;i++){
sb.append("<item>");
if(StringUtil.isNotEmpty(wxArticleTitleArray[i])){
sb.append("<Title><![CDATA["+wxArticleTitleArray[i]+"]]></Title>");
}
if(StringUtil.isNotEmpty(wxMessageDescArray[i])){
sb.append("<Description><![CDATA["+wxMessageDescArray[i]+"]]></Description>");
}
if(StringUtil.isNotEmpty(wxPicUrlArray[i])){
sb.append("<PicUrl><![CDATA["+(String)SysConfigInit.sysConfig.get(GlobalConstant.IMGPATH_URL_DOMAIN)+wxPicUrlArray[i]+"]]></PicUrl>");
}
if(StringUtil.isNotEmpty(wxArticleUrlArray[i])){
sb.append("<Url><![CDATA["+wxArticleUrlArray[i]+"]]></Url>");
}
sb.append("</item>");
}
sb.append("<Articles>");
sb.append("</xml>");
return sb.toString();
}
/**
*
* @Title: parseXml1
* @Description: 获取微信端传过来的参数
* @param @param str
* @param @return
* @param @throws Exception
* @return Map<String,Object>
*/
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;
}
/**
*
* @Title: parseXml1
* @Description: 获取微信端传过来的参数
* @param @param str
* @param @return
* @param @throws Exception
* @return Map<String,Object>
*/
public static Map<String,Object> parseXml1(String str) throws Exception {
// 将解析结果存储在HashMap中
Map<String,Object> map = new HashMap<String,Object>();
// 从request中取得输入流
InputStream inputStream =new ByteArrayInputStream(str.getBytes()); //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;
}
/**
*
* @param type 类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
* @param filename 文件名字
* @param mediaFileUrl 文件路劲
*/
public static String uploadPermanentMedia(String type, String filename, String mediaFileUrl,String accessToken) {
String medeId="";
BufferedReader reader = null;
OutputStream out = null;
DataInputStream in = null;
try {
// 拼装请求地址
String uploadMediaUrl = "http://api.weixin.qq.com/cgi-bin/material/add_material?access_token=##ACCESS_TOKEN##&type=##type##";
uploadMediaUrl = uploadMediaUrl.replace("##ACCESS_TOKEN##", accessToken).replace("##type##", type);
URL url = new URL(uploadMediaUrl);
String result = null;
File file = new File(mediaFileUrl);
if (!file.exists() || !file.isFile()) {
System.out.println("上传的文件不存在");
}
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST"); // 以Post方式提交表单,默认get方式
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false); // post方式不能使用缓存
// 设置请求头信息
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=\"media\";filename=\""
+ filename + "\" \r\n");
sb.append("Content-Type:application/octet-stream\r\n\r\n");
byte[] head = sb.toString().getBytes("utf-8");
// 获得输出流
out = new DataOutputStream(con.getOutputStream());
// 输出表头
out.write(head);
// 文件正文部分
// 把文件已流文件的方式 推入到url中
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输入流来读取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();
}
// 使用JSON-lib解析返回结果
JSONObject jsonObject = JSONObject.fromObject(result);
if (jsonObject.has("media_id")) {
medeId =jsonObject.getString("media_id");
logger.info("media_id:" + jsonObject.getString("media_id"));
} else {
logger.error(jsonObject.toString());
}
} catch (IOException e) {
logger.error("发送POST请求出现异常!" + e);
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
logger.error("关闭异常");
e.printStackTrace();
}
}
return medeId;
}
/**
*
* @Title: deleteMedid
* @Description: 删除永久素材
* @param @param medid
* @param @return
* @param @throws Exception
* @return boolean
*/
public static boolean deleteMedid(String medid,String access_token){
String medeid = "{\"media_id\":\""+medid+"\"}";
String url ="https://api.weixin.qq.com/cgi-bin/material/del_material?access_token="+access_token;
String result =SmsClientAccessTool.getInstance().doAccessHTTPPost(url, medeid,null);
JSONObject jsonObject = JSONObject.fromObject(result);
if(jsonObject!=null){
if(0==jsonObject.getInt("errcode")){
logger.info("删除成功medid"+medid);
return true;
}else{
logger.info("删除失败medid"+medid);
return false;
}
}else{
return false;
}
}
这个方法是第一步里面配置的url 这时候只要用户和公众号交互就会进入这个方法这时候用户就可以在这个方法里面写用户关注、关键字回复的消息。这个方法也可以拿到用户的openid 拿到用户open_id特别需要注意这是微信的服务端的方法。所以拿到open_id不能存在session里面需要存到数据库里面。获取open_id 有两种方式第一种是在这个方法里面,第二种是通过网页授权获取后面会讲到。怎么通过网页授权拿到open_id。这里基本上可以回复图文消息、文字消息、图片消息。
文字消息
图片消息(图片消息需要上传素材)
图文消息(这里需要注意最多只能八条图文一次性)
至此基本上完成了微信的消息服务。基本上这些回复做成后台可配置的附上一些后台的截图