公众号开发
公众号配置:微信公众平台
开发文档:微信官方文档 | 微信开放文档
设置服务器AppId、Secret、白名单
菜单:开发-基本配置获得公众号的AppId和AppSecret
服务器配置
网页授权
如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。
-
以snsapi_base为scope的网页授权。即静默授权。
-
以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。
用户第一次授权时用snsapi_userinfo拿用户的基本信息,后续用静默授权即可。
菜单配置
公众号接口调试工具:
菜单增删改查接口文档:
API
@RequestMapping("/wxapi")
@Controller
public class WxApiController {
@Autowired
private GzhMessageService messageService;
@Autowired
private WxApiService weiXinService;
@Autowired
private RedisService redisService;
/**
* GET请求:进行URL、Tocken 认证;
* 1. 将token、timestamp、nonce三个参数进行字典序排序
* 2. 将三个参数字符串拼接成一个字符串进行sha1加密
* 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
*/
@RequestMapping(value = "/wx/receive", method = RequestMethod.GET)
public void doGet(HttpServletRequest request,HttpServletResponse response) {
//如果是多账号,根据url中的account参数获取对应的MpAccount处理即可
Set<String> keySet = request.getParameterMap().keySet();
Iterator<String> iterator = keySet.iterator();
while(iterator.hasNext()){
//如果存在,则调用next实现迭代
String key=iterator.next();
System.out.println("key: " + key + " value: " + request.getParameterMap().get(key)+"");
}
String accessToken = redisService.getAccessToken();
PrintWriter out = null;
try {
out = response.getWriter();
} catch (IOException e) {
e.printStackTrace();
}
if(StringUtils.isNotEmpty(accessToken)){
String signature = request.getParameter("signature");// 微信加密签名
String timestamp = request.getParameter("timestamp");// 时间戳
String nonce = request.getParameter("nonce");// 随机数
String echostr = request.getParameter("echostr");// 随机字符串
// 校验成功返回 echostr,成功成为开发者;否则返回error,接入失败
if (SignUtil.validSign(signature, accessToken, timestamp, nonce)) {
System.out.println("返回数据:"+echostr);
out.print(echostr);
}
}
out.close();
out = null;
}
@RequestMapping(value = "/wx/receive", method = RequestMethod.POST)
public void doPost(HttpServletRequest request,HttpServletResponse response) {
//处理用户和微信公众账号交互消息
try {
MsgRequest msgRequest = MsgXmlUtil.parseXml(request);
PrintWriter out = response.getWriter();
out.print(weiXinService.processMsg(msgRequest));
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@PostMapping("gzhMessagePush")
@ApiOperation("公众号推送")
public Result gzhMessagePush(TemplateDTO template){
return messageService.messagePush(template);
}
}
@Component
public class WxApiServiceImpl implements WxApiService {
@Override
public String processMsg(MsgRequest msgRequest) throws Exception {
String msgtype = msgRequest.getMsgType();// 接收到的消息类型
String respXml = null;// 返回的内容;
if (msgtype.equals("text")) {
//文本消息,一般公众号接收到的都是此类型消息
} else if (msgtype.equals("event")) {// 事件消息
//用户订阅公众账号、点击菜单按钮的时候,会触发事件消息
respXml = this.processEventMsg(msgRequest);
// 其他消息类型,开发者自行处理
} else if (msgtype.equals("image")) {// 图片消息
} else if (msgtype.equals("location")) {// 地理位置消息
}
// 如果没有对应的消息,默认返回订阅消息;
if (StringUtils.isEmpty(respXml)) {
MsgText text = new MsgText();
text.setContent("欢迎关注XXXX");
return MsgXmlUtil.textToXml(WxMessageBuilder.getMsgResponseText(msgRequest, text));
}
return respXml;
}
// 处理事件消息
@Override
public String processEventMsg(MsgRequest msgRequest){
try {
String openId = msgRequest.getFromUserName();
System.out.println("event:"+msgRequest.getEvent());
if ("subscribe".equals(msgRequest.getEvent())) {// 关注
/*====自己的业务====*/
//发送消息
MsgText text = new MsgText();
text.setContent("欢迎关注XXXX");
return MsgXmlUtil.textToXml(WxMessageBuilder.getMsgResponseText(msgRequest, text));
}
else if ("unsubscribe".equals(msgRequest.getEvent())) {// 取消关注
msgResponseText.setContent("取消关注成功");
return MsgXmlUtil.textToXml(msgResponseText);
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
消息推送
-
配置消息模板,获得模板id
-
代码实现
@Service
@Slf4j
public class GzhMessageServiceImpl implements GzhMessageService {
@Value("${gzh.wechat.appsecret}")
private String secret;
@Value("${gzh.wechat.appid}")
private String appId;
@Autowired
private RedisService redisService;
@Override
public Result messagePush(TemplateDTO template) {
//封装请求体
// TemplateDTO template = new TemplateDTO("oHHSbxPyZ9qo8AmFV5CMHA5zoLpA","KSSsdMPEw-hySt17P-Qs1vjLlBmXxyXHxCgKKTbRKxw",null,
// null,"您好,运行监测报告如下","延安医院机房5号服务器","2015-8-30 12:32:33","运行统计",
// "今天总共传输医学影像603份,其中,成功601份,失败2份。","谢谢您及时跟踪系统的运行。");
String errmsg = pull(template.toJSON());
if("ok".equals(errmsg)){
log.info("推送成功");
return Result.ok();
}else {
log.error("推送失败");
return Result.error("推送失败");
}
}
@Override
public String pull(String template){
String token = redisService.getAccessToken();
log.info("获取的token为:{}",token);
if(StringUtils.isBlank(token)){
log.error("推送公众号消息token为空:{}",template);
return "fail";
}
String TEMPLATE_URL = String.format(WechatAPI.TEMPLATE_URL,token);
log.info("获取的TEMPLATE_URL为:{}",TEMPLATE_URL);
String resJson = HttpClientUtil.doTemplateMsgPost(TEMPLATE_URL, template);
log.info("推送公众号消息结果:{}",resJson);
JSONObject jsonObject = JSONObject.parseObject(resJson);
String errmsg = jsonObject.getString("errmsg");
return errmsg;
}
}
TemplateDTO封装消息体
@Data
public class TemplateDTO {
private TemplateDTO(){}
/**
*
* @param toUser 消息接收人的公众号openId
* @param templateId 发送的模板id
* @param url 消息详情
* @param miniprogramDTO 跳转到小程序设置
* @param first 消息模板第一个参数
* @param keyword1 消息模板keyword1
* @param keyword2 消息模板keyword2
* @param keyword3 消息模板keyword3
* @param keyword4 消息模板keyword4
* @param remark 消息模板备注
*/
public TemplateDTO(String toUser, String templateId, String url, MiniprogramDTO miniprogramDTO,
String first,String keyword1,String keyword2,String keyword3,String keyword4,String remark){
this.toUser = toUser;
this.templateId = templateId;
this.url = url;
//this.topColor = topColor;
this.miniprogramDTO = miniprogramDTO;
List<TemplateParamDTO> templateParamList = new ArrayList<>();
if(StringUtils.isNoneBlank(first)){
TemplateParamDTO firstDTO = new TemplateParamDTO("first", first + "\\r\\n", "#DB1A1B");
templateParamList.add(firstDTO);
}
if(StringUtils.isNoneBlank(keyword1)){
TemplateParamDTO keyword1DTO = new TemplateParamDTO("keyword1", keyword1 + "\\r\\n", "#DB1A1B");
templateParamList.add(keyword1DTO);
}
if(StringUtils.isNoneBlank(keyword2)){
TemplateParamDTO keyword2DTO = new TemplateParamDTO("keyword2", keyword2 + "", "#DB1A1B");
templateParamList.add(keyword2DTO);
}
if(StringUtils.isNoneBlank(keyword3)){
TemplateParamDTO keyword3DTO = new TemplateParamDTO("keyword3", keyword3, "#DB1A1B");
templateParamList.add(keyword3DTO);
}
if(StringUtils.isNoneBlank(keyword4)){
TemplateParamDTO keyword4DTO = new TemplateParamDTO("keyword4", keyword4, "#DB1A1B");
templateParamList.add(keyword4DTO);
}
if(StringUtils.isNoneBlank()){
TemplateParamDTO remarkDTO = new TemplateParamDTO("remark", remark, "#DB1A1B");
templateParamList.add(remarkDTO);
}
this.templateParamList = templateParamList;
}
// 消息接收方
private String toUser;
// 模板id
private String templateId;
// 模板消息详情链接
private String url;
// 消息顶部的颜色
private String topColor;
// 参数列表
private List<TemplateParamDTO> templateParamList;
//跳转小程序参数
private MiniprogramDTO miniprogramDTO;
public String toJSON() {
StringBuffer buffer = new StringBuffer();
buffer.append("{");
buffer.append(String.format("\"touser\":\"%s\"", this.toUser)).append(",");
buffer.append(String.format("\"template_id\":\"%s\"", this.templateId)).append(",");
if(StringUtils.isNoneBlank(this.url)){
buffer.append(String.format("\"url\":\"%s\"", this.url)).append(",");
}
if(StringUtils.isNoneBlank(this.topColor)){
buffer.append(String.format("\"topcolor\":\"%s\"", this.topColor)).append(",");
}
//拼接小程序的参数
if(miniprogramDTO !=null){
buffer.append("\"miniprogram\":{");
buffer.append("\"appid\":\"");
buffer.append(miniprogramDTO.getAppid()+"\",");
buffer.append("\"path\":\"");
buffer.append(miniprogramDTO.getPagepath());
buffer.append("\"},");
}
buffer.append("\"data\":{");
TemplateParamDTO param = null;
for (int i = 0; i < this.templateParamList.size(); i++) {
param = templateParamList.get(i);
// 判断是否追加逗号
if (i < this.templateParamList.size() - 1) {
buffer.append(String.format("\"%s\": {\"value\":\"%s\",\"color\":\"%s\"},", param.getName(), param.getValue(), param.getColor()));
} else {
buffer.append(String.format("\"%s\": {\"value\":\"%s\",\"color\":\"%s\"}", param.getName(), param.getValue(), param.getColor()));
}
}
buffer.append("}");
buffer.append("}");
return buffer.toString();
}
}