WeChat public number development menu processing

Keywords: Programming JSON Java github Spring

I. Preface

  1. WeChat public number development (1) WeChat access certification as developer
  2. WeChat public number development (2) message processing
This article will implement
  1. Get access_token according to AppID and AppSecret
  2. Custom menu (create menu, query menu, delete menu)
Some tips in wechat documents:
  1. access_token must be stored with at least 512 characters.
  2. The valid period of access_token is 2 hours. It needs to be refreshed regularly. Repeated access will cause the last access_token to be invalid
  3. Up to 3 first level menus can be customized, and up to 5 second level menus can be customized
  4. At most 4 Chinese characters in the first level menu and 7 Chinese characters in the second level menu
  5. Menu refresh policy: update the menu in 5 minutes. During the test, you can try to cancel paying attention to the public account and pay attention to it again, then you can see the effect after creation

2, RestTemplate configuration (used to call wechat http interface method remotely)

RestTemplate is a client provided by Spring to access the Rest service. RestTemplate provides a variety of convenient methods to access remote Http service, which can greatly improve the writing efficiency of the client.

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        // Solve the problem of Chinese scrambling in post request
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        return restTemplate;
    }

}

3, Wechat interface call description

  1. GET access? Token interface: [GET request] https://api.weixin.qq.com/cgi-bin/token? Grant? Type = client? Credential & appid = apppid & Secret = appsecret
  2. Query menu interface: [GET request] https://api.weixin.qq.com/cgi-bin/menu/GET? Access menu token = access menu token
  3. Delete menu interface: [GET request] https://api.weixin.qq.com/cgi-bin/menu/delete? Access? Token = access? Token
  4. Create menu interface: [POST request] https://api.weixin.qq.com/cgi-bin/menu/create? Access menu token = access menu token
Encapsulate variables required for wechat interface
public class Constants {
    /**
     * TODO Fill in your own 'appID' and 'appsecret'`
     */
    public static final String APP_ID = "xxx";
    public static final String APP_SECRET = "xxx";

    /**
     * GET 'access' token through' GET request method '`
     */
    public static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    /**
     * TODO Only for temporary test
     */
    public static final String ACCESS_TOKEN = "xxx";

    /**
     * Query menu interface - GET request
     */
    public static final String GET_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";
    /**
     * Delete menu interface - GET request (note that when calling this interface, the default menu and all personalized menus will be deleted)
     */
    public static final String DELETE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";
    /**
     * Create menu interface - POST request
     */
    public static final String CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

}

4, Get access_token according to AppID and AppSecret

Access_token is the global only interface calling credential for public numbers. When calling the public interfaces (the following create menu, query menu, delete menu, etc.), you need to use access_token!

Here, you can view the wechat document to obtain the access [token] method

① Encapsulate the response result AccessTokenVO
@Data
@ApiModel(description = "access_token: Global unique interface call credentials for public numbers")
public class AccessTokenVO {

    @ApiModelProperty(value = "Acquired credentials")
    private String access_token;

    @ApiModelProperty(value = "Effective time of voucher, unit: Second(Wechat is temporarily 7200 seconds, i.e. 2 hours. It needs to be acquired again after expiration)")
    private int expires_in;

}
② Service class
public interface IWeixinService {

    /**
     * Get access_token according to AppID and AppSecret
     *
     * @param appId:
     * @param appSecret:
     * @return: com.zhengqing.demo.modules.weixin.model.AccessTokenVO
     */
    AccessTokenVO getAccessToken(String appId, String appSecret);

}
③ Service implementation class
@Slf4j
@Service
public class WeixinServiceImpl implements IWeixinService {

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public AccessTokenVO getAccessToken(String appId, String appSecret) {
        AccessTokenVO accessTokenVO = restTemplate.getForObject(Constants.GET_ACCESS_TOKEN_URL.replace("APPID", appId).replace("APPSECRET", appSecret), AccessTokenVO.class);
        return accessTokenVO;
    }

}

5, Custom menu processing

click and view request examples

{
     "button":[
     {	
          "type":"click",
          "name":"Today's songs",
          "key":"V1001_TODAY_MUSIC"
      },
      {
           "name":"menu",
           "sub_button":[
           {	
               "type":"view",
               "name":"search",
               "url":"http://www.soso.com/"
            },
            {
                 "type":"miniprogram",
                 "name":"wxa",
                 "url":"http://mp.weixin.qq.com",
                 "appid":"wx286b93c14bbf93aa",
                 "pagepath":"pages/lunar/index"
             },
            {
               "type":"click",
               "name":"Like us",
               "key":"V1001_GOOD"
            }]
       }]
 }

1, Encapsulate menu data

Warm tip: it's recommended to look at the data given in wechat documents when encapsulating the data here. Otherwise, you may be confused when you finally assemble the menu tree data to create a menu~

① Menu type enumeration class
public enum MenuType {
    // Click menu
    CLICK("click"),
    // Linked menu
    VIEW("view");
}
② Menu - base class
@Data
@ApiModel(description = "menu - Base class")
public class Button {

    @ApiModelProperty(value = "Menu title, no more than 16 bytes, submenu no more than 60 bytes")
    private String name;

}
③ Click menu
@Data
@ApiModel(description = "Users can click the menu to receive message push")
public class ClickButton extends Button {

    @ApiModelProperty(value = "The response action type of the menu, view Represents the page type, click Indicates the type of click, miniprogram Represents the applet type")
    private String type = MenuType.CLICK.getType();

    @ApiModelProperty(value = "menu KEY Value, for message interface push, no more than 128 bytes")
    private String key;

}
④ Linked menu
@Data
@ApiModel(description = "Users can click the menu to open the link")
public class ViewButton extends Button {

    @ApiModelProperty(value = "The response action type of the menu, view Represents the page type, click Indicates the type of click, miniprogram Represents the applet type")
    private String type = MenuType.VIEW.getType();

    @ApiModelProperty(value = "(view,miniprogram Type must) Web link, users can click the menu to open the link, no more than 1024 bytes. type by miniprogram The old version of the client that does not support applets will open this url")
    private String url;

}
⑤ Primary menu with secondary menu
@Data
@ApiModel(description = "Primary menu with secondary menu")
public class ComplexButton extends Button {

    @ApiModelProperty(value = "Array of secondary menus, the number should be 1~5 individual")
    private Button[] sub_button;

}
⑥ Outermost menu tree
@Data
@ApiModel(description = "Menu tree")
public class Menu {

    @ApiModelProperty(value = "First level menu array, the number should be 1~3 individual")
    private Button[] button;

}

2. Service class

public interface IMenuService {

    /**
     * Query menu
     *
     * @param accessToken:Access credentials
     * @return: java.lang.Object
     */
    Object getMenu(String accessToken);

    /**
     * Delete menu
     *
     * @param accessToken:Access credentials
     * @return: com.zhengqing.demo.modules.weixin.model.WeixinResponseResult
     */
    WeixinResponseResult deleteMenu(String accessToken);

    /**
     * create menu
     *
     * @param menu        : Menu data created
     * @param accessToken : Access credentials
     * @return: com.zhengqing.demo.modules.weixin.model.WeixinResponseResult
     */
    WeixinResponseResult createMenu(Menu menu, String accessToken);

}

3. Service implementation class

@Slf4j
@Service
public class MenuServiceImpl implements IMenuService {

    @Autowired
    private RestTemplate restTemplate;


    @Override
    public Object getMenu(String accessToken) {
        Object menu = restTemplate.getForObject(Constants.GET_MENU_URL.replace("ACCESS_TOKEN", accessToken), Object.class);
        return menu;
    }

    @Override
    public WeixinResponseResult deleteMenu(String accessToken) {
        WeixinResponseResult result = restTemplate.getForObject(Constants.DELETE_MENU_URL.replace("ACCESS_TOKEN", accessToken), WeixinResponseResult.class);
        return result;
    }

    @Override
    public WeixinResponseResult createMenu(Menu menu, String accessToken) {
        // Convert menu objects to json strings
        String jsonMenu = JSON.toJSONString(menu);
        WeixinResponseResult result = restTemplate.postForObject(Constants.CREATE_MENU_URL.replace("ACCESS_TOKEN", accessToken), jsonMenu, WeixinResponseResult.class);
        return result;
    }

}

Six, test

1. Get access_token
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class WeixinTest {

    @Autowired
    private IWeixinService weixinService;

    @Test // Get ` access'token`
    public void getAccessToken() throws Exception {
        AccessTokenVO accessTokenVO = weixinService.getAccessToken(Constants.APP_ID, Constants.APP_SECRET);
        log.info("======================================== \n" + accessTokenVO.getAccess_token());
    }

}
2. Create custom menu, query menu, delete menu

Note: here, the editor writes the access token obtained to constant.access token for testing. In the actual project, the access token can be saved to the cache, and the cache data can be refreshed every 2 hours~

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class MenuTest {

    @Autowired
    private IMenuService menuService;

    @Test // Query menu
    public void getMenu() {
        Object menu = menuService.getMenu(Constants.ACCESS_TOKEN);
        log.info("======================================== \n" + JSON.toJSONString(menu));
    }

    @Test // Delete menu
    public void deleteMenu() {
        WeixinResponseResult result = menuService.deleteMenu(Constants.ACCESS_TOKEN);
        log.info("======================================== \n" + result);
    }

    @Test // create menu
    public void createMenu() {
        WeixinResponseResult result = menuService.createMenu(createMenuTree(), Constants.ACCESS_TOKEN);
        log.info("======================================== \n" + result);
    }

    /**
     * Menu data
     */
     private Menu createMenuTree() {
        // Linked menu
        ViewButton btn11 = new ViewButton();
        btn11.setName("CSDN");
        btn11.setUrl("https://zhengqing.blog.csdn.net/");

        ViewButton btn12 = new ViewButton();
        btn12.setName("Personal blog");
        btn12.setUrl("http://zhengqingya.gitee.io/blog/");

        // Click menu
        ClickButton mainBtn2 = new ClickButton();
        mainBtn2.setName("Point me.");
        mainBtn2.setKey("hello");

        ViewButton btn31 = new ViewButton();
        btn31.setName("Code cloud");
        btn31.setUrl("https://gitee.com/zhengqingya/projects");

        ViewButton btn32 = new ViewButton();
        btn32.setName("GitHub");
        btn32.setUrl("https://github.com/zhengqingya?tab=repositories");

        // Primary menu with secondary menu
        ComplexButton mainBtn1 = new ComplexButton();
        mainBtn1.setName("Blog");
        mainBtn1.setSub_button(new ViewButton[]{btn11, btn12});

        ComplexButton mainBtn3 = new ComplexButton();
        mainBtn3.setName("Warehouse");
        mainBtn3.setSub_button(new ViewButton[]{btn31, btn32});

        Menu menu = new Menu();
        menu.setButton(new Button[]{mainBtn1, mainBtn2, mainBtn3});

        return menu;
    }

}

Final customized menu

demo source code of this case

https://gitee.com/zhengqingya/java-workspace

Posted by big_c147 on Fri, 17 Jan 2020 05:22:26 -0800