CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-github-binarywang--weixin-java-mp

Comprehensive Java SDK for WeChat Official Account development with complete API coverage for user management, messaging, materials, menus, and WeChat platform features.

Pending
Overview
Eval results
Files

menu-management.mddocs/

Menu Management

Create, update, and delete custom menus for WeChat Official Accounts, providing interactive navigation for users.

Menu Service Interface

interface WxMpMenuService {
  // Menu operations
  String menuCreate(WxMenu menu) throws WxErrorException;
  void menuDelete() throws WxErrorException;
  WxMenu menuGet() throws WxErrorException;
  WxMpGetSelfMenuInfoResult getSelfMenuInfo() throws WxErrorException;
  
  // Conditional menu operations
  String menuTryMatch(String userId) throws WxErrorException;
  String conditionalMenuCreate(WxMenuConditional menu) throws WxErrorException;
  void conditionalMenuDelete(String menuid) throws WxErrorException;
}

Menu Data Models

Basic Menu Structure

class WxMenu implements Serializable {
  private List<WxMenuButton> buttons;
  private WxMenuRule matchRule;
  
  public List<WxMenuButton> getButtons();
  public void setButtons(List<WxMenuButton> buttons);
  public WxMenuRule getMatchRule();
  public void setMatchRule(WxMenuRule matchRule);
}

class WxMenuButton implements Serializable {
  private String type;
  private String name;
  private String key;
  private String url;
  private String mediaId;
  private String appid;
  private String pagepath;
  private String articleId;
  private List<WxMenuButton> subButtons;
  
  public String getType();
  public void setType(String type);
  public String getName();
  public void setName(String name);
  public String getKey();
  public void setKey(String key);
  public String getUrl();
  public void setUrl(String url);
  public String getMediaId();
  public void setMediaId(String mediaId);
  public String getAppid();
  public void setAppid(String appid);
  public String getPagepath();
  public void setPagepath(String pagepath);
  public String getArticleId();
  public void setArticleId(String articleId);
  public List<WxMenuButton> getSubButtons();
  public void setSubButtons(List<WxMenuButton> subButtons);
}

Conditional Menu

class WxMenuConditional extends WxMenu {
  private String menuid;
  
  public String getMenuid();
  public void setMenuid(String menuid);
}

class WxMenuRule implements Serializable {
  private String tagId;
  private String sex;
  private String country;
  private String province;
  private String city;
  private String clientPlatformType;
  private String language;
  
  public String getTagId();
  public void setTagId(String tagId);
  public String getSex();
  public void setSex(String sex);
  public String getCountry();
  public void setCountry(String country);
  public String getProvince();
  public void setProvince(String province);
  public String getCity();
  public void setCity(String city);
  public String getClientPlatformType();
  public void setClientPlatformType(String clientPlatformType);
  public String getLanguage();
  public void setLanguage(String language);
}

Menu Information Result

class WxMpGetSelfMenuInfoResult implements Serializable {
  private Boolean isMenuOpen;
  private List<WxMpSelfMenuInfo> selfMenuInfo;
  
  public Boolean getIsMenuOpen();
  public void setIsMenuOpen(Boolean isMenuOpen);
  public List<WxMpSelfMenuInfo> getSelfMenuInfo();
  public void setSelfMenuInfo(List<WxMpSelfMenuInfo> selfMenuInfo);
  
  public static class WxMpSelfMenuInfo implements Serializable {
    private String type;
    private String name;
    private String value;
    private WxMpSelfMenuInfo newsInfo;
    private List<WxMpSelfMenuInfo> subButton;
    
    public String getType();
    public void setType(String type);
    public String getName();
    public void setName(String name);
    public String getValue();
    public void setValue(String value);
    public WxMpSelfMenuInfo getNewsInfo();
    public void setNewsInfo(WxMpSelfMenuInfo newsInfo);
    public List<WxMpSelfMenuInfo> getSubButton();
    public void setSubButton(List<WxMpSelfMenuInfo> subButton);
  }
}

Menu Button Types

// Menu button type constants
public static final String BUTTON_TYPE_CLICK = "click";
public static final String BUTTON_TYPE_VIEW = "view";
public static final String BUTTON_TYPE_SCANCODE_PUSH = "scancode_push";
public static final String BUTTON_TYPE_SCANCODE_WAITMSG = "scancode_waitmsg";
public static final String BUTTON_TYPE_PIC_SYSPHOTO = "pic_sysphoto";
public static final String BUTTON_TYPE_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album";
public static final String BUTTON_TYPE_PIC_WEIXIN = "pic_weixin";
public static final String BUTTON_TYPE_LOCATION_SELECT = "location_select";
public static final String BUTTON_TYPE_MEDIA_ID = "media_id";
public static final String BUTTON_TYPE_VIEW_LIMITED = "view_limited";
public static final String BUTTON_TYPE_MINIPROGRAM = "miniprogram";
public static final String BUTTON_TYPE_ARTICLE_ID = "article_id";
public static final String BUTTON_TYPE_ARTICLE_VIEW_LIMITED = "article_view_limited";

Usage Examples

Create Basic Menu

import me.chanjar.weixin.mp.bean.menu.WxMenu;
import me.chanjar.weixin.mp.bean.menu.WxMenuButton;

// Create menu
WxMenu menu = new WxMenu();
List<WxMenuButton> buttons = new ArrayList<>();

// First level button - Click type
WxMenuButton button1 = new WxMenuButton();
button1.setType(WxConsts.MenuButtonType.CLICK);
button1.setName("About Us");
button1.setKey("ABOUT_US");
buttons.add(button1);

// First level button - View type (URL)
WxMenuButton button2 = new WxMenuButton();
button2.setType(WxConsts.MenuButtonType.VIEW);
button2.setName("Website");
button2.setUrl("https://www.example.com");
buttons.add(button2);

// First level button with sub-buttons
WxMenuButton button3 = new WxMenuButton();
button3.setName("Services");

List<WxMenuButton> subButtons = new ArrayList<>();

// Sub-button 1
WxMenuButton subButton1 = new WxMenuButton();
subButton1.setType(WxConsts.MenuButtonType.CLICK);
subButton1.setName("Service A");
subButton1.setKey("SERVICE_A");
subButtons.add(subButton1);

// Sub-button 2
WxMenuButton subButton2 = new WxMenuButton();
subButton2.setType(WxConsts.MenuButtonType.VIEW);
subButton2.setName("Service B");
subButton2.setUrl("https://www.example.com/service-b");
subButtons.add(subButton2);

button3.setSubButtons(subButtons);
buttons.add(button3);

menu.setButtons(buttons);

// Create menu
String result = wxService.getMenuService().menuCreate(menu);
System.out.println("Menu created: " + result);

Create Advanced Menu with Special Button Types

WxMenu advancedMenu = new WxMenu();
List<WxMenuButton> buttons = new ArrayList<>();

// Scan QR code button
WxMenuButton scanButton = new WxMenuButton();
scanButton.setType(WxConsts.MenuButtonType.SCANCODE_PUSH);
scanButton.setName("Scan QR");
scanButton.setKey("SCAN_QR");
buttons.add(scanButton);

// Photo button
WxMenuButton photoButton = new WxMenuButton();
photoButton.setType(WxConsts.MenuButtonType.PIC_PHOTO_OR_ALBUM);
photoButton.setName("Upload Photo");
photoButton.setKey("UPLOAD_PHOTO");
buttons.add(photoButton);

// Location button
WxMenuButton locationButton = new WxMenuButton();
locationButton.setType(WxConsts.MenuButtonType.LOCATION_SELECT);
locationButton.setName("Send Location");
locationButton.setKey("SEND_LOCATION");
buttons.add(locationButton);

advancedMenu.setButtons(buttons);
wxService.getMenuService().menuCreate(advancedMenu);

Create Menu with Mini Program Button

WxMenu miniProgramMenu = new WxMenu();
List<WxMenuButton> buttons = new ArrayList<>();

// Mini program button
WxMenuButton miniProgramButton = new WxMenuButton();
miniProgramButton.setType(WxConsts.MenuButtonType.MINIPROGRAM);
miniProgramButton.setName("Mini Program");
miniProgramButton.setUrl("https://fallback.url.com"); // Fallback URL for older versions
miniProgramButton.setAppid("your-miniprogram-appid");
miniProgramButton.setPagepath("pages/index/index");
buttons.add(miniProgramButton);

miniProgramMenu.setButtons(buttons);
wxService.getMenuService().menuCreate(miniProgramMenu);

Create Menu with Media Button

// Upload media first (image/voice)
File mediaFile = new File("path/to/media.jpg");
WxMpMaterialUploadResult uploadResult = wxService.getMaterialService()
    .materialFileUpload(WxConsts.MediaFileType.IMAGE, mediaFile);

// Create menu with media button
WxMenu mediaMenu = new WxMenu();
List<WxMenuButton> buttons = new ArrayList<>();

WxMenuButton mediaButton = new WxMenuButton();
mediaButton.setType(WxConsts.MenuButtonType.MEDIA_ID);
mediaButton.setName("View Image");
mediaButton.setMediaId(uploadResult.getMediaId());
buttons.add(mediaButton);

mediaMenu.setButtons(buttons);
wxService.getMenuService().menuCreate(mediaMenu);

Create Conditional Menu

// Create conditional menu for specific user groups
WxMenuConditional conditionalMenu = new WxMenuConditional();

// Set menu rule (conditions)
WxMenuRule rule = new WxMenuRule();
rule.setTagId("100"); // For users with tag ID 100
rule.setSex("1"); // For male users (1=male, 2=female)
rule.setCountry("China");
rule.setProvince("Beijing");
conditionalMenu.setMatchRule(rule);

// Set menu buttons
List<WxMenuButton> buttons = new ArrayList<>();
WxMenuButton vipButton = new WxMenuButton();
vipButton.setType(WxConsts.MenuButtonType.CLICK);
vipButton.setName("VIP Services");
vipButton.setKey("VIP_SERVICES");
buttons.add(vipButton);

conditionalMenu.setButtons(buttons);

// Create conditional menu
String menuid = wxService.getMenuService().conditionalMenuCreate(conditionalMenu);
System.out.println("Conditional menu created with ID: " + menuid);

Get Current Menu

// Get current menu configuration
WxMenu currentMenu = wxService.getMenuService().menuGet();

if (currentMenu != null && currentMenu.getButtons() != null) {
    for (WxMenuButton button : currentMenu.getButtons()) {
        System.out.println("Button: " + button.getName() + " - Type: " + button.getType());
        
        if (button.getSubButtons() != null) {
            for (WxMenuButton subButton : button.getSubButtons()) {
                System.out.println("  Sub-button: " + subButton.getName() + 
                                 " - Type: " + subButton.getType());
            }
        }
    }
}

Get Self Menu Information

// Get detailed menu information including conditionally displayed menus
WxMpGetSelfMenuInfoResult selfMenuInfo = wxService.getMenuService().getSelfMenuInfo();

System.out.println("Menu open: " + selfMenuInfo.getIsMenuOpen());

if (selfMenuInfo.getSelfMenuInfo() != null) {
    for (WxMpGetSelfMenuInfoResult.WxMpSelfMenuInfo menuInfo : selfMenuInfo.getSelfMenuInfo()) {
        System.out.println("Menu: " + menuInfo.getName() + " - Type: " + menuInfo.getType());
        
        if (menuInfo.getSubButton() != null) {
            for (WxMpGetSelfMenuInfoResult.WxMpSelfMenuInfo subMenu : menuInfo.getSubButton()) {
                System.out.println("  Sub-menu: " + subMenu.getName() + 
                                 " - Type: " + subMenu.getType());
            }
        }
    }
}

Delete Menu

// Delete current menu
wxService.getMenuService().menuDelete();
System.out.println("Menu deleted successfully");

// Delete conditional menu
wxService.getMenuService().conditionalMenuDelete("menuid");

Test Menu Matching

// Test which menu a specific user would see
String userId = "user_openid";
String menuResult = wxService.getMenuService().menuTryMatch(userId);
System.out.println("User would see menu: " + menuResult);

Handle Menu Click Events

// In your message handler
public class MenuClickHandler implements WxMpMessageHandler {
    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                   Map<String, Object> context,
                                   WxMpService wxMpService,
                                   WxSessionManager sessionManager) throws WxErrorException {
        
        String eventKey = wxMessage.getEventKey();
        
        switch (eventKey) {
            case "ABOUT_US":
                return TextBuilder.build("About our company...", wxMessage);
            
            case "SERVICE_A":
                return buildServiceAResponse(wxMessage);
            
            case "VIP_SERVICES":
                return buildVipResponse(wxMessage);
            
            case "SCAN_QR":
                return TextBuilder.build("Please scan the QR code", wxMessage);
            
            case "UPLOAD_PHOTO":
                return TextBuilder.build("Please upload your photo", wxMessage);
            
            case "SEND_LOCATION":
                return TextBuilder.build("Please share your location", wxMessage);
            
            default:
                return TextBuilder.build("Menu option not implemented", wxMessage);
        }
    }
    
    private WxMpXmlOutMessage buildServiceAResponse(WxMpXmlMessage wxMessage) {
        // Build rich response for Service A
        List<WxMpXmlOutNewsMessage.Item> articles = new ArrayList<>();
        
        WxMpXmlOutNewsMessage.Item item = new WxMpXmlOutNewsMessage.Item();
        item.setTitle("Service A Details");
        item.setDescription("Complete information about Service A");
        item.setUrl("https://www.example.com/service-a");
        item.setPicUrl("https://www.example.com/service-a-image.jpg");
        articles.add(item);
        
        return NewsBuilder.build(articles, wxMessage);
    }
}

// Register menu handler in router
router.rule()
    .msgType(WxConsts.XmlMsgType.EVENT)
    .event(WxConsts.EventType.CLICK)
    .handler(new MenuClickHandler())
    .end();

Complex Menu Structure

public WxMenu createComplexMenu() {
    WxMenu menu = new WxMenu();
    List<WxMenuButton> buttons = new ArrayList<>();
    
    // Products menu with sub-buttons
    WxMenuButton productsButton = new WxMenuButton();
    productsButton.setName("Products");
    
    List<WxMenuButton> productSubButtons = new ArrayList<>();
    
    // Product category 1
    WxMenuButton product1 = new WxMenuButton();
    product1.setType(WxConsts.MenuButtonType.VIEW);
    product1.setName("Category A");
    product1.setUrl("https://www.example.com/category-a");
    productSubButtons.add(product1);
    
    // Product category 2
    WxMenuButton product2 = new WxMenuButton();
    product2.setType(WxConsts.MenuButtonType.CLICK);
    product2.setName("Category B");
    product2.setKey("CATEGORY_B");
    productSubButtons.add(product2);
    
    // Product catalog
    WxMenuButton catalog = new WxMenuButton();
    catalog.setType(WxConsts.MenuButtonType.MEDIA_ID);
    catalog.setName("Catalog");
    catalog.setMediaId("catalog_media_id");
    productSubButtons.add(catalog);
    
    productsButton.setSubButtons(productSubButtons);
    buttons.add(productsButton);
    
    // Services menu
    WxMenuButton servicesButton = new WxMenuButton();
    servicesButton.setName("Services");
    
    List<WxMenuButton> serviceSubButtons = new ArrayList<>();
    
    // Customer service
    WxMenuButton customerService = new WxMenuButton();
    customerService.setType(WxConsts.MenuButtonType.CLICK);
    customerService.setName("Customer Service");
    customerService.setKey("CUSTOMER_SERVICE");
    serviceSubButtons.add(customerService);
    
    // Technical support
    WxMenuButton techSupport = new WxMenuButton();
    techSupport.setType(WxConsts.MenuButtonType.VIEW);
    techSupport.setName("Tech Support");
    techSupport.setUrl("https://support.example.com");
    serviceSubButtons.add(techSupport);
    
    // FAQ
    WxMenuButton faq = new WxMenuButton();
    faq.setType(WxConsts.MenuButtonType.ARTICLE_VIEW_LIMITED);
    faq.setName("FAQ");
    faq.setArticleId("faq_article_id");
    serviceSubButtons.add(faq);
    
    servicesButton.setSubButtons(serviceSubButtons);
    buttons.add(servicesButton);
    
    // Contact menu
    WxMenuButton contactButton = new WxMenuButton();
    contactButton.setName("Contact");
    
    List<WxMenuButton> contactSubButtons = new ArrayList<>();
    
    // Phone
    WxMenuButton phone = new WxMenuButton();
    phone.setType(WxConsts.MenuButtonType.CLICK);
    phone.setName("Phone");
    phone.setKey("CONTACT_PHONE");
    contactSubButtons.add(phone);
    
    // Address
    WxMenuButton address = new WxMenuButton();
    address.setType(WxConsts.MenuButtonType.LOCATION_SELECT);
    address.setName("Address");
    address.setKey("CONTACT_ADDRESS");
    contactSubButtons.add(address);
    
    // Mini Program
    WxMenuButton miniProgram = new WxMenuButton();
    miniProgram.setType(WxConsts.MenuButtonType.MINIPROGRAM);
    miniProgram.setName("Mini Program");
    miniProgram.setUrl("https://www.example.com");
    miniProgram.setAppid("miniprogram_appid");
    miniProgram.setPagepath("pages/contact/contact");
    contactSubButtons.add(miniProgram);
    
    contactButton.setSubButtons(contactSubButtons);
    buttons.add(contactButton);
    
    menu.setButtons(buttons);
    return menu;
}

Menu Limitations

  • Maximum 3 first-level buttons
  • Maximum 5 sub-buttons per first-level button
  • Button names: 1-16 characters for first-level, 1-60 characters for sub-buttons
  • Click event keys: 1-128 characters
  • URLs: Must be valid HTTP/HTTPS URLs

Best Practices

  1. Clear Naming: Use descriptive, concise button names
  2. Logical Grouping: Group related functions under the same parent button
  3. Event Keys: Use meaningful, consistent naming conventions for event keys
  4. Fallback URLs: Always provide fallback URLs for mini program buttons
  5. Testing: Test menus with different user segments for conditional menus
  6. Regular Updates: Keep menu content fresh and relevant
  7. Analytics: Track menu usage to optimize structure

Error Handling

try {
    wxService.getMenuService().menuCreate(menu);
} catch (WxErrorException e) {
    int errorCode = e.getError().getErrorCode();
    
    switch (errorCode) {
        case 40018:
            System.err.println("Invalid button name length");
            break;
        case 40019:
            System.err.println("Invalid button key length");
            break;
        case 40020:
            System.err.println("Invalid button URL");
            break;
        case 40023:
            System.err.println("Invalid sub-menu level");
            break;
        case 40024:
            System.err.println("Too many sub-menu buttons");
            break;
        case 40025:
            System.err.println("Too many main menu buttons");
            break;
        default:
            System.err.println("Menu creation failed: " + e.getError().getErrorMsg());
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-github-binarywang--weixin-java-mp

docs

advanced-services.md

index.md

material-management.md

menu-management.md

message-handling.md

service-management.md

shopping-guide.md

template-messaging.md

user-management.md

tile.json