{"id":36420095,"url":"https://github.com/chensheng/wechatty-project","last_synced_at":"2026-01-11T17:05:46.744Z","repository":{"id":41534461,"uuid":"89065292","full_name":"chensheng/wechatty-project","owner":"chensheng","description":"Wechattty Project是一个基于JAVA的微信公众号（包括服务号和订阅号）和微信企业号的开发SDK，封装良好的API让开发者可以专注于业务逻辑的开发，提高开发效率。","archived":false,"fork":false,"pushed_at":"2025-06-27T16:12:52.000Z","size":394,"stargazers_count":182,"open_issues_count":8,"forks_count":28,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-07-10T02:41:37.093Z","etag":null,"topics":["java","wechat","wechat-sdk"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chensheng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-04-22T11:37:54.000Z","updated_at":"2025-07-02T06:58:30.000Z","dependencies_parsed_at":"2023-02-01T01:45:52.089Z","dependency_job_id":null,"html_url":"https://github.com/chensheng/wechatty-project","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/chensheng/wechatty-project","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chensheng%2Fwechatty-project","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chensheng%2Fwechatty-project/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chensheng%2Fwechatty-project/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chensheng%2Fwechatty-project/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chensheng","download_url":"https://codeload.github.com/chensheng/wechatty-project/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chensheng%2Fwechatty-project/sbom","scorecard":{"id":276495,"data":{"date":"2025-08-11","repo":{"name":"github.com/chensheng/wechatty-project","commit":"2e07a086b69df44df110307e6817611118b9bd10"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"102 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-h46c-h94j-95f3","Warn: Project is vulnerable to: GHSA-wf8f-6423-gfxg","Warn: Project is vulnerable to: GHSA-27xj-rqx5-2255","Warn: Project is vulnerable to: GHSA-288c-cq4h-88gq","Warn: Project is vulnerable to: GHSA-4w82-r329-3q67","Warn: Project is vulnerable to: GHSA-57j2-w4cx-62h2","Warn: Project is vulnerable to: GHSA-58pp-9c76-5625","Warn: Project is vulnerable to: GHSA-5949-rw7g-wx7w","Warn: Project is vulnerable to: GHSA-5p34-5m6p-p58g","Warn: Project is vulnerable to: GHSA-5r5r-6hpj-8gg9","Warn: Project is vulnerable to: GHSA-6fpp-rgj9-8rwc","Warn: Project is vulnerable to: GHSA-758m-v56v-grj4","Warn: Project is vulnerable to: GHSA-85cw-hj65-qqv9","Warn: Project is vulnerable to: GHSA-89qr-369f-5m5x","Warn: Project is vulnerable to: GHSA-8c4j-34r4-xr8g","Warn: Project is vulnerable to: GHSA-8w26-6f25-cm9x","Warn: Project is vulnerable to: GHSA-95cm-88f5-f2c7","Warn: Project is vulnerable to: GHSA-9gph-22xh-8x98","Warn: Project is vulnerable to: GHSA-9m6f-7xcq-8vf8","Warn: Project is vulnerable to: GHSA-9vvp-fxw6-jcxr","Warn: Project is vulnerable to: GHSA-c265-37vj-cwcc","Warn: Project is vulnerable to: GHSA-c2q3-4qrh-fm48","Warn: Project is vulnerable to: GHSA-cf6r-3wgc-h863","Warn: Project is vulnerable to: GHSA-cmfg-87vq-g5g4","Warn: Project is vulnerable to: GHSA-cvm9-fjm9-3572","Warn: Project is vulnerable to: GHSA-f3j5-rmmp-3fc5","Warn: Project is vulnerable to: GHSA-f9xh-2qgp-cq57","Warn: Project is vulnerable to: GHSA-fmmc-742q-jg75","Warn: Project is vulnerable to: GHSA-fqwf-pjwf-7vqv","Warn: Project is vulnerable to: GHSA-gjmw-vf9h-g25v","Warn: Project is vulnerable to: GHSA-gwp4-hfv6-p7hw","Warn: Project is vulnerable to: GHSA-gww7-p5w4-wrfv","Warn: Project is vulnerable to: GHSA-h3cw-g4mq-c5x2","Warn: Project is vulnerable to: GHSA-h4rc-386g-6m85","Warn: Project is vulnerable to: GHSA-h822-r4r5-v8jg","Warn: Project is vulnerable to: GHSA-j823-4qch-3rgm","Warn: Project is vulnerable to: GHSA-jjjh-jjxp-wpff","Warn: Project is vulnerable to: GHSA-m6x4-97wx-4q27","Warn: Project is vulnerable to: GHSA-mc6h-4qgp-37qh","Warn: Project is vulnerable to: GHSA-mph4-vhrx-mv67","Warn: Project is vulnerable to: GHSA-mx7p-6679-8g3q","Warn: Project is vulnerable to: GHSA-p43x-xfjf-5jhr","Warn: Project is vulnerable to: GHSA-q93h-jc49-78gg","Warn: Project is vulnerable to: GHSA-qjw2-hr98-qgfh","Warn: Project is vulnerable to: GHSA-qmqc-x3r4-6v39","Warn: Project is vulnerable to: GHSA-r3gr-cxrf-hg25","Warn: Project is vulnerable to: GHSA-r695-7vr9-jgc2","Warn: Project is vulnerable to: GHSA-rf6r-2c4q-2vwg","Warn: Project is vulnerable to: GHSA-rgv9-q543-rqg4","Warn: Project is vulnerable to: GHSA-rpr3-cw39-3pxh","Warn: Project is vulnerable to: GHSA-v3xw-c963-f5hc","Warn: Project is vulnerable to: GHSA-v585-23hc-c647","Warn: Project is vulnerable to: GHSA-vfqx-33qm-g869","Warn: Project is vulnerable to: GHSA-wh8g-3j2c-rqj5","Warn: Project is vulnerable to: GHSA-2p3x-qw9c-25hh","Warn: Project is vulnerable to: GHSA-2q8x-2p7f-574v","Warn: Project is vulnerable to: GHSA-3ccq-5vw3-2p6x","Warn: Project is vulnerable to: GHSA-43gc-mjxg-gvrq","Warn: Project is vulnerable to: GHSA-4cch-wxpw-8p28","Warn: Project is vulnerable to: GHSA-4hrm-m67v-5cxr","Warn: Project is vulnerable to: GHSA-56p8-3fh9-4cvq","Warn: Project is vulnerable to: GHSA-59jw-jqf4-3wq3","Warn: Project is vulnerable to: GHSA-64xx-cq4q-mf44","Warn: Project is vulnerable to: GHSA-6w62-hx7r-mw68","Warn: Project is vulnerable to: GHSA-6wf9-jmg9-vxcc","Warn: Project is vulnerable to: GHSA-74cv-f58x-f9wf","Warn: Project is vulnerable to: GHSA-7chv-rrw6-w6fc","Warn: Project is vulnerable to: GHSA-7hwc-46rm-65jh","Warn: Project is vulnerable to: GHSA-8jrj-525p-826v","Warn: Project is vulnerable to: GHSA-cxfm-5m4g-x7xp","Warn: Project is vulnerable to: GHSA-f6hm-88x3-mfjv","Warn: Project is vulnerable to: GHSA-f8cc-g7j8-xxpm","Warn: Project is vulnerable to: GHSA-g5w6-mrj7-75h2","Warn: Project is vulnerable to: GHSA-h7v4-7xg3-hxcc","Warn: Project is vulnerable to: GHSA-hf23-9pf7-388p","Warn: Project is vulnerable to: GHSA-hfq9-hggm-c56q","Warn: Project is vulnerable to: GHSA-hph2-m3g5-xxv4","Warn: Project is vulnerable to: GHSA-hrcp-8f3q-4w2c","Warn: Project is vulnerable to: GHSA-hvv8-336g-rx3m","Warn: Project is vulnerable to: GHSA-hwpc-8xqv-jvj4","Warn: Project is vulnerable to: GHSA-j563-grx4-pjpv","Warn: Project is vulnerable to: GHSA-j9h8-phrw-h4fh","Warn: Project is vulnerable to: GHSA-jfvx-7wrx-43fh","Warn: Project is vulnerable to: GHSA-mw36-7c6c-q4q2","Warn: Project is vulnerable to: GHSA-p8pq-r894-fm8f","Warn: Project is vulnerable to: GHSA-qpfq-ph7r-qv6f","Warn: Project is vulnerable to: GHSA-qrx8-8545-4wg2","Warn: Project is vulnerable to: GHSA-rgh3-987h-wpmw","Warn: Project is vulnerable to: GHSA-rmr5-cpv2-vgjf","Warn: Project is vulnerable to: GHSA-xw4p-crpj-vjx2","Warn: Project is vulnerable to: GHSA-2qrg-x229-3v8q","Warn: Project is vulnerable to: GHSA-65fg-84f6-3jq3","Warn: Project is vulnerable to: GHSA-f7vh-qwp3-x37m","Warn: Project is vulnerable to: GHSA-fp5r-v3w9-4333","Warn: Project is vulnerable to: GHSA-w9p3-5cr8-m3jj","Warn: Project is vulnerable to: GHSA-7r82-7xv7-xcpj","Warn: Project is vulnerable to: GHSA-6xx3-rg99-gc3p","Warn: Project is vulnerable to: GHSA-72m5-fvvv-55m6","Warn: Project is vulnerable to: GHSA-8xfc-gm6g-vgpv","Warn: Project is vulnerable to: GHSA-hr8g-6v94-x4m9","Warn: Project is vulnerable to: GHSA-v435-xc8x-wvr9","Warn: Project is vulnerable to: GHSA-wjxj-5m7g-mg7q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-17T14:33:09.532Z","repository_id":41534461,"created_at":"2025-08-17T14:33:09.532Z","updated_at":"2025-08-17T14:33:09.532Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28314264,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-11T14:58:17.114Z","status":"ssl_error","status_checked_at":"2026-01-11T14:55:53.580Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","wechat","wechat-sdk"],"created_at":"2026-01-11T17:05:46.677Z","updated_at":"2026-01-11T17:05:46.737Z","avatar_url":"https://github.com/chensheng.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Wechatty Project\n\nWechattty Project是一个基于JAVA的微信公众号（包括服务号和订阅号）和微信企业号的开发框架，封装良好的API让开发者可以专注于业务逻辑的开发，提高开发效率。\n\n## 简单使用教程\n\n* [引入依赖](#引入依赖)\n* [初始化](#初始化)\n* [配置](#配置)\n* [接收消息](#接收消息)\n* [发送消息](#发送消息)\n* [素材管理](#素材管理)\n* [帐号管理](#帐号管理)\n* [微信授权](#微信授权)\n* [微信支付](#微信支付)\n\n### 引入依赖\n\n这里使用maven来引入依赖。\n```\n\u003cdependency\u003e\n  \u003cgroupId\u003espace.chensheng.wechatty\u003c/groupId\u003e\n  \u003cartifactId\u003ewechatty-mp\u003c/artifactId\u003e\n  \u003cversion\u003e2.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n\n```\n\n### 初始化\n\n`MpAppContext`是公众号API的统一调用入口，使用`WechatMpBootstrap`对其进行初始化。\n```\nWechatMpBootstrap bootstrap = new WechatMpBootstrap();\nbootstrap.addMsgListener(new TextMessageListener());\nMpAppContext mpAppContext = bootstrap.build();\n```\n如果项目使用spring来管理，可实现一个`FactoryBean`来初始化`MpAppContext`，以便后续引用。\n```\n@Component\npublic class MpAppContextFactoryBean implements FactoryBean\u003cMpAppContext\u003e {\n\n\t@Override\n\tpublic MpAppContext getObject() throws Exception {\n\t    WechatMpBootstrap bootstrap = new WechatMpBootstrap();\n\t    bootstrap.addMsgListener(new TextMessageListener());\n\t    return bootstrap.build();\n\t}\n\n\t@Override\n\tpublic Class\u003c?\u003e getObjectType() {\n\t    return MpAppContext.class;\n\t}\n\n\t@Override\n\tpublic boolean isSingleton() {\n\t    return true;\n\t}\n}\n```\n\n### 配置\n\n配置方式有两种，一种是`配置文件`，另一种是 `JAVA代码配置`。其中`JAVA代码配置`的优先级高于`配置文件`。\n\n###### 配置文件\n新建配置文件wechat-mp.properties, 将该文件放在项目类路径下。比如maven项目，可将该文件放在`src/main/resources`目录下。一般的配置如下:\n```\ntoken=thisIsToken\naesKey=thisIsAesKey\nappId=thisIsYourAppId\nappSecret=thisIsAppSecret\n```\n\n###### JAVA代码配置\n在`MpAppConetxt`初始化时，调用`WechatMpBootstrap`的`customizeWechatContext`方法来进行配置。\n```\nWechatMpBootstrap bootstrap = new WechatMpBootstrap();\nbootstrap.customizeWechatContext(new MpWechatContextCustomizer() {\n    @Override\n    public void customize(MpWechatContext wechatContext) {\n\twechatContext.setToken(\"thisIsToken\");\n\twechatContext.setAesKey(\"thisIsAeskey\");\n\twechatContext.setAppId(\"thisIsAppId\");\n\twechatContext.setAppSecret(\"thisIsAppSecret\");\n    }\n});\n```\n\n###### 配置参数说明\n\n必填参数|说明\n-----|-----\ntoken|公众号的token，可在公众号后台查看.\naesKey|加密用的key， 可在公众号后台查看.\nappId|公众号appId，可在公众号后台查看。\nappSecret|公众号的appSecret，可在公众号后台查看。\n\n可选参数|说明\n-----|-----\nenableCryptedMode|是否开启回调加密模式，默认true。如果开启则要下载[JCE无限制权限策略文件](http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html),覆盖jdk中的相关文件，具体可查看[微信常见错误举例](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list\u0026t=resource/res_list\u0026verify=1\u0026id=open1419318482\u0026lang=zh_CN)。\nautoUpdateAccessToken|出现access_token相关错误时是否自动更新access_token，默认false，应用可自己通过定时任务来更新，后面将详细介绍。\naccessTokenStrategyClass|access_token存取策略，默认是space.chensheng.wechatty.common.http.MemoryAccessTokenStrategy，将access_token存在内存中，应用可实现自己的存取策略，比如存在数据库中，后面将详细介绍。\npayKey|微信支付key\npayCertFile|微信支付证书文件路径\npayCertPassword|微信支付证书密码\npayMchId|微信支付商户id\npayClientIp|调用支付的机器ip\npoolingHttpProxyEnable|是否通过代理服务器给微信服务器必请求，默认false\npoolingHttpProxyHostname|代理服务器的hostname，比如www.chensheng.space\npoolingHttpProxyPort|代理服务器端口\npoolingHttpProxyUsername|代理服务器用户名\npoolingHttpProxyPassword|代理服务器密码\npoolingHttpMaxPerRoute|http连接池每条链路最大并发连接数，默认为50\npoolingHttpMaxTotal|http连接池最大并发连接数，默认200\npoolingHttpSocketTimeoutMillis|socket超时毫秒数，默认10000\npoolingHttpConnectTimeoutMillis|连接到微信服务器超时毫秒数，默认10000\npoolingHttpConnectionRequestTimeoutMillis|从htttp连接池获取连接超时毫秒数，默认10000\npoolingHttpTcpNoDelay|是否开启tpcNoDelay,默认true\n\n###### access_token更新问题\n\n* 自动更新：如果开启了自动更新，则在因为access_token错误而导致请求微信接口失败的情况下，框架会自动更新access_token。\n* 定时更新：在应用中使用定时任务(比如quartz)来定时执行`mpAppContext.getAccessTokenFetcher().updateAccessToken()`，一般每1.5小时执行一次，因为access_token的过期时间为2小时。\n* 自动更新和定时更新可共存，如果多个线程并发执行更新access_token，只有一个线程会去请求微信服务器来更新access_token，其他线程会立即返回，不执行任何操作。\n\n###### access_token存取策略问题\n\n* Web应用单机部署：如果您的应用是单机部署，则可直接使用默认的策略，将access_token存储在内存中。\n* Web应用集群部署：如果您的应用是集群部署，则要实现自己的access_token存取策略，将access_token存放在集群共享的媒介（比如数据库）来达到access_token中控管理的目的。实现完自己的策略类后，要在wechat-mp.properties中添加配置`accessTokenStrategyClass=your.package.name.YourAccessTokenStrategy`。以下是一个accesss_token数据库存取的策略：\n```java\nimport space.chensheng.wechatty.common.http.AccessTokenStrategy;\n\n//因为这个策略类的实例化不是通过Spring来管理的，所以在这个类中不能使用Autowired来注入bean，\n//要通过ApplicationContext#getBean方法来获取。\npublic class DatabaseAccessTokenStrategy implements AccessTokenStrategy{\n\t\n    //将access_token存到数据库中去\n    @Override\n    public void doSave(String accessToken) {\n        TokenService tokenService = ApplicationContextUtil\n\t    .getApplicationContext().getBean(TokenService.class);\n\ttokenService.doSave(accessToken);\n    }\n    \n    //从数据库中取出access_token\n    @Override\n    public String doQuery() {\n        TokenService tokenService = ApplicationContextUtil\n\t    .getApplicationContext().getBean(TokenService.class);\n\treturn tokenService.doQuery();\n    }\n}\n```\n\n### 接收消息\n\n在`MpAppContext`初始化时，通过`WechatMpBootstrap`添加消息监听器来接收消息(关于message listener会在后面介绍):\n```\nWechatMpBootstrap bootstrap = new WechatMpBootstrap();\nbootstrap.addMsgListener(new TextMessageListener());\nbootstrap.addMsgListener(new SubscribeEventListener());\nbootstrap.addMsgListener(new UnsubscribeEventListener());\n```\n\n###### 验证微信服务器的开启回调请求\n\n如果你已经在微信公众号后台设置了回调URL，微信服务器会向这个URL发送一个GET请求来验证，开发者需要在Web应用中处理这个请求。以下是一个SpringMVC的验证例子：\n```\n@RestController\n@RequestMapping(value = \"/wechat-mp\")\npublic class CallbackController extends BaseController{\n\n    @Autowired\n    private MpAppContext mpAppContext;\n    \n    //验证请求，并回复字符串\n    @RequestMapping(value = \"/callback\", method = RequestMethod.GET)\n    public String verify(String msg_signature, String timestamp, String nonce, String echostr) {\n        String reply = mpAppContext.getCallbackModeVerifier().verify(msg_signature, timestamp, nonce, echostr);\n\treturn reply;\n    }\n    \n}\n```\n\n###### 消息回调请求处理\n\n验证完开启回调请求后，回调模式就真正开启了。如果用户发了个消息给公众号，微信服务器会向回调URL发送一个POST请求，将消息转发到这个URL上，开发者需要在Web应用中处理这个请求，以下是一个SpringMVC的例子（和前面验证开启回调的例子在一个controller中）：\n```\n@RestController\n@RequestMapping(value = \"/wechat-mp\")\npublic class CallbackController extends BaseController{\n\n    @Autowired\n    private MpAppContext mpAppContext;\n    \n    //接收回调消息，并回复相应xml消息\n    @RequestMapping(value = \"/callback\", method = RequestMethod.POST)\n    public String verify(String msg_signature, String timestamp, String nonce) {\n        //postBody是请求体内容，String格式，开发者可以通过HttpServletRequest来解析\n        String replyXml = mpAppContext.getMpMessageDispatcher().dispatch(msg_signature(), timestamp, nonce, postBody);\n\treturn replyXml;\n    }\n}\n```\n\n###### 回调消息的监听\n\n开发者可以通过继承`space.chensheng.wechatty.common.message.MessageListener`来监听特定类型的消息。以下是一个监听用户发送的文本消息的例子:\n\n```\npublic class TextMessageListener extends MessageListener\u003cTextInboundMessage\u003e {\n\n    @Override\n    protected ReplyMessage onMessage(TextInboundMessage message) {\n        String content = message.getContent();\n\t\n\t//根据消息内容来回复用户\n\tif (\"1\".equals(content)) {\n\t    TextReplyMessage replyMsg = new TextReplyMessage();\n\t    replyMsg.setContent(\"this is reply message content\");\n\t    replyMsg.setFromUserName(message.getToUserName());\n\t    replyMsg.setToUserName(message.getFromUserName());\n\t    replyMsg.setCreateTime(System.currentTimeMillis());\n\t    return replyMsg;\n\t}\n\t\n\t//返回null表示不回复用户\n\treturn null;\n    }\n}\n```\n\n###### 可监听的消息类型\n\n消息|说明\n---|---\nTextInboundMessage|文本消息 \nImageInboundMessage|图片消息\nLinkInboundMessage|跳转图文消息\nLocationInboundMessage|共享位置消息\nShortVideoInboundMessage|小视频消息\nVideoInboundMessage|视频消息\nVoiceInboundMessage|语音消息\nClickEventMessage|点击普通菜单消息\nViewEventMessage|点击跳转链接菜单消息\nLocationEventMessage|位置事件消息\nSubscribeEventMessage|用户关注公众号消息\nUnsubscribeEventMessage|用记取消关注公众号消息\nScanEventMessage|用户扫描二维码消息\nMassSendJobFinishEventMessage|群发消息发送完成报告\n\n###### 可回复的消息类型\n\n消息|说明\n---|---\nTextReplyMessage|文本回复\nImageReplyMessage|图片回复\nMusicReplyMessage|音乐回复\nNewsReplyMessage|图文回复\nVideoReplyMessage|视频回复\nVoiceReplyMessage|语音回复\n\n### 发送消息\n\n公众号可以主动发送消息给用户，包括群发消息和客服消息两大类型消息。所有消息统一使用`space.chensheng.wechatty.mp.message.MpMessageSender`来发送。\n\n###### 群发消息\n\n```\nTextMassMessage message = new TextMassMessage();\nmessage.setIsToAll(true);\nmessage.setContent(\"群发消息测试\");\nmpAppContext.getMpMessageSender().send(message, 3);\n```\n群发消息类型|说明\n-----|-----\nTextMassMessage|文本群发\nImageMassMessage|图片群发\nMpnewsMassMessage|微信内图文群发\nMpvideoMassMessage|视频群发\nVoiceMassMessage|语音群发\nWxcardMassMessage|微信卡券群发\n\n###### 客服消息\n\n```\nTextCsMessage message = new TextCsMessage();\nmessage.setToUser(\"thisIsUserOpenId\");\nmessage.setContent(\"客服消息测试 \\n 212\");\nmpAppContext.getMpMessageSender().send(message, 3);\n```\n客服消息类型|说明\n-----|-----\nTextCsMessage|文本客服\nImageCsMessage|图片客服\nMpnewsCsMessage|微信内图文客服\nNewsCsMessage|外部图文客服\nVideoCsMessage|视频客服\nVoiceCsMessage|语音客服\nWxcardCsMessage|微信卡券客服\n\n### 素材管理\n\n素材管理主要是进行素材的上传、查询、修改、删除，素材类型包括图片、视频、语音、图文。\n\n###### 上传素材\n\n上传素材通过操作对应的素材上传类来完成，下面是一个上传图片的例子：\n\n```\nFile image = new File(\"/this/is/image/path.jpg\");\nImagePermanentMedia material = new ImagePermanentMedia(mpAppContext, image);\nUploadResponse resp = material.upload();\n```\n素材上传类|说明\n-----|-----\nImagePermanentMedia|永久图片\nThumbPermanentMedia|永久缩略图\nVideoPermanentMedia|永久视频\nVoicePermanentMedia|永久语音\nPermanentNews|永久图文\nPermanentNewsImg|永久图文中的图片\nImageTemporaryMedia|临时图片\nThumbTemporaryMedia|临时缩略图\nVideoTemporaryMedia|临时视频\nVoiceTemporaryMedia|临时语音\n\n###### 查询素材\n\n查询素材操作通过工具类`space.chensheng.wechatty.mp.material.MaterialQuery`和`space.chensheng.wechatty.mp.material.MaterialFinder`完成。\n\n* 查询素材的数量信息：`mpAppContext.getMaterialQuery().count()`\n* 查询图文素材：`mpAppContext.getMaterialQuery().listNews(int offset, int count)`\n* 查询其他素材：`mpAppContext.getMaterialQuery().listMedia(MediaType mediaType, int offset, int count)`\n* 根据mediaId查找图文：`mpAppContext.getMaterialFinder().findNews(String mediaId)`\n* 根据mediaId查找永久视频：`mpAppContext.getMaterialFinder().findPermanentVideo(String mediaId)`\n* 根据mediaId查找临时视频：`mpAppContext.getMaterialFinder().findTemporaryVideo(String mediaId)`\n* 根据mediaId下载永久素材：`mpAppContext.getMaterialFinder().downloadPermanentMedia(String mediaId, String saveDir, String fileName)`\n* 根据mediaId下载临时素材：`mpAppContext.getMaterialFinder().downloadTemporaryMedia(String mediaId, String saveDir, String fileName)`\n\n###### 删除素材\n\n删除素材操作通过工具类`space.chensheng.wechatty.mp.material.MaterialDeleter`完成。\n\n* 根据mediaId删除素材：`mpAppContext.getMaterialDeleter().delete(String mediaId)`\n\n### 帐号管理\n\n###### 生成带参数二维码\n\n生成带参数二维码通过工具类`space.chensheng.wechatty.mp.account.QRCodeCreator`完成。\n\n* 生成带参数临时二维码：`mpAppContext.getQRCodeCreator().createTemporary(int expireSeconds, int sceneId)`\n* 生成带整型参数永久二维码：`mpAppContext.getQRCodeCreator().createPermanent(int sceneId)`\n* 生成带字符串参数永久二维码：`mpAppContext.getQRCodeCreator().createPermanent(String sceneStr)`\n\n###### 查询用户信息\n\n查询用户信息通过`UserInfoQuery`实现。\n\n* 查询单个用户信息: `mpAppConext.getUserInfoQuery().get(String openId)`\n* 批量查询用户信息：`mpAppContext.getUserInfoQuery().batchGet(List\u003cString\u003e openIds)`\n\n### 微信授权\n\n###### 用户授权\n\n用户授权通过`AuthHelper`实现。\n\n* 通过授权链接的code获取`auth access token`: `mpAppContext.getAuthHelper().fetchAuthAccessToken(String code)`\n* 刷新`auth access token`: `mpAppContext.getAuthHelper().refreshAuthAccessToken(String refreshAccessToken)`\n* 通过`auth access token`获取用户信息: `mpAppContext.getAuthHelper().fetchAuthUserInfo(String authAccessToken, String openId)`\n\n以下是一段用户授权的伪代码:\n```\npublic WxAuthLoginDto authAndLogin(String code) {\n    AuthAccessTokenResponse authResp = mpAppContext.getAuthHelper().fetchAuthAccessToken(code);\n    if (authResp == null || !authResp.isOk()) {\n        //授权失败，执行相应业务逻辑\n        return new WxAuthLoginDto(\"fail\");\n    }\n\t\t\n    String openId = authResp.getOpenId();\n    AuthUserInfoResponse wxUserInfo = mpAppContext.getAuthHelper().fetchAuthUserInfo(authResp.getAccessToken(), authResp.getOpenId())\n    //根据微信用户信息在数据库里查找系统对应的用户，或新建一个用户\n    \n    //进行登录相关业务逻辑处理\n    return new WxAuthLoginDto(\"success\");\n}\n```\n\n###### jsapi授权\n\njsapi授权通过`JsapiHelper`实现。\n\n* 获取`jsapi ticket`(可使用定时任务来定时获取ticket并存于数据库中): `mpAppContext.getJsapiHelper().fetchTicket()`\n* 生成jsapi签名信息: `mpAppContext.getJsapiHelper().generateSignature(String jsapiTicket, String nonceStr, long timestamp, String url)`\n\n### 微信支付\n\n初始化`MpAppContext`时，调用`WechatMpBootstrap`的`enablePayCert()`方法来启用微信支付，并配置相关参数。(具体参数查看[配置](#配置)模块)\n```\nWechatMpBootstrap bootstrap = new WechatMpBootstrap();\nbootstrap.enablePayCert();\n```\n\n* 发送普通红包: `mpAppContext.getPayHelper().sendRedPack(RedPackRequest request)`\n* 发送群红包: `mpAppContext.getPayHelper().sendGroupRedPack(GroupRedPackRequest request)`\n* 转账: `mpAppContext.getPayHelper().transfers(TransfersRequest request)`\n* 生成预付款订单: `mpAppContext.getPayHelper().unifiedOrder(UnifiedOrderRequest request)`\n* 解析支付回调: `mpAppContext.getPayHelper().parsePayNotify(String notifyContent)`\n* 校验支付回调: `mpAppContext.getPayHelper().validatePayNotify(PayNotifyResponse response)`\n* 支付订单查询: `mpAppContext.getPayHelper().orderQuery(OrderQueryRequest request)`\n* 关闭支付订单: `mpAppContext.getPayHelper().closeOrder(CloseOrderRequest request)` \n* 生成短链接: `mpAppContext.getPayHelper().shortUrl(String longUrl)`\n* 生成js支付参数: `mpAppContext.getPayHelper().generateJsapiPayParams(String prepayId, PaySignType signType)`\n* 发起退款: `mpAppContext.getPayHelper().refund(RefundRequest request)`\n* 解析退款回调: `mpAppContext.getPayHelper().parseRefundNotify(String notifyContent)`\n* \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchensheng%2Fwechatty-project","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchensheng%2Fwechatty-project","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchensheng%2Fwechatty-project/lists"}