├── src ├── main │ ├── resource │ │ ├── META-INF │ │ │ ├── README.md │ │ │ ├── NOTICE.txt │ │ │ └── wechat4j.properties.sample │ │ ├── log4j.properties │ │ └── wechat4j.properties.sample │ └── java │ │ └── org │ │ └── sword │ │ └── wechat4j │ │ ├── ai │ │ └── readme.md │ │ ├── card │ │ └── readme.md │ │ ├── iot │ │ └── readme.md │ │ ├── pay │ │ └── readme.md │ │ ├── shop │ │ └── readme.md │ │ ├── common │ │ ├── MediaType.java │ │ ├── ValidateSignature.java │ │ ├── Config.java │ │ └── MediaFile.java │ │ ├── token │ │ ├── TicketType.java │ │ ├── server │ │ │ ├── TicketServer.java │ │ │ ├── TokenServer.java │ │ │ ├── IServer.java │ │ │ ├── AccessTokenServer.java │ │ │ ├── CustomerServer.java │ │ │ ├── JsApiTicketServer.java │ │ │ ├── JsApiTicketMemServer.java │ │ │ ├── AccessTokenMemServer.java │ │ │ └── AbsServer.java │ │ ├── TokenProxy.java │ │ ├── AccessToken.java │ │ ├── timer │ │ │ ├── JsApiTicketTimer.java │ │ │ └── AccessTokenTimer.java │ │ ├── Ticket.java │ │ ├── TokenListener.java │ │ └── Token.java │ │ ├── user │ │ ├── LanguageType.java │ │ ├── QrcodeType.java │ │ ├── Data.java │ │ ├── Group.java │ │ ├── Follwers.java │ │ ├── Qrcode.java │ │ ├── AccountManager.java │ │ └── User.java │ │ ├── exception │ │ └── WeChatException.java │ │ ├── menu │ │ ├── Menu.java │ │ ├── MenuButtonType.java │ │ ├── MenuButton.java │ │ └── MenuManager.java │ │ ├── event │ │ ├── MsgType.java │ │ └── EventType.java │ │ ├── param │ │ ├── WechatParamName.java │ │ └── SignatureParam.java │ │ ├── request │ │ ├── Item.java │ │ ├── ScanCodeInfo.java │ │ ├── SendPicsInfo.java │ │ └── SendLocationInfo.java │ │ ├── response │ │ ├── ImageResponse.java │ │ ├── VoiceResponse.java │ │ ├── TransInfoResponse.java │ │ ├── ArticleResponse.java │ │ ├── VideoResponse.java │ │ ├── MusicResponse.java │ │ └── WechatResponse.java │ │ ├── message │ │ ├── template │ │ │ ├── TemplateMsgData.java │ │ │ └── TemplateMsgBody.java │ │ └── TemplateMsg.java │ │ ├── util │ │ └── WeChatUtil.java │ │ └── csc │ │ ├── RecordOperCode.java │ │ ├── CustomerServicesSession.java │ │ ├── Record.java │ │ └── CustomerServices.java └── test │ └── java │ ├── org │ └── sword │ │ └── wechat4j │ │ ├── common │ │ ├── weixin.jpg │ │ ├── weixin_down.jpg │ │ ├── ConfigTest.java │ │ └── MediaFileTest.java │ │ ├── WechatSupportTest.java │ │ ├── WechatTestSuite.java │ │ ├── token │ │ ├── TicketTest.java │ │ ├── AccessTokenTest.java │ │ ├── TokenProxyTest.java │ │ └── AccessTokenServerTest.java │ │ ├── SendMsgTest.java │ │ ├── WechatTest.java │ │ ├── user │ │ ├── AccountTest.java │ │ └── UserTest.java │ │ ├── Wechat.java │ │ └── menu │ │ └── MenuTest.java │ ├── log4j.properties │ └── wechat4j.properties ├── doc ├── api │ ├── resources │ │ └── inherit.gif │ ├── package-list │ ├── org │ │ └── sword │ │ │ └── wechat4j │ │ │ ├── package-frame.html │ │ │ ├── event │ │ │ └── package-frame.html │ │ │ ├── user │ │ │ ├── package-frame.html │ │ │ ├── package-use.html │ │ │ └── class-use │ │ │ │ └── UserManager.html │ │ │ ├── message │ │ │ ├── package-frame.html │ │ │ ├── template │ │ │ │ └── package-frame.html │ │ │ └── package-use.html │ │ │ ├── param │ │ │ ├── package-frame.html │ │ │ └── package-use.html │ │ │ ├── token │ │ │ ├── timer │ │ │ │ ├── package-frame.html │ │ │ │ └── package-use.html │ │ │ ├── package-frame.html │ │ │ ├── server │ │ │ │ └── package-frame.html │ │ │ └── class-use │ │ │ │ ├── Ticket.html │ │ │ │ └── TokenProxy.html │ │ │ ├── request │ │ │ └── package-frame.html │ │ │ ├── common │ │ │ ├── package-frame.html │ │ │ └── class-use │ │ │ │ └── MediaFile.html │ │ │ ├── response │ │ │ └── package-frame.html │ │ │ ├── package-use.html │ │ │ └── class-use │ │ │ └── WechatSupport.html │ ├── stylesheet.css │ ├── index.html │ ├── overview-frame.html │ ├── deprecated-list.html │ └── allclasses-noframe.html ├── wiki │ └── static │ │ └── assets │ │ ├── ac9be2eafdeb95d50b28fa7cd75bb499.jpg │ │ └── f2f7d30aa3411cb6688869baa817725a.jpg └── index.html ├── .settings ├── org.eclipse.m2e.core.prefs └── org.eclipse.jdt.core.prefs ├── .gitignore ├── .project ├── .classpath ├── pom.xml └── README.md /src/main/resource/META-INF/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /doc/api/resources/inherit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subaochen/wechat4j/HEAD/doc/api/resources/inherit.gif -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/ai/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subaochen/wechat4j/HEAD/src/main/java/org/sword/wechat4j/ai/readme.md -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/card/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subaochen/wechat4j/HEAD/src/main/java/org/sword/wechat4j/card/readme.md -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/iot/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subaochen/wechat4j/HEAD/src/main/java/org/sword/wechat4j/iot/readme.md -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/pay/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subaochen/wechat4j/HEAD/src/main/java/org/sword/wechat4j/pay/readme.md -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/shop/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subaochen/wechat4j/HEAD/src/main/java/org/sword/wechat4j/shop/readme.md -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/common/weixin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subaochen/wechat4j/HEAD/src/test/java/org/sword/wechat4j/common/weixin.jpg -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/common/weixin_down.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subaochen/wechat4j/HEAD/src/test/java/org/sword/wechat4j/common/weixin_down.jpg -------------------------------------------------------------------------------- /doc/wiki/static/assets/ac9be2eafdeb95d50b28fa7cd75bb499.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subaochen/wechat4j/HEAD/doc/wiki/static/assets/ac9be2eafdeb95d50b28fa7cd75bb499.jpg -------------------------------------------------------------------------------- /doc/wiki/static/assets/f2f7d30aa3411cb6688869baa817725a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subaochen/wechat4j/HEAD/doc/wiki/static/assets/f2f7d30aa3411cb6688869baa817725a.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | /bin 14 | /target/ 15 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/common/MediaType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.common; 5 | 6 | /** 7 | * @author ChengNing 8 | * @date 2015年1月26日 9 | */ 10 | public enum MediaType { 11 | image, 12 | voice, 13 | video, 14 | thumb 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/WechatSupportTest.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | public class WechatSupportTest { 8 | 9 | @Test 10 | public void test() { 11 | 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/TicketType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token; 5 | 6 | /** 7 | * @author ChengNing 8 | * @date 2015年1月29日 9 | */ 10 | public enum TicketType { 11 | /** 12 | * jsapi_ticket 13 | */ 14 | jsapi 15 | } 16 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 3 | org.eclipse.jdt.core.compiler.compliance=1.5 4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 5 | org.eclipse.jdt.core.compiler.source=1.5 6 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/server/TicketServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.server; 5 | 6 | /** 7 | * @author ChengNing 8 | * @date 2015年1月29日 9 | */ 10 | public interface TicketServer { 11 | 12 | public String ticket(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/user/LanguageType.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.user; 2 | /** 3 | * 语言种类 4 | * @author Zhangxs 5 | * @version 2015-7-5 6 | */ 7 | public enum LanguageType { 8 | /** 简体 */ 9 | zh_CN, 10 | /** 繁体 */ 11 | zh_TW, 12 | /** 英语 */ 13 | en; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/WechatTestSuite.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.junit.runners.Suite; 5 | import org.junit.runners.Suite.SuiteClasses; 6 | 7 | @RunWith(Suite.class) 8 | @SuiteClasses({}) 9 | public class WechatTestSuite { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/server/TokenServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.server; 5 | 6 | 7 | 8 | /** 9 | * accessToken中控服务器 10 | * @author ChengNing 11 | * @date 2015年1月9日 12 | */ 13 | public interface TokenServer { 14 | 15 | public String token(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/user/QrcodeType.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.user; 2 | /** 3 | * 二维码类型 4 | * @author Zhangxs 5 | * @version 2015-7-5 6 | */ 7 | public enum QrcodeType { 8 | /** 临时二维码 */ 9 | QR_SCENE, 10 | /** 永久二维码 */ 11 | QR_LIMIT_SCENE, 12 | /** 永久的字符串参数值 */ 13 | QR_LIMIT_STR_SCENE; 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/token/TicketTest.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.token; 2 | 3 | import org.junit.Test; 4 | 5 | public class TicketTest { 6 | 7 | @Test 8 | public void test(){ 9 | String jsapiTicket = TokenProxy.jsApiTicket(); 10 | String expi = ""; 11 | System.out.println(jsapiTicket); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/common/ConfigTest.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.common; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | public class ConfigTest { 8 | 9 | @Test 10 | public void testInstance() { 11 | Config c = Config.instance(); 12 | String appid = c.getAppid(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resource/META-INF/NOTICE.txt: -------------------------------------------------------------------------------- 1 | ====project home 2 | https://github.com/sword-org/wachat4j 3 | 4 | ====need jar 5 | commons-codec-1.9.jar 6 | commons-lang3-3.1.jar 7 | fastjson-1.2.0.jar 8 | log4j-1.2.14.jar 9 | 10 | httpclient-4.3.6.jar 11 | fluent-hc-4.3.6.jar(httpclient依赖) 12 | httpcore-4.3.3.jar (httpclient依赖) 13 | 14 | servlet-api.jar 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/exception/WeChatException.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.exception; 2 | 3 | /** 4 | * 异常处理 5 | * @author Zhangxs 6 | * @version 2015-7-4 7 | */ 8 | public class WeChatException extends Exception { 9 | private static final long serialVersionUID = 1L; 10 | public WeChatException(String msg){ 11 | super(msg); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/token/AccessTokenTest.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.token; 2 | 3 | 4 | import org.junit.Test; 5 | 6 | public class AccessTokenTest { 7 | 8 | @Test 9 | public void testRequest() { 10 | AccessToken accessToken = new AccessToken(); 11 | accessToken.request(); 12 | String result = accessToken.getToken(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/server/IServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.server; 5 | 6 | 7 | /** 8 | * 9 | * @author ChengNing 10 | * @date 2015年1月7日 11 | */ 12 | public interface IServer { 13 | 14 | public String token(); 15 | // 16 | // public IServer server(); 17 | // 18 | // public IServer customerServer(); 19 | // 20 | } 21 | -------------------------------------------------------------------------------- /doc/api/package-list: -------------------------------------------------------------------------------- 1 | org.sword.wechat4j 2 | org.sword.wechat4j.common 3 | org.sword.wechat4j.event 4 | org.sword.wechat4j.message 5 | org.sword.wechat4j.message.template 6 | org.sword.wechat4j.param 7 | org.sword.wechat4j.request 8 | org.sword.wechat4j.response 9 | org.sword.wechat4j.token 10 | org.sword.wechat4j.token.server 11 | org.sword.wechat4j.token.timer 12 | org.sword.wechat4j.user 13 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/menu/Menu.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.menu; 2 | 3 | import java.util.List; 4 | 5 | 6 | /** 7 | * 微信菜单 8 | * @author Zhangxs 9 | * @version 2015-7-4 10 | */ 11 | public class Menu { 12 | private List button; 13 | 14 | public List getButton() { 15 | return button; 16 | } 17 | 18 | public void setButton(List button) { 19 | this.button = button; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/event/MsgType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.event; 5 | 6 | /** 7 | * 微信消息类型,大小写对应微信接口,msgType的枚举值 8 | * @author ChengNing 9 | * @date 2014-12-4 10 | */ 11 | public enum MsgType { 12 | event, //事件 13 | text, //文本消息 14 | image, 15 | location, 16 | link, 17 | voice, 18 | video, 19 | shortvideo, //小视频消息 20 | music, 21 | news, 22 | transfer_customer_service;//客服系统 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/user/Data.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.user; 2 | 3 | import java.util.List; 4 | /** 5 | * 关注者列表 6 | * @author Zhangxs 7 | * @version 2015-7-5 8 | */ 9 | public class Data { 10 | /** 11 | * 用户列表 12 | */ 13 | private List openid; 14 | 15 | public List getOpenid() { 16 | return openid; 17 | } 18 | 19 | public void setOpenid(List openid) { 20 | this.openid = openid; 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/param/WechatParamName.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.param; 5 | 6 | /** 7 | * 微信接口中get请求方式中的参数名称 8 | * @author ChengNing 9 | * @date 2014-12-4 10 | */ 11 | public class WechatParamName { 12 | 13 | public static final String ECHOSTR = "echostr"; 14 | public static final String SIGNATURE = "signature"; 15 | public static final String TIMESTAMP = "timestamp"; 16 | public static final String NONCE = "nonce"; 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/request/Item.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.request; 5 | 6 | import javax.xml.bind.annotation.XmlElement; 7 | 8 | /** 9 | * @author ChengNing 10 | * @date 2015年1月6日 11 | */ 12 | public class Item { 13 | private String PicMd5Sum; 14 | 15 | @XmlElement(name="PicMd5Sum") 16 | public String getPicMd5Sum() { 17 | return PicMd5Sum; 18 | } 19 | public void setPicMd5Sum(String picMd5Sum) { 20 | PicMd5Sum = picMd5Sum; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/response/ImageResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.response; 5 | 6 | import javax.xml.bind.annotation.XmlElement; 7 | 8 | /** 9 | * @author ChengNing 10 | * @date 2014年12月7日 11 | */ 12 | public class ImageResponse { 13 | private String MediaId; 14 | 15 | @XmlElement(name="MediaId") 16 | public String getMediaId() { 17 | return MediaId; 18 | } 19 | 20 | public void setMediaId(String mediaId) { 21 | MediaId = mediaId; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/response/VoiceResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.response; 5 | 6 | import javax.xml.bind.annotation.XmlElement; 7 | 8 | /** 9 | * @author ChengNing 10 | * @date 2014年12月7日 11 | */ 12 | public class VoiceResponse { 13 | 14 | private String MediaId; 15 | 16 | @XmlElement(name="MediaId") 17 | public String getMediaId() { 18 | return MediaId; 19 | } 20 | 21 | public void setMediaId(String mediaId) { 22 | MediaId = mediaId; 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/menu/MenuButtonType.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.menu; 2 | 3 | /** 4 | * 菜单按钮类型 5 | * @author Zhangxs 6 | * @version 2015-7-4 7 | */ 8 | public enum MenuButtonType { 9 | /** 点击 */ 10 | click, 11 | /** 跳转URL */ 12 | view, 13 | /** 扫码推事件 */ 14 | scancode_push, 15 | /** 扫码推事件且弹出“消息接收中”提示框 */ 16 | scancode_waitmsg, 17 | /** 弹出系统拍照发图 */ 18 | pic_sysphoto, 19 | /** 弹出拍照或者相册发图 */ 20 | pic_photo_or_album, 21 | /** 弹出微信相册发图器 */ 22 | pic_weixin, 23 | /** 弹出地理位置选择器 */ 24 | location_select, 25 | /** //下发消息(除文本消息) */ 26 | media_id, 27 | /** 跳转图文消息URL */ 28 | view_limited; 29 | } 30 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | wechat4j 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.m2e.core.maven2Nature 21 | org.eclipse.jdt.core.javanature 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/server/AccessTokenServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.server; 5 | 6 | import org.sword.wechat4j.common.Config; 7 | 8 | /** 9 | * 适配器 10 | * @author ChengNing 11 | * @date 2015年1月30日 12 | */ 13 | public class AccessTokenServer extends AbsServer implements TokenServer { 14 | 15 | 16 | /** 17 | * 18 | */ 19 | public String token(){ 20 | return super.token(); 21 | } 22 | 23 | @Override 24 | protected String getCustomerServerClass() { 25 | return Config.instance().getAccessTokenServer(); 26 | } 27 | 28 | @Override 29 | public IServer defaultServer() { 30 | return AccessTokenMemServer.instance(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/server/CustomerServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.server; 5 | 6 | import org.sword.wechat4j.token.Token; 7 | 8 | /** 9 | * @author ChengNing 10 | * @date 2015年1月30日 11 | */ 12 | public abstract class CustomerServer implements IServer { 13 | 14 | public String token(){ 15 | return find(); 16 | } 17 | 18 | /** 19 | * 保存或者更新accesstoken到数据库 20 | * 由客户自己实现数据库插入或者更新操作 21 | * @param token 得到的token或者ticket,需要保存 22 | * @return 23 | */ 24 | public abstract boolean save(Token token); 25 | /** 26 | * 从数据库得到accessToken 27 | * 由客户自己实现数据库的查询操作 28 | * @return 29 | */ 30 | protected abstract String find(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/user/Group.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.user; 2 | /** 3 | * 分组 4 | * @author Zhangxs 5 | * @version 2015-7-5 6 | */ 7 | public class Group { 8 | /**分组id*/ 9 | private Integer id; 10 | /**分组名字*/ 11 | private String name; 12 | /**分组内用户数量*/ 13 | private int count; 14 | public Integer getId() { 15 | return id; 16 | } 17 | public void setId(Integer id) { 18 | this.id = id; 19 | } 20 | public String getName() { 21 | return name; 22 | } 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | public int getCount() { 27 | return count; 28 | } 29 | public void setCount(int count) { 30 | this.count = count; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/response/TransInfoResponse.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.response; 2 | 3 | import javax.xml.bind.annotation.XmlElement; 4 | 5 | /** 6 | * 指定客服 7 | * @author Zhangxs 8 | * @version 2015-7-7 9 | */ 10 | 11 | public class TransInfoResponse { 12 | private String KfAccount;//指定会话接入的客服账号 13 | 14 | public TransInfoResponse() { 15 | super(); 16 | } 17 | 18 | public TransInfoResponse(String kfAccount) { 19 | super(); 20 | KfAccount = kfAccount; 21 | } 22 | 23 | @XmlElement(name="KfAccount") 24 | public String getKfAccount() { 25 | return KfAccount; 26 | } 27 | 28 | public void setKfAccount(String kfAccount) { 29 | KfAccount = kfAccount; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/token/TokenProxyTest.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.token; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | public class TokenProxyTest { 10 | 11 | @Before 12 | public void setUp() throws Exception { 13 | } 14 | 15 | @After 16 | public void tearDown() throws Exception { 17 | } 18 | 19 | 20 | // @Test 21 | // public void tokenTest(){ 22 | // String accessToken = TokenProxy.accessToken(); 23 | // System.out.println(accessToken); 24 | // 25 | // } 26 | 27 | @Test 28 | public void jsApiTicketTest(){ 29 | String jsApiTicket = TokenProxy.jsApiTicket(); 30 | System.out.println(jsApiTicket); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, file, stdout 3 | 4 | # Direct log messages to a log file 5 | log4j.appender.file=org.apache.log4j.RollingFileAppender 6 | log4j.appender.file.File=D:\\ims.log 7 | log4j.appender.file.MaxFileSize=10MB 8 | log4j.appender.file.MaxBackupIndex=10 9 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 11 | 12 | # Direct log messages to stdout 13 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 14 | log4j.appender.stdout.Target=System.out 15 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /src/main/resource/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, file, stdout 3 | 4 | # Direct log messages to a log file 5 | log4j.appender.file=org.apache.log4j.RollingFileAppender 6 | log4j.appender.file.File=D:\\ims.log 7 | log4j.appender.file.MaxFileSize=10MB 8 | log4j.appender.file.MaxBackupIndex=10 9 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 11 | 12 | # Direct log messages to stdout 13 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 14 | log4j.appender.stdout.Target=System.out 15 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/request/ScanCodeInfo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.request; 5 | 6 | import javax.xml.bind.annotation.XmlElement; 7 | 8 | /** 9 | * @author ChengNing 10 | * @date 2015年1月7日 11 | */ 12 | public class ScanCodeInfo { 13 | private String ScanType; //扫描类型,一般是qrcode 14 | private String ScanResult; //扫描结果,即二维码对应的字符串信息 15 | 16 | @XmlElement(name="ScanType") 17 | public String getScanType() { 18 | return ScanType; 19 | } 20 | public void setScanType(String scanType) { 21 | ScanType = scanType; 22 | } 23 | @XmlElement(name="ScanResult") 24 | public String getScanResult() { 25 | return ScanResult; 26 | } 27 | public void setScanResult(String scanResult) { 28 | ScanResult = scanResult; 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/server/JsApiTicketServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.server; 5 | 6 | import org.sword.wechat4j.common.Config; 7 | 8 | 9 | /** 10 | * Ticket server适配器 11 | * @author ChengNing 12 | * @date 2015年1月29日 13 | */ 14 | public class JsApiTicketServer extends AbsServer implements TicketServer { 15 | 16 | 17 | /** 18 | * 19 | */ 20 | public String ticket() { 21 | return super.token(); 22 | } 23 | 24 | /** 25 | * 26 | */ 27 | @Override 28 | protected String getCustomerServerClass() { 29 | return Config.instance().getJsApiTicketServer(); 30 | } 31 | 32 | /** 33 | * 34 | */ 35 | @Override 36 | public IServer defaultServer() { 37 | return JsApiTicketMemServer.instance(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/message/template/TemplateMsgData.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.message.template; 5 | 6 | /** 7 | * @author ChengNing 8 | * @date 2014年12月24日 9 | */ 10 | public class TemplateMsgData { 11 | private String name; //json中的数据名称 12 | private String value; //keynote value 13 | private String color; //data keynote color 14 | 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | public String getValue() { 23 | return value; 24 | } 25 | public void setValue(String value) { 26 | this.value = value; 27 | } 28 | public String getColor() { 29 | return color; 30 | } 31 | public void setColor(String color) { 32 | this.color = color; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resource/META-INF/wechat4j.properties.sample: -------------------------------------------------------------------------------- 1 | 2 | #you wechat token 3 | wechat.token=token 4 | #message secret key,if don't set then message is cleartext 5 | wechat.encodingaeskey= 6 | 7 | #wechat appid 8 | wechat.appid=appid 9 | #wechat app secret 10 | wechat.appsecret=appsecret 11 | 12 | #wechat access token server ,when you save in db,must implement you server class 13 | #this class must extend org.sword.wechat4j.token.server.CustomerServer 14 | #if no this property,then token server is default memery accesstoken server 15 | wechat.accessToken.server.class= 16 | 17 | #jsapi_ticket customer server class name, 18 | #this class must extend org.sword.wechat4j.token.server.CustomerServer 19 | #if no this property,then ticket server is default memery ticket server 20 | wechat.ticket.jsapi.server.class= -------------------------------------------------------------------------------- /src/test/java/wechat4j.properties: -------------------------------------------------------------------------------- 1 | 2 | 3 | #url 4 | wechat.url= 5 | #token 6 | wechat.token=lejian 7 | #encodingaeskey 8 | wechat.encodingaeskey= 9 | 10 | #wechat appid 11 | wechat.appid=wx575d25f1d917ea69 12 | #wechat app secret 13 | wechat.appsecret=a338496aaed7c84f0466b494a51c88f1 14 | 15 | 16 | #wechat access token server ,when you save in db,must implement you server class 17 | #this class must extend org.sword.wechat4j.token.server.CustomerServer 18 | #if no this property,then token server is default memery accesstoken server 19 | wechat.accessToken.server.class= 20 | 21 | #jsapi_ticket customer server class name, 22 | #this class must extend org.sword.wechat4j.token.server.CustomerServer 23 | #if no this property,then ticket server is default memery ticket server 24 | wechat.ticket.jsapi.server.class= -------------------------------------------------------------------------------- /src/main/resource/wechat4j.properties.sample: -------------------------------------------------------------------------------- 1 | 2 | #you server url 3 | wechat.url= 4 | #you wechat token 5 | wechat.token=token 6 | #message secret key,if don't set then message is cleartext 7 | wechat.encodingaeskey= 8 | 9 | #wechat appid 10 | wechat.appid=appid 11 | #wechat app secret 12 | wechat.appsecret=appsecret 13 | 14 | #wechat access token server ,when you save in db,must implement you server class 15 | #this class must extend org.sword.wechat4j.token.server.CustomerServer 16 | #if no this property,then token server is default memery accesstoken server 17 | wechat.accessToken.server.class= 18 | 19 | #jsapi_ticket customer server class name, 20 | #this class must extend org.sword.wechat4j.token.server.CustomerServer 21 | #if no this property,then ticket server is default memery ticket server 22 | wechat.ticket.jsapi.server.class= -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/request/SendPicsInfo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.request; 5 | 6 | import java.util.List; 7 | 8 | import javax.xml.bind.annotation.XmlElement; 9 | import javax.xml.bind.annotation.XmlElementWrapper; 10 | 11 | /** 12 | * @author ChengNing 13 | * @date 2015年1月6日 14 | */ 15 | public class SendPicsInfo { 16 | private String Count; 17 | private List item; 18 | 19 | @XmlElement(name="Count") 20 | public String getCount() { 21 | return Count; 22 | } 23 | public void setCount(String count) { 24 | Count = count; 25 | } 26 | @XmlElementWrapper(name="PicList") 27 | @XmlElement(name="item") 28 | public List getItem() { 29 | return item; 30 | } 31 | public void setItem(List item) { 32 | this.item = item; 33 | } 34 | 35 | 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/util/WeChatUtil.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.util; 2 | 3 | import org.sword.wechat4j.exception.WeChatException; 4 | import org.sword.wechat4j.exception.WeChatReturnCode; 5 | 6 | import com.alibaba.fastjson.JSONObject; 7 | /** 8 | * 工具类 9 | * @author Zhangxs 10 | * @version 2015-7-4 11 | */ 12 | public class WeChatUtil { 13 | /** 14 | * 判断是否请求成功 15 | * @param resultStr 16 | * @throws WeChatException 17 | */ 18 | public static void isSuccess(String resultStr) throws WeChatException{ 19 | JSONObject jsonObject = JSONObject.parseObject(resultStr); 20 | Integer errCode =jsonObject.getIntValue("errcode"); 21 | if (errCode!=null && errCode!=0) { 22 | String errMsg = WeChatReturnCode.getMsg(errCode); 23 | if (errMsg.equals("")) { 24 | errMsg = jsonObject.getString("errmsg"); 25 | } 26 | throw new WeChatException("异常码:"+errCode+";异常说明:"+errMsg); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/token/AccessTokenServerTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token; 5 | 6 | import org.apache.log4j.Logger; 7 | import org.junit.Test; 8 | import org.sword.lang.HttpUtils; 9 | import org.sword.wechat4j.token.server.AccessTokenServer; 10 | 11 | /** 12 | * @author ChengNing 13 | * @date 2015年1月30日 14 | */ 15 | public class AccessTokenServerTest { 16 | 17 | private static Logger logger = Logger.getLogger(AccessTokenServerTest.class); 18 | @Test 19 | public void test(){ 20 | AccessTokenServer accessTokenServer = new AccessTokenServer(); 21 | accessTokenServer.defaultServer(); 22 | } 23 | 24 | @Test 25 | public void testGet(){ 26 | try { 27 | String result = HttpUtils.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx925a77489e94a7e6&secret=d29ae7a0b55d2f8570107d90985034dc"); 28 | logger.info(result); 29 | } catch (Exception e) { 30 | // TODO: handle exception 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/TokenProxy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token; 5 | 6 | import org.sword.wechat4j.token.server.AccessTokenServer; 7 | import org.sword.wechat4j.token.server.JsApiTicketServer; 8 | import org.sword.wechat4j.token.server.TicketServer; 9 | import org.sword.wechat4j.token.server.TokenServer; 10 | 11 | 12 | /** 13 | * AccessToken代理 14 | * 所有获取accessToken的地方都通过此代理获得 15 | * 获得方法String token = AccessTokenProxy.token() 16 | * @author ChengNing 17 | * @date 2015年1月9日 18 | */ 19 | public class TokenProxy { 20 | 21 | /** 22 | * 通过代理得到accessToken的串 23 | */ 24 | public static String accessToken(){ 25 | TokenServer accessTokenServer = new AccessTokenServer(); 26 | return accessTokenServer.token(); 27 | } 28 | 29 | /** 30 | * 通过代理得到jsapi_ticket 31 | */ 32 | public static String jsApiTicket(){ 33 | TicketServer ticketServer = new JsApiTicketServer(); 34 | return ticketServer.ticket(); 35 | } 36 | 37 | 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/csc/RecordOperCode.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.csc; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | /** 6 | * 操作ID(会话状态)说明 7 | * @author Zhangxs 8 | * @date 2015-7-8 9 | * @version 10 | */ 11 | public class RecordOperCode { 12 | private final static Map operCodeMap = new HashMap(); 13 | 14 | static { 15 | operCodeMap.put(1000,"创建未接入会话"); 16 | operCodeMap.put(1001,"接入会话"); 17 | operCodeMap.put(1002,"主动发起会话"); 18 | operCodeMap.put(1004,"关闭会话"); 19 | operCodeMap.put(1005,"抢接会话"); 20 | operCodeMap.put(2001,"公众号收到消息"); 21 | operCodeMap.put(2002,"客服发送消息"); 22 | operCodeMap.put(2003,"客服收到消息"); 23 | } 24 | /** 25 | * 根据opercode返回会话状态 26 | * @param opercode 27 | * @return 28 | */ 29 | public static String getSessionState(int opercode){ 30 | if (operCodeMap.containsKey(opercode)) { 31 | return operCodeMap.get(opercode); 32 | } 33 | return ""; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j 21 | 22 | 23 | 28 | 29 |
24 | 类  25 | 26 |
27 | WechatSupport
30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/user/Follwers.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.user; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | 5 | /** 6 | * 关注者集合 7 | * @author Zhangxs 8 | * @version 2015-7-5 9 | */ 10 | public class Follwers { 11 | private int total;// 关注该公众账号的总用户数 12 | private int count;// 拉取的OPENID个数,最大值为10000 13 | private Data data;// 列表数据,OPENID的列表 14 | private String nextOpenid;//拉取列表的后一个用户的OPENID 15 | public int getTotal() { 16 | return total; 17 | } 18 | public void setTotal(int total) { 19 | this.total = total; 20 | } 21 | public int getCount() { 22 | return count; 23 | } 24 | public void setCount(int count) { 25 | this.count = count; 26 | } 27 | public Data getData() { 28 | return data; 29 | } 30 | public void setData(Data data) { 31 | this.data = data; 32 | } 33 | @JSONField(name="next_openid") 34 | public String getNextOpenid() { 35 | return nextOpenid; 36 | } 37 | @JSONField(name="next_openid") 38 | public void setNextOpenid(String nextOpenid) { 39 | this.nextOpenid = nextOpenid; 40 | } 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/AccessToken.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token; 5 | 6 | 7 | import org.apache.log4j.Logger; 8 | import org.sword.wechat4j.common.Config; 9 | 10 | 11 | /** 12 | * Access token实体模型 13 | * @author ChengNing 14 | * @date 2014年12月12日 15 | */ 16 | public class AccessToken extends Token { 17 | 18 | private static Logger logger = Logger.getLogger(AccessToken.class); 19 | private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"; 20 | 21 | 22 | @Override 23 | protected String tokenName() { 24 | return "access_token"; 25 | } 26 | 27 | @Override 28 | protected String expiresInName() { 29 | return "expires_in"; 30 | } 31 | 32 | /** 33 | * 组织accesstoken的请求utl 34 | */ 35 | @Override 36 | protected String accessTokenUrl() { 37 | String appid = Config.instance().getAppid(); 38 | String appsecret = Config.instance().getAppSecret(); 39 | String url = ACCESS_TOKEN_URL + "&appid=" + appid + "&secret=" + appsecret; 40 | logger.info("创建获取access_token url"); 41 | return url; 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/event/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.event 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.event 21 | 22 | 23 | 30 | 31 |
24 | 枚举  25 | 26 |
27 | EventType 28 |
29 | MsgType
32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/response/ArticleResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.response; 5 | 6 | import javax.xml.bind.annotation.XmlElement; 7 | 8 | /** 9 | * 图文消息体 10 | * @author ChengNing 11 | * @date 2014年12月7日 12 | */ 13 | public class ArticleResponse { 14 | 15 | private String Title; //图文消息标题 16 | private String Description; //图文消息描述 17 | private String PicUrl; //图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200 18 | private String Url; //点击图文消息跳转链接 19 | 20 | @XmlElement(name="Title") 21 | public String getTitle() { 22 | return Title; 23 | } 24 | public void setTitle(String title) { 25 | Title = title; 26 | } 27 | @XmlElement(name="Description") 28 | public String getDescription() { 29 | return Description; 30 | } 31 | public void setDescription(String description) { 32 | Description = description; 33 | } 34 | @XmlElement(name="PicUrl") 35 | public String getPicUrl() { 36 | return PicUrl; 37 | } 38 | public void setPicUrl(String picUrl) { 39 | PicUrl = picUrl; 40 | } 41 | @XmlElement(name="Url") 42 | public String getUrl() { 43 | return Url; 44 | } 45 | public void setUrl(String url) { 46 | Url = url; 47 | } 48 | 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/user/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.user 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.user 21 | 22 | 23 | 30 | 31 |
24 | 类  25 | 26 |
27 | AccountManager 28 |
29 | UserManager
32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/message/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.message 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.message 21 | 22 | 23 | 30 | 31 |
24 | 类  25 | 26 |
27 | CustomerMsg 28 |
29 | TemplateMsg
32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/param/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.param 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.param 21 | 22 | 23 | 30 | 31 |
24 | 类  25 | 26 |
27 | SignatureParam 28 |
29 | WechatParamName
32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/response/VideoResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.response; 5 | 6 | import javax.xml.bind.annotation.XmlElement; 7 | 8 | /** 9 | * 视频消息 10 | * @author ChengNing 11 | * @date 2014年12月7日 12 | */ 13 | public class VideoResponse { 14 | 15 | private String MediaId; //通过上传多媒体文件,得到的id 16 | private String Title; //视频消息的标题 17 | private String Description; //视频消息的描述 18 | private String ThumbMediaId; 19 | 20 | @XmlElement(name="MediaId") 21 | public String getMediaId() { 22 | return MediaId; 23 | } 24 | public void setMediaId(String mediaId) { 25 | MediaId = mediaId; 26 | } 27 | @XmlElement(name="Title") 28 | public String getTitle() { 29 | return Title; 30 | } 31 | public void setTitle(String title) { 32 | Title = title; 33 | } 34 | @XmlElement(name="Description") 35 | public String getDescription() { 36 | return Description; 37 | } 38 | public void setDescription(String description) { 39 | Description = description; 40 | } 41 | @XmlElement(name="ThumbMediaId") 42 | public String getThumbMediaId() { 43 | return ThumbMediaId; 44 | } 45 | public void setThumbMediaId(String thumbMediaId) { 46 | ThumbMediaId = thumbMediaId; 47 | } 48 | 49 | 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/timer/JsApiTicketTimer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.timer; 5 | 6 | import java.util.TimerTask; 7 | 8 | import org.apache.log4j.Logger; 9 | import org.sword.wechat4j.token.Ticket; 10 | import org.sword.wechat4j.token.TicketType; 11 | import org.sword.wechat4j.token.server.CustomerServer; 12 | import org.sword.wechat4j.token.server.JsApiTicketServer; 13 | 14 | /** 15 | * @author ChengNing 16 | * @date 2015年1月29日 17 | */ 18 | public class JsApiTicketTimer extends TimerTask { 19 | 20 | private static Logger logger = Logger.getLogger(JsApiTicketTimer.class); 21 | // jsapi_ticket有效期7200秒,提前200秒请求新的token 22 | public static final long PERIOD = 7000 * 1000; 23 | public static final long DELAY = 0; // 此任务的延迟时间为0,即立即执行 24 | 25 | @Override 26 | public void run() { 27 | logger.info("jsapi_ticket 定时任务启动,获取新的jsapi_ticket"); 28 | // 得到新的access token 29 | Ticket jsapiTicket = new Ticket(TicketType.jsapi); 30 | // 手动获取成功之后持久化accessToken 31 | if (jsapiTicket.request()) { 32 | JsApiTicketServer jsapiTicketServer = new JsApiTicketServer(); 33 | CustomerServer customerServer = (CustomerServer) jsapiTicketServer 34 | .customerServer(); 35 | customerServer.save(jsapiTicket); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/timer/AccessTokenTimer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.timer; 5 | 6 | import java.util.TimerTask; 7 | 8 | import org.apache.log4j.Logger; 9 | import org.sword.wechat4j.token.AccessToken; 10 | import org.sword.wechat4j.token.server.AccessTokenServer; 11 | import org.sword.wechat4j.token.server.CustomerServer; 12 | 13 | /** 14 | * access token 定时器 15 | * @author ChengNing 16 | * @date 2015年1月8日 17 | */ 18 | public class AccessTokenTimer extends TimerTask{ 19 | 20 | private static Logger logger = Logger.getLogger(AccessTokenTimer.class); 21 | 22 | //accessToken有效期7200秒,提前200秒请求新的token 23 | // @TODO 未来微信可能修改7200秒的设置,需要灵活处理一下,比如放到配置文件 24 | public static final long PERIOD = 7000 * 1000; 25 | public static final long DELAY = 0; //此任务的延迟时间为0,即立即执行 26 | 27 | @Override 28 | public void run() { 29 | logger.info("accessToken 定时任务启动,获取新的accessToken"); 30 | //得到新的access token 31 | AccessToken accessToken = new AccessToken(); 32 | //获取成功之后持久化accessToken 33 | if(accessToken.request()){ 34 | AccessTokenServer accessTokenServer = new AccessTokenServer(); 35 | CustomerServer customerServer = (CustomerServer)accessTokenServer.customerServer(); 36 | customerServer.save(accessToken); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/token/timer/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.token.timer 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.token.timer 21 | 22 | 23 | 30 | 31 |
24 | 类  25 | 26 |
27 | AccessTokenTimer 28 |
29 | JsApiTicketTimer
32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/event/EventType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.event; 5 | 6 | /** 7 | * 微信事件类型,event字段的枚举
8 | * scancode_push、scancode_waitmsg、pic_sysphoto、pic_photo_or_album、pic_weixin、location_select
9 | * 仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户
10 | * media_id,view_limited
11 | * 仅限第三方平台旗下未微信认证(具体而言,是资质认证未通过)的订阅号准备的事件类型,没有事件推送 12 | * @author ChengNing 13 | * @author Zhangxs 14 | * @date 2015-7-6 15 | * 16 | */ 17 | public enum EventType { 18 | subscribe, //关注 19 | unsubscribe, //取消关注 20 | /** 创建菜单使用 */ 21 | click, 22 | CLICK, //点击 23 | /** 创建菜单使用 */ 24 | view, 25 | VIEW, //跳转链接 26 | SCAN, //扫描 27 | LOCATION, //上报地理位置 28 | TEMPLATESENDJOBFINISH, //模板消息发送成功之后事件 29 | scancode_push, //扫码推事件 30 | scancode_waitmsg, //扫码推事件且弹出“消息接收中”提示框的事件 31 | pic_sysphoto, //弹出系统拍照发图的事件 32 | pic_photo_or_album, //弹出拍照或者相册发图的事件 33 | pic_weixin, //弹出微信相册发图器的事件 34 | location_select, //弹出地理位置选择器的事件 35 | media_id, //下发消息(除文本消息) 36 | view_limited, //跳转图文消息URL 37 | kf_create_session, //接入会话 38 | kf_close_session, //关闭会话 39 | kf_switch_session, //转接会话 40 | merchant_order, //订单付款通知 41 | } 42 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/message/template/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.message.template 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.message.template 21 | 22 | 23 | 30 | 31 |
24 | 类  25 | 26 |
27 | TemplateMsgBody 28 |
29 | TemplateMsgData
32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/csc/CustomerServicesSession.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.csc; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | 5 | /** 6 | * 会话状态 7 | * @author Zhangxs 8 | * @date 2015-7-8 9 | * @version 10 | */ 11 | public class CustomerServicesSession { 12 | 13 | private int createTime;//会话接入的时间 14 | private String kfAccount;//客服 15 | private String openId;//客户openid 16 | /** 17 | * 会话接入的时间 18 | * @return 19 | */ 20 | @JSONField(name="createtime") 21 | public int getCreateTime() { 22 | return createTime; 23 | } 24 | @JSONField(name="createtime") 25 | public void setCreateTime(int createTime) { 26 | this.createTime = createTime; 27 | } 28 | /** 29 | * 客服 30 | * @return 31 | */ 32 | @JSONField(name="kf_account") 33 | public String getKfAccount() { 34 | return kfAccount; 35 | } 36 | @JSONField(name="kf_account") 37 | public void setKfAccount(String kfAccount) { 38 | this.kfAccount = kfAccount; 39 | } 40 | /** 41 | * 客户openid 42 | * @return 43 | */ 44 | @JSONField(name="openid") 45 | public String getOpenId() { 46 | return openId; 47 | } 48 | @JSONField(name="openid") 49 | public void setOpenId(String openId) { 50 | this.openId = openId; 51 | } 52 | 53 | 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/server/JsApiTicketMemServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.server; 5 | 6 | import org.sword.wechat4j.token.Ticket; 7 | import org.sword.wechat4j.token.TicketType; 8 | 9 | /** 10 | * 内存控制单例 11 | * @author ChengNing 12 | * @date 2015年1月29日 13 | */ 14 | public class JsApiTicketMemServer implements IServer{ 15 | 16 | private static JsApiTicketMemServer ticketServer = new JsApiTicketMemServer(); 17 | 18 | private Ticket jsApiTicket = new Ticket(TicketType.jsapi); 19 | 20 | private int requestTimes = 1;//token请求失败后重新请求的次数 21 | 22 | /** 23 | * 私有构造 24 | */ 25 | private JsApiTicketMemServer(){ 26 | //获取新的token 27 | refresh(); 28 | } 29 | 30 | /** 31 | * token中控服务器实例 32 | * @return ticket服务器实例 33 | */ 34 | public static JsApiTicketMemServer instance(){ 35 | return ticketServer; 36 | } 37 | 38 | 39 | /** 40 | * 通过中控服务器得到accessToken 41 | * @return 42 | */ 43 | public String token(){ 44 | //没有可用的token,则去刷新 45 | if(!this.jsApiTicket.isValid()){ 46 | refresh(); 47 | } 48 | return this.jsApiTicket.getToken(); 49 | } 50 | 51 | /** 52 | * 服务器刷新token 53 | */ 54 | private void refresh(){ 55 | for(int i=0;i 2 | 3 | 4 | 5 | 6 | 7 | 8 | wechat4j 9 | 10 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | <H2> 32 | 框架警报</H2> 33 | 34 | <P> 35 | 请使用框架功能查看此文档。如果看到此消息,则表明您使用的是不支持框架的 Web 客户机。 36 | <BR> 37 | 链接到<A HREF="overview-summary.html">非框架版本。</A> 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/Ticket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token; 5 | 6 | import org.apache.log4j.Logger; 7 | 8 | 9 | /** 10 | * 微信ticket操作类 11 | * ticket和token的逻辑在腾讯是差不多的,所以继承抽象类token 12 | * @author ChengNing 13 | * @date 2015年1月29日 14 | */ 15 | public class Ticket extends Token { 16 | 17 | private static Logger logger = Logger.getLogger(Ticket.class); 18 | 19 | private static final String TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?"; 20 | private static final String TICKET_NAME = "ticket"; 21 | private static final String EXPIRESIN_NAME = "expires_in"; 22 | 23 | private String type; 24 | 25 | public Ticket(TicketType ticketType){ 26 | super(); 27 | this.type = ticketType.name(); 28 | } 29 | 30 | /* (non-Javadoc) 31 | * @see org.sword.wechat4j.token.Token#accessTokenUrl() 32 | */ 33 | @Override 34 | protected String accessTokenUrl() { 35 | String access_token = TokenProxy.accessToken(); 36 | String url = TICKET_URL + "access_token=" + access_token + "&type=" + this.type; 37 | logger.info("获取ticket,ticket类型" + this.type); 38 | return url; 39 | } 40 | 41 | /* (non-Javadoc) 42 | * @see org.sword.wechat4j.token.Token#tokenName() 43 | */ 44 | @Override 45 | protected String tokenName() { 46 | return TICKET_NAME; 47 | } 48 | 49 | /* (non-Javadoc) 50 | * @see org.sword.wechat4j.token.Token#expiresInName() 51 | */ 52 | @Override 53 | protected String expiresInName() { 54 | return EXPIRESIN_NAME; 55 | } 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/response/MusicResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.response; 5 | 6 | import javax.xml.bind.annotation.XmlElement; 7 | 8 | /** 9 | * 音乐消息类型 10 | * @author ChengNing 11 | * @date 2014-12-4 12 | */ 13 | public class MusicResponse { 14 | 15 | private String Title; //音乐标题 16 | private String Description; //音乐描述 17 | private String MusicURL; //音乐链接 18 | private String HQMusicUrl; //高质量音乐链接,WIFI环境优先使用该链接播放音乐 19 | private String ThumbMediaId; //缩略图的媒体id,通过上传多媒体文件,得到的id 20 | 21 | 22 | @XmlElement(name="Title") 23 | public String getTitle() { 24 | return Title; 25 | } 26 | public void setTitle(String title) { 27 | Title = title; 28 | } 29 | @XmlElement(name="Description") 30 | public String getDescription() { 31 | return Description; 32 | } 33 | public void setDescription(String description) { 34 | Description = description; 35 | } 36 | @XmlElement(name="MusicURL") 37 | public String getMusicURL() { 38 | return MusicURL; 39 | } 40 | public void setMusicURL(String musicURL) { 41 | MusicURL = musicURL; 42 | } 43 | @XmlElement(name="HQMusicUrl") 44 | public String getHQMusicUrl() { 45 | return HQMusicUrl; 46 | } 47 | public void setHQMusicUrl(String hQMusicUrl) { 48 | HQMusicUrl = hQMusicUrl; 49 | } 50 | @XmlElement(name="ThumbMediaId") 51 | public String getThumbMediaId() { 52 | return ThumbMediaId; 53 | } 54 | public void setThumbMediaId(String thumbMediaId) { 55 | ThumbMediaId = thumbMediaId; 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | wechat4j doc 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |

wechat4j doc

21 |

wechat4j is wechat(weixin) develop framework for java 微信开发框架JAVA版,最简单易用微信开发框架

22 |

github项目地址: https://github.com/sword-org/wechat4j

23 |

github项目wiki: https://github.com/sword-org/wechat4j/wiki

24 |

25 | 开发者文档 26 |

27 |

微信开发者文档提供了同微信公众平台开发者文档类似的说明,不过文档中的内容都是如何用wechat4j来实现官方文档中的内容,读者可以两者一起对比阅读,这样就会更加深入的理解wechat4j和微信开发接口。ps:本文档的样式采用了微信官方文档的模板样式,如有侵权,请联系作者。

28 |

29 | API接口手册 30 |

31 |

API接口文档是通过javadoc生成的wechat4j的所有公开的接口,包括了包,类,方法和参数的说明,方便读者深入研究wechat4j和作为开发过程中的手册使用。

32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/request/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.request 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.request 21 | 22 | 23 | 36 | 37 |
24 | 类  25 | 26 |
27 | Item 28 |
29 | ScanCodeInfo 30 |
31 | SendLocationInfo 32 |
33 | SendPicsInfo 34 |
35 | WechatRequest
38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/common/ValidateSignature.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.common; 5 | 6 | import java.util.Arrays; 7 | 8 | import org.apache.commons.codec.digest.DigestUtils; 9 | 10 | /** 11 | * 用于微信的前面验证 12 | * 13 | * @author ChengNing 14 | * @date 2014-12-4 15 | */ 16 | public class ValidateSignature { 17 | 18 | private String signature; 19 | private String timestamp; 20 | private String nonce; 21 | private String token; 22 | 23 | /** 24 | * 前面验证构造 25 | * 26 | * @param signature 27 | * @param timestamp 28 | * @param nonce 29 | * @param token 30 | */ 31 | public ValidateSignature(String signature, String timestamp, String nonce, String token) { 32 | this.signature = signature; 33 | this.timestamp = timestamp; 34 | this.nonce = nonce; 35 | this.token = token; 36 | } 37 | 38 | /** 39 | * 验证 40 | * 41 | * @param token 42 | * @return true 验证通过,false 验证失败 43 | */ 44 | public boolean check() { 45 | if(this.signature == null || this.timestamp == null 46 | || this.nonce == null || this.token == null) 47 | return false; 48 | 49 | String sha1 = encode(); 50 | return sha1.equals(this.signature); 51 | } 52 | 53 | /** 54 | * 得到加密后的数据 55 | * 56 | * @return 57 | */ 58 | private String encode() { 59 | String[] sa = {this.token, this.timestamp, this.nonce}; 60 | Arrays.sort(sa); 61 | String sortStr = sa[0] + sa[1] + sa[2]; 62 | return DigestUtils.sha1Hex(sortStr); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/common/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.common 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.common 21 | 22 | 23 | 32 | 33 |
24 | 类  25 | 26 |
27 | Config 28 |
29 | MediaFile 30 |
31 | ValidateSignature
34 | 35 | 36 | 37 | 38 | 43 | 44 |
39 | 枚举  40 | 41 |
42 | MediaType
45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/TokenListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token; 5 | 6 | import java.util.Timer; 7 | 8 | import javax.servlet.ServletContextEvent; 9 | import javax.servlet.ServletContextListener; 10 | 11 | import org.apache.log4j.Logger; 12 | import org.sword.wechat4j.token.timer.AccessTokenTimer; 13 | import org.sword.wechat4j.token.timer.JsApiTicketTimer; 14 | 15 | 16 | /** 17 | * Access Token 监听器 18 | * @author ChengNing 19 | * @date 2015年1月8日 20 | */ 21 | public class TokenListener implements ServletContextListener{ 22 | 23 | private static Logger log = Logger.getLogger(TokenListener.class); 24 | 25 | private Timer timer = null; 26 | 27 | @Override 28 | public void contextInitialized(ServletContextEvent arg0) { 29 | log.info("accessToken监听器启动.........."); 30 | timer = new Timer(true); 31 | //注册定时任务 32 | registeAccessTokenTimer(); 33 | //注册jsapi_ticket定时器 34 | registeJsApiTicketTimer(); 35 | } 36 | 37 | @Override 38 | public void contextDestroyed(ServletContextEvent arg0) { 39 | timer.cancel(); 40 | } 41 | 42 | /** 43 | * 注册accessToken定时器 44 | */ 45 | private void registeAccessTokenTimer(){ 46 | AccessTokenTimer accessTokenTimer = new AccessTokenTimer(); 47 | timer.schedule(accessTokenTimer, AccessTokenTimer.DELAY,AccessTokenTimer.PERIOD); 48 | log.info("accessToken定时器注册成功,执行间隔为" + AccessTokenTimer.PERIOD); 49 | } 50 | 51 | /** 52 | * 注册jsapi_ticket定时器 53 | */ 54 | private void registeJsApiTicketTimer(){ 55 | JsApiTicketTimer jsApiTicketTimer = new JsApiTicketTimer(); 56 | timer.schedule(jsApiTicketTimer, JsApiTicketTimer.DELAY,JsApiTicketTimer.PERIOD); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/server/AccessTokenMemServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.server; 5 | 6 | import org.sword.wechat4j.token.AccessToken; 7 | import org.sword.wechat4j.token.Ticket; 8 | import org.sword.wechat4j.token.TicketType; 9 | 10 | /** 11 | * 内存中控服务器 12 | * access_token 中控服务器 13 | * access_token保存在内存中,过期则自动刷新 14 | * 此中控服务器采用单例模式,提供单一的访问点,并且持有全局唯一的accessToken对象 15 | * 采用这种模式而不是AccessToken提供全局唯一访问是 16 | * 因为AccessToken需要为其他类型的中控服务器提供服务, 17 | * 比如是定时器刷新存数据库或者文件之类的就不需要提供全局唯一 18 | * @author ChengNing 19 | * @date 2015年1月8日 20 | */ 21 | public class AccessTokenMemServer implements IServer{ 22 | 23 | 24 | private static AccessTokenMemServer tokenServer = new AccessTokenMemServer(); 25 | 26 | private AccessToken accessToken = new AccessToken(); 27 | 28 | private int requestTimes = 1;//token请求失败后重新请求的次数 29 | 30 | /** 31 | * 私有构造 32 | */ 33 | private AccessTokenMemServer(){ 34 | //获取新的token 35 | refresh(); 36 | } 37 | 38 | /** 39 | * token中控服务器实例 40 | * @return 中控服务器实例 41 | */ 42 | public static AccessTokenMemServer instance(){ 43 | return tokenServer; 44 | } 45 | 46 | /** 47 | * 通过中控服务器得到token 48 | * @return 49 | */ 50 | private AccessToken accessToken(){ 51 | //没有可用的token,则去刷新 52 | if(!this.accessToken.isValid()){ 53 | refresh(); 54 | } 55 | return this.accessToken; 56 | } 57 | 58 | /** 59 | * 通过中控服务器得到accessToken 60 | * @return 61 | */ 62 | public String token(){ 63 | return accessToken().getToken(); 64 | } 65 | 66 | /** 67 | * 服务器刷新token 68 | */ 69 | private void refresh(){ 70 | for(int i=0;i 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.response 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.response 21 | 22 | 23 | 38 | 39 |
24 | 类  25 | 26 |
27 | ArticleResponse 28 |
29 | ImageResponse 30 |
31 | MusicResponse 32 |
33 | VideoResponse 34 |
35 | VoiceResponse 36 |
37 | WechatResponse
40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/menu/MenuButton.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.menu; 2 | 3 | import java.util.List; 4 | 5 | import org.sword.wechat4j.event.EventType; 6 | 7 | 8 | import com.alibaba.fastjson.annotation.JSONField; 9 | /** 10 | * 菜单按钮 11 | * @author Zhangxs 12 | * @version 2015-7-4 13 | */ 14 | public class MenuButton { 15 | private EventType type;//菜单的响应动作类型 16 | private String name;//菜单标题,不超过16个字节,子菜单不超过40个字节 17 | private String key;//click等点击类型必须 菜单KEY值,用于消息接口推送,不超过128字节 18 | private String url;//view类型必须 网页链接,用户点击菜单可打开链接,不超过256字节 19 | private String mediaId;//media_id类型和view_limited类型必须 调用新增永久素材接口返回的合法media_id 20 | private List subButton;//子菜单,每个一级菜单最多包含5个二级菜单 21 | 22 | public EventType getType() { 23 | return type; 24 | } 25 | public void setType(EventType type) { 26 | this.type = type; 27 | } 28 | public String getName() { 29 | return name; 30 | } 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | public String getKey() { 35 | return key; 36 | } 37 | public void setKey(String key) { 38 | this.key = key; 39 | } 40 | public String getUrl() { 41 | return url; 42 | } 43 | public void setUrl(String url) { 44 | this.url = url; 45 | } 46 | @JSONField(name="media_id") 47 | public String getMediaId() { 48 | return mediaId; 49 | } 50 | @JSONField(name="media_id") 51 | public void setMediaId(String mediaId) { 52 | this.mediaId = mediaId; 53 | } 54 | @JSONField(name="sub_button") 55 | public List getSubButton() { 56 | return subButton; 57 | } 58 | @JSONField(name="sub_button") 59 | public void setSubButton(List subButton) { 60 | this.subButton = subButton; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/common/MediaFileTest.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.common; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.File; 6 | import java.io.FileOutputStream; 7 | 8 | import org.apache.log4j.Logger; 9 | import org.junit.Test; 10 | 11 | public class MediaFileTest { 12 | 13 | private static Logger logger = Logger.getLogger(MediaFileTest.class); 14 | private String uploadFile = MediaFileTest.class.getResource("").getPath() + "weixin.jpg"; 15 | private String downFile = MediaFileTest.class.getResource("").getPath() + "weixin_down.jpg"; 16 | private String mediaId; 17 | 18 | /** 19 | * 多媒体文件上传 20 | */ 21 | public void testUpload() { 22 | MediaFile mediaFile = new MediaFile(); 23 | 24 | File file = new File(uploadFile); 25 | String result = mediaFile.upload(file,MediaType.image); 26 | this.mediaId = result; 27 | 28 | assertTrue(result != null); 29 | logger.info("mediaFile upload result: " + result); 30 | } 31 | 32 | /** 33 | * 多媒体文件下载 34 | * @return 35 | */ 36 | public byte[] testDownload() { 37 | MediaFile mediaFile = new MediaFile(); 38 | byte[] b = mediaFile.download(mediaId); 39 | 40 | assertTrue(b != null); 41 | return b; 42 | } 43 | 44 | /** 45 | * 多媒体文件上传下载测试套件 46 | */ 47 | @Test 48 | public void testSuite(){ 49 | //上传得到mediaId 50 | testUpload(); 51 | //根据mediaId下载刚才上传的文件 52 | byte[] b = testDownload(); 53 | 54 | //下载的文件另存为 55 | File file = new File(downFile); 56 | FileOutputStream fStream = null; 57 | try { 58 | fStream = new FileOutputStream(file); 59 | fStream.write(b); 60 | fStream.flush(); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | } 64 | logger.info("文件下载成功,请去查看,路径" + downFile ); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/csc/Record.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.csc; 2 | 3 | /** 4 | * 聊天记录 5 | * @author Zhangxs 6 | * @date 2015-7-7 7 | * @version 8 | */ 9 | public class Record { 10 | 11 | private String openid;//用户的标识 12 | private int opercode;//操作ID(会话状态) 13 | private String text;//聊天记录 14 | private int time;//操作时间,UNIX时间戳 15 | private String worker;//客服账号 16 | 17 | public Record() { 18 | super(); 19 | } 20 | public Record(String openid, int opercode, 21 | String text, int time, String worker) { 22 | super(); 23 | this.openid = openid; 24 | this.opercode = opercode; 25 | this.text = text; 26 | this.time = time; 27 | this.worker = worker; 28 | } 29 | 30 | /** 31 | * 用户的标识 32 | * @return 33 | */ 34 | public String getOpenid() { 35 | return openid; 36 | } 37 | public void setOpenid(String openid) { 38 | this.openid = openid; 39 | } 40 | /** 41 | * 操作ID(会话状态) 42 | * @see RecordOperCode#getSessionState(int) 43 | */ 44 | public int getOpercode() { 45 | return opercode; 46 | } 47 | public void setOpercode(int opercode) { 48 | this.opercode = opercode; 49 | } 50 | /** 51 | * 聊天记录 52 | * @return 53 | */ 54 | public String getText() { 55 | return text; 56 | } 57 | public void setText(String text) { 58 | this.text = text; 59 | } 60 | /** 61 | * 操作时间,UNIX时间戳 62 | * @return 63 | */ 64 | public int getTime() { 65 | return time; 66 | } 67 | public void setTime(int time) { 68 | this.time = time; 69 | } 70 | /** 71 | * 客服账号 72 | * @return 73 | */ 74 | public String getWorker() { 75 | return worker; 76 | } 77 | public void setWorker(String worker) { 78 | this.worker = worker; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/server/AbsServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token.server; 5 | 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.apache.log4j.Logger; 8 | 9 | /** 10 | * @author ChengNing 11 | * @date 2015年1月29日 12 | */ 13 | public abstract class AbsServer implements IServer{ 14 | 15 | private static Logger logger = Logger.getLogger(AbsServer.class); 16 | 17 | protected String customerServerClass; 18 | 19 | public AbsServer(){ 20 | this.customerServerClass = getCustomerServerClass(); 21 | } 22 | 23 | @Override 24 | public String token(){ 25 | return server().token(); 26 | } 27 | /** 28 | * 得到系统可用的中控服务器 29 | * @return 正在使用的中控服务器 30 | */ 31 | public IServer server(){ 32 | if(isCustomer()) 33 | return customerServer(); 34 | return defaultServer(); 35 | } 36 | 37 | /** 38 | * 加载自定义中控服务器 39 | * @return 自定义的中控服务器 40 | */ 41 | public IServer customerServer(){ 42 | String className = customerServerClass; 43 | IServer customerServer = null; 44 | try { 45 | Class clazz = Class.forName(className); 46 | customerServer = (IServer)clazz.newInstance(); 47 | } catch (Exception e) { 48 | logger.error("系统找不到" + className); 49 | logger.error("自定义server实例化失败," + e.getMessage()); 50 | e.printStackTrace(); 51 | } 52 | return customerServer; 53 | } 54 | 55 | /** 56 | * 如果配置文件中配置了AccessTokenServer,那么使用客户自定义server 57 | * @return 是否配置了自定义中控服务器 58 | */ 59 | public boolean isCustomer(){ 60 | if(StringUtils.isBlank(customerServerClass)) 61 | return false; 62 | return true; 63 | } 64 | 65 | /** 66 | * 指定的默认中控服务器 67 | * @return 默认的中控服务器 68 | */ 69 | public abstract IServer defaultServer() ; 70 | 71 | /** 72 | * 自定义服务器的类 73 | * @return 74 | */ 75 | protected abstract String getCustomerServerClass(); 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/SendMsgTest.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | import org.sword.wechat4j.message.CustomerMsg; 7 | 8 | import com.alibaba.fastjson.JSONObject; 9 | 10 | 11 | 12 | public class SendMsgTest { 13 | CustomerMsg senMsg = new CustomerMsg(""); 14 | 15 | @Test 16 | public void testSendText() { 17 | // String expected = "Hello World"; 18 | // senMsg.sendText(expected); 19 | //// String actual = senMsg.getMsgBody(); 20 | // JSONObject json = JSONObject.parseObject(actual); 21 | // actual = json.getJSONObject("text").getString("content"); 22 | // 23 | // assertEquals(expected, actual); 24 | } 25 | 26 | // @Test 27 | // public void testSendImage() { 28 | // fail("Not yet implemented"); 29 | // } 30 | // 31 | // @Test 32 | // public void testSendVoice() { 33 | // fail("Not yet implemented"); 34 | // } 35 | // 36 | // @Test 37 | // public void testSendVideoStringStringStringString() { 38 | // fail("Not yet implemented"); 39 | // } 40 | // 41 | // @Test 42 | // public void testSendVideoVideoResponse() { 43 | // fail("Not yet implemented"); 44 | // } 45 | // 46 | // @Test 47 | // public void testSendMusicStringStringStringStringString() { 48 | // fail("Not yet implemented"); 49 | // } 50 | // 51 | // @Test 52 | // public void testSendMusicMusicResponse() { 53 | // fail("Not yet implemented"); 54 | // } 55 | 56 | @Test 57 | public void testsendNew() { 58 | // String expected = "Hello World"; 59 | // senMsg.sendNew("title", expected, "picUrl", "picUrl"); 60 | // String actual = senMsg.getMsgBody(); 61 | // JSONObject json = JSONObject.parseObject(actual); 62 | // actual = json.getJSONObject("news").getJSONArray("articles").getJSONObject(0).getString("description"); 63 | // 64 | // assertEquals(expected, actual); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/message/template/TemplateMsgBody.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.message.template; 5 | 6 | import java.util.List; 7 | 8 | 9 | /** 10 | * @author ChengNing 11 | * @date 2014年12月24日 12 | */ 13 | public class TemplateMsgBody { 14 | private String touser; 15 | private String templateId; 16 | private String url; 17 | private String topcolor; 18 | // private TemplateMsgData first; 19 | // private TemplateMsgData remark; 20 | // private List keynote; 21 | private List data; 22 | public String getTouser() { 23 | return touser; 24 | } 25 | public void setTouser(String touser) { 26 | this.touser = touser; 27 | } 28 | public String getTemplateId() { 29 | return templateId; 30 | } 31 | public void setTemplateId(String templateId) { 32 | this.templateId = templateId; 33 | } 34 | public String getUrl() { 35 | return url; 36 | } 37 | public void setUrl(String url) { 38 | this.url = url; 39 | } 40 | public String getTopcolor() { 41 | return topcolor; 42 | } 43 | public void setTopcolor(String topcolor) { 44 | this.topcolor = topcolor; 45 | } 46 | // public TemplateMsgData getFirst() { 47 | // return first; 48 | // } 49 | // public void setFirst(TemplateMsgData first) { 50 | // this.first = first; 51 | // } 52 | // public TemplateMsgData getRemark() { 53 | // return remark; 54 | // } 55 | // public void setRemark(TemplateMsgData remark) { 56 | // this.remark = remark; 57 | // } 58 | // public List getKeynote() { 59 | // return keynote; 60 | // } 61 | // public void setKeynote(List keynote) { 62 | // this.keynote = keynote; 63 | // } 64 | public List getData() { 65 | return data; 66 | } 67 | public void setData(List data) { 68 | this.data = data; 69 | } 70 | 71 | 72 | 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/token/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.token 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.token 21 | 22 | 23 | 36 | 37 |
24 | 类  25 | 26 |
27 | AccessToken 28 |
29 | Ticket 30 |
31 | Token 32 |
33 | TokenListener 34 |
35 | TokenProxy
38 | 39 | 40 | 41 | 42 | 47 | 48 |
43 | 枚举  44 | 45 |
46 | TicketType
49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/user/Qrcode.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.user; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import org.sword.lang.HttpUtils; 5 | 6 | import java.io.File; 7 | import java.io.FileOutputStream; 8 | import java.net.URLEncoder; 9 | 10 | /** 11 | * 二维码 12 | * @author Zhangxs 13 | * @version 2015-7-5 14 | */ 15 | public class Qrcode { 16 | //通过ticket换取二维码 17 | private static final String SHOWQRCODE_POST_URL = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket="; 18 | private String ticket;// 获取的二维码ticket,凭借此ticket可以在有效时间内换取二维码。 19 | private Integer expireSeconds;// 二维码的有效时间,以秒为单位。最大不超过1800。 20 | private String url;// 二维码图片解析后的地址,开发者可根据该地址自行生成需要的二维码图片 21 | public String getTicket() { 22 | return ticket; 23 | } 24 | public void setTicket(String ticket) { 25 | this.ticket = ticket; 26 | } 27 | @JSONField(name="expire_seconds") 28 | public Integer getExpireSeconds() { 29 | return expireSeconds; 30 | } 31 | @JSONField(name="expire_seconds") 32 | public void setExpireSeconds(Integer expireSeconds) { 33 | this.expireSeconds = expireSeconds; 34 | } 35 | public String getUrl() { 36 | return url; 37 | } 38 | public void setUrl(String url) { 39 | this.url = url; 40 | } 41 | 42 | /** 43 | * 换取二维码 44 | * @param qrcodeFile 二维码存储路径 45 | */ 46 | public void getQrcode(String qrcodeFile){ 47 | try { 48 | byte[] b = HttpUtils.getFile(SHOWQRCODE_POST_URL + URLEncoder.encode(ticket, "UTF-8")); 49 | File file = new File(qrcodeFile); 50 | FileOutputStream fStream = new FileOutputStream(file); 51 | fStream.write(b); 52 | fStream.flush(); 53 | fStream.close(); 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | 59 | /** 60 | * 通过二维码获取二维码URL 61 | * @return 62 | */ 63 | public String getQrcodeUrl(){ 64 | return SHOWQRCODE_POST_URL + ticket; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/menu/MenuManager.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.menu; 2 | 3 | 4 | 5 | import org.apache.log4j.Logger; 6 | import org.sword.lang.HttpUtils; 7 | import org.sword.wechat4j.exception.WeChatException; 8 | import org.sword.wechat4j.token.TokenProxy; 9 | import org.sword.wechat4j.util.WeChatUtil; 10 | 11 | import com.alibaba.fastjson.JSON; 12 | import com.alibaba.fastjson.JSONObject; 13 | /** 14 | * 微信菜单操作 15 | * @author Zhangxs 16 | * @version 2015-7-4 17 | */ 18 | public class MenuManager { 19 | private static Logger logger = Logger.getLogger(MenuManager.class); 20 | 21 | private static final String MENU_CREATE_POST_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="; 22 | private static final String MENU_GET_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token="; 23 | private static final String MENU_DEL_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token="; 24 | 25 | private String accessToken; 26 | public MenuManager() { 27 | this.accessToken = TokenProxy.accessToken(); 28 | } 29 | /** 30 | * 创建菜单 31 | * @throws WeChatException 32 | */ 33 | public void create(Menu menu) throws WeChatException{ 34 | logger.info("创建菜单"); 35 | String resultStr = HttpUtils.post(MENU_CREATE_POST_URL+this.accessToken, JSON.toJSONString(menu)); 36 | WeChatUtil.isSuccess(resultStr); 37 | } 38 | 39 | /** 40 | * 查询菜单 41 | */ 42 | public Menu getMenu() { 43 | logger.info("查询菜单"); 44 | String resultStr = HttpUtils.get(MENU_GET_GET_URL+this.accessToken); 45 | try { 46 | WeChatUtil.isSuccess(resultStr); 47 | } catch (WeChatException e) { 48 | e.printStackTrace(); 49 | return null; 50 | } 51 | JSONObject menuObject = JSONObject.parseObject(resultStr); 52 | Menu menu = menuObject.getObject("menu", Menu.class); 53 | return menu; 54 | } 55 | /** 56 | * 删除菜单 57 | * @throws WeChatException 58 | */ 59 | public void delete() throws WeChatException{ 60 | logger.info("删除菜单"); 61 | String resultStr = HttpUtils.get(MENU_DEL_GET_URL+this.accessToken); 62 | WeChatUtil.isSuccess(resultStr); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/WechatTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j; 5 | 6 | 7 | 8 | import org.junit.After; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | 13 | /** 14 | * @author ChengNing 15 | * @date 2014年12月7日 16 | */ 17 | public class WechatTest { 18 | 19 | private String url = "http://localhost:8080/phdc/lejian?signature=de8de4d90ab29dc1edca1d80863115e5385e25aa×tamp=1418008326&nonce=1917848460"; 20 | 21 | 22 | /** 23 | * @throws java.lang.Exception 24 | */ 25 | @Before 26 | public void setUp() throws Exception { 27 | } 28 | 29 | /** 30 | * @throws java.lang.Exception 31 | */ 32 | @After 33 | public void tearDown() throws Exception { 34 | } 35 | 36 | @Test 37 | public void textTest() { 38 | // HttpClient client = new HttpClient(); 39 | // PostMethod post = new PostMethod(url); 40 | // post.setRequestBody("1418007611"); 41 | // 42 | // String expected = "test ok"; 43 | // String actual = ""; 44 | // try { 45 | // client.executeMethod(post); 46 | // actual = post.getResponseBodyAsString(); 47 | // } catch (Exception e) { 48 | // e.printStackTrace(); 49 | // } 50 | // Assert.assertEquals(expected, actual); 51 | } 52 | 53 | @Test 54 | public void linkTest(){ 55 | // HttpClient client = new HttpClient(); 56 | // PostMethod post = new PostMethod(url); 57 | // post.setRequestBody("<![CDATA[test ok]]>12345678901234561418007611"); 58 | // 59 | // String expected = "test ok"; 60 | // String actual = ""; 61 | // try { 62 | // client.executeMethod(post); 63 | // actual = post.getResponseBodyAsString(); 64 | // } catch (Exception e) { 65 | // e.printStackTrace(); 66 | // } 67 | // Assert.assertEquals(expected, actual); 68 | } 69 | 70 | @Test 71 | public void clickTest(){ 72 | 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/user/AccountTest.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.user; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | /** 7 | * 账号管理接口测试 8 | * 9 | * @author Zhangxs 10 | * @version 2015-7-5 11 | */ 12 | public class AccountTest { 13 | 14 | private AccountManager accountManager; 15 | 16 | @Before 17 | public void init() { 18 | accountManager = new AccountManager(); 19 | } 20 | 21 | /** 22 | * 创建临时二维码 23 | */ 24 | @Test 25 | public void createQrcodeTemporary() { 26 | long sceneId = 100; 27 | int expireSeconds = 1860; 28 | Qrcode qrcode = accountManager.createQrcodeTemporary(sceneId, expireSeconds); 29 | System.out.println("二维码有效时间:" + qrcode.getExpireSeconds()); 30 | System.out.println("二维码Ticket:" + qrcode.getTicket()); 31 | System.out.println("二维码图片解析后的地址:" + qrcode.getUrl()); 32 | } 33 | 34 | /** 35 | * 创建永久二维码 36 | */ 37 | @Test 38 | public void createQrcodePerpetualstr() { 39 | String sceneStr = "wtb"; 40 | Qrcode qrcode = accountManager.createQrcodePerpetualstr(sceneStr); 41 | System.out.println("二维码Ticket:" + qrcode.getTicket()); 42 | System.out.println("二维码图片解析后的地址:" + qrcode.getUrl()); 43 | } 44 | 45 | /** 46 | * 创建永久二维码 47 | */ 48 | @Test 49 | public void createQrcodePerpetual() { 50 | int sceneId = 123; 51 | Qrcode qrcode = accountManager.createQrcodePerpetual(sceneId); 52 | System.out.println("二维码Ticket:" + qrcode.getTicket()); 53 | System.out.println("二维码图片解析后的地址:" + qrcode.getUrl()); 54 | 55 | } 56 | 57 | /** 58 | * 长链接转短链接接口 59 | */ 60 | @Test 61 | public void shortUrl() { 62 | String longUrl = "https://github.com/Zhangys-hh/wechat4j"; 63 | String shortUrl = accountManager.shortUrl(longUrl); 64 | System.out.println("转换后的Url:" + shortUrl); 65 | } 66 | /** 67 | * 获取二维码图片 68 | */ 69 | // @Test 70 | // public void getQrcode(){ 71 | // String ticket="gQHE7zoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL1RVd1BodWpsQkJSOUdGeW5JMkp6AAIEZUaZVQMERAcAAA=="; 72 | // String qrcodeFile="D://qrcode.png"; 73 | // AccountManager.getQrcode(ticket, qrcodeFile); 74 | // } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/token/server/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | org.sword.wechat4j.token.server 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.sword.wechat4j.token.server 21 | 22 | 23 | 32 | 33 |
24 | 接口  25 | 26 |
27 | IServer 28 |
29 | TicketServer 30 |
31 | TokenServer
34 | 35 | 36 | 37 | 38 | 53 | 54 |
39 | 类  40 | 41 |
42 | AbsServer 43 |
44 | AccessTokenMemServer 45 |
46 | AccessTokenServer 47 |
48 | CustomerServer 49 |
50 | JsApiTicketMemServer 51 |
52 | JsApiTicketServer
55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/common/Config.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.common; 5 | 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.util.Properties; 9 | 10 | import org.apache.log4j.Logger; 11 | 12 | /** 13 | * @author ChengNing 14 | * @date 2014年12月8日 15 | */ 16 | public class Config { 17 | 18 | private static Logger logger = Logger.getLogger(Config.class); 19 | 20 | private static final String configFile = "/wechat4j.properties"; 21 | 22 | private String url; 23 | private String token; 24 | private String encodingAESKey; 25 | private String appid; 26 | private String appSecret; 27 | private String accessTokenServer; 28 | private String jsApiTicketServer; 29 | private static Config config = new Config(); 30 | 31 | private Config(){ 32 | Properties p = new Properties(); 33 | InputStream inStream = this.getClass().getResourceAsStream(configFile); 34 | if(inStream == null){ 35 | logger.error("根目录下找不到wechat4j.properties文件"); 36 | return; 37 | } 38 | try { 39 | p.load(inStream); 40 | this.url = p.getProperty("wechat.url") == null ? null : p.getProperty("wechat.url").trim(); 41 | this.encodingAESKey = p.getProperty("wechat.encodingaeskey") == null ? null : p.getProperty("wechat.encodingaeskey").trim(); 42 | this.token = p.getProperty("wechat.token") == null ? null : p.getProperty("wechat.token").trim(); 43 | this.appid = p.getProperty("wechat.appid") == null ? null: p.getProperty("wechat.appid").trim(); 44 | this.appSecret = p.getProperty("wechat.appsecret") == null ? null : p.getProperty("wechat.appsecret").trim(); 45 | this.accessTokenServer = p.getProperty("wechat.accessToken.server.class") == null ? null : p.getProperty("wechat.accessToken.server.class").trim(); 46 | this.jsApiTicketServer = p.getProperty("wechat.ticket.jsapi.server.class") == null ? null : p.getProperty("wechat.ticket.jsapi.server.class").trim(); 47 | inStream.close(); 48 | } catch (IOException e) { 49 | logger.error("load wechat4j.properties error,class根目录下找不到wechat4j.properties文件"); 50 | e.printStackTrace(); 51 | } 52 | logger.info("load wechat4j.properties success"); 53 | } 54 | 55 | public static Config instance(){ 56 | return config; 57 | } 58 | public String getToken() { 59 | return token; 60 | } 61 | public String getAppid() { 62 | return appid; 63 | } 64 | public String getAppSecret() { 65 | return appSecret; 66 | } 67 | 68 | public String getUrl() { 69 | return url; 70 | } 71 | 72 | public String getEncodingAESKey() { 73 | return encodingAESKey; 74 | } 75 | 76 | public String getAccessTokenServer(){ 77 | return accessTokenServer; 78 | } 79 | 80 | public String getJsApiTicketServer() { 81 | return jsApiTicketServer; 82 | } 83 | 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/csc/CustomerServices.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.csc; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | 5 | /** 6 | * 客服基本信息 7 | * @author Zhangxs 8 | * @date 2015-7-8 9 | * @version 10 | */ 11 | public class CustomerServices { 12 | private String kfAccount;//完整客服账号,格式为:账号前缀@公众号微信号 13 | private String kfId;// 客服工号 14 | private String kfHeadimgurl;//客服头像url 15 | private String kfNick;// 客服昵称 16 | private Integer status;// 客服在线状态 17 | private Integer autoAccept;// 客服设置的最大自动接入数 18 | private Integer acceptedCase;// 客服当前正在接待的会话数 19 | 20 | /** 21 | * 完整客服账号
22 | * 格式为:账号前缀@公众号微信号 23 | * @return 24 | */ 25 | @JSONField(name="kf_account") 26 | public String getKfAccount() { 27 | return kfAccount; 28 | } 29 | @JSONField(name="kf_account") 30 | public void setKfAccount(String kfAccount) { 31 | this.kfAccount = kfAccount; 32 | } 33 | /** 34 | * 客服工号 35 | * @return 36 | */ 37 | @JSONField(name="kf_id") 38 | public String getKfId() { 39 | return kfId; 40 | } 41 | @JSONField(name="kf_id") 42 | public void setKfId(String kfId) { 43 | this.kfId = kfId; 44 | } 45 | /** 46 | * 客服头像url 47 | * @return 48 | */ 49 | @JSONField(name="kf_headimgurl") 50 | public String getKfHeadimgurl() { 51 | return kfHeadimgurl; 52 | } 53 | @JSONField(name="kf_headimgurl") 54 | public void setKfHeadimgurl(String kfHeadimgurl) { 55 | this.kfHeadimgurl = kfHeadimgurl; 56 | } 57 | /** 58 | * 客服昵称 59 | * @return 60 | */ 61 | @JSONField(name="kf_nick") 62 | public String getKfNick() { 63 | return kfNick; 64 | } 65 | @JSONField(name="kf_nick") 66 | public void setKfNick(String kfNick) { 67 | this.kfNick = kfNick; 68 | } 69 | /** 70 | * 客服在线状态
71 | * 1:pc在线
72 | * 2:手机在线
73 | * 3:pc和手机同时在线 74 | * @return 75 | */ 76 | @JSONField(name="status") 77 | public Integer getStatus() { 78 | return status; 79 | } 80 | @JSONField(name="status") 81 | public void setStatus(Integer status) { 82 | this.status = status; 83 | } 84 | /** 85 | * 客服设置的最大自动接入数 86 | * @return 87 | */ 88 | @JSONField(name="auto_accept") 89 | public Integer getAutoAccept() { 90 | return autoAccept; 91 | } 92 | @JSONField(name="auto_accept") 93 | public void setAutoAccept(Integer autoAccept) { 94 | this.autoAccept = autoAccept; 95 | } 96 | /** 97 | * 客服当前正在接待的会话数 98 | * @return 99 | */ 100 | @JSONField(name="accepted_case") 101 | public Integer getAcceptedCase() { 102 | return acceptedCase; 103 | } 104 | @JSONField(name="accepted_case") 105 | public void setAcceptedCase(Integer acceptedCase) { 106 | this.acceptedCase = acceptedCase; 107 | } 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | sword.org 5 | wechat4j 6 | 1.2.0 7 | 8 | 9 | 10 | commons-codec 11 | commons-codec 12 | 1.10 13 | 14 | 15 | 16 | org.apache.commons 17 | commons-lang3 18 | 3.4 19 | 20 | 21 | org.apache.httpcomponents 22 | httpclient 23 | 4.5.1 24 | 25 | 26 | 27 | com.alibaba 28 | fastjson 29 | 1.2.7 30 | 31 | 32 | 33 | log4j 34 | log4j 35 | 1.2.17 36 | 37 | 38 | 39 | javax.servlet 40 | javax.servlet-api 41 | 3.1.0 42 | 43 | 44 | 45 | sword.org 46 | sword-lang 47 | 2.0.0 48 | 49 | 50 | 51 | junit 52 | junit 53 | 4.12 54 | test 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-compiler-plugin 63 | 3.5 64 | 65 | 1.5 66 | 1.5 67 | 68 | 69 | 70 | org.apache.maven.plugins 71 | maven-surefire-plugin 72 | 2.19 73 | 74 | 75 | true 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /doc/api/overview-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 概述列表 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 |
23 |
26 | 27 | 28 | 29 | 59 | 60 |
所有类 30 |

31 | 32 | 软件包 33 |
34 | org.sword.wechat4j 35 |
36 | org.sword.wechat4j.common 37 |
38 | org.sword.wechat4j.event 39 |
40 | org.sword.wechat4j.message 41 |
42 | org.sword.wechat4j.message.template 43 |
44 | org.sword.wechat4j.param 45 |
46 | org.sword.wechat4j.request 47 |
48 | org.sword.wechat4j.response 49 |
50 | org.sword.wechat4j.token 51 |
52 | org.sword.wechat4j.token.server 53 |
54 | org.sword.wechat4j.token.timer 55 |
56 | org.sword.wechat4j.user 57 |
58 |

61 | 62 |

63 |   64 | 65 | 66 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/common/MediaFile.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.common; 5 | 6 | import java.io.File; 7 | 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.sword.lang.HttpUtils; 10 | import org.sword.wechat4j.token.TokenProxy; 11 | 12 | import com.alibaba.fastjson.JSONObject; 13 | 14 | /** 15 | * 上传下载多媒体文件 16 | * @author ChengNing 17 | * @date 2015年1月6日 18 | */ 19 | public class MediaFile { 20 | 21 | private static final String UPLOAD = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token="; 22 | private static final String DOWNLOAD = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token="; 23 | private static final String PARAM_FILE = "media"; 24 | private static final String PARAM_MEDIA_ID = "media_id"; 25 | private static final String PARAM_TYPE = "type"; 26 | private static final String PARAM_CREATE_TIME = "created_at"; 27 | 28 | private MediaType type; 29 | private File file; 30 | private String mediaId; //3天失效 31 | private String createdTimestamp;//文件创建时间戳,上传之后返回 32 | 33 | 34 | /** 35 | * 文件上传url 36 | * @return 37 | */ 38 | private String uploadUrl(){ 39 | String url = UPLOAD + TokenProxy.accessToken() + "&" 40 | + PARAM_TYPE + "=" + this.type.name(); 41 | return url; 42 | } 43 | 44 | /** 45 | * 文件下载url 46 | * @return 47 | */ 48 | private String downloadUrl(){ 49 | String url = DOWNLOAD + TokenProxy.accessToken() + "&" 50 | + PARAM_MEDIA_ID + "=" + this.mediaId; 51 | return url; 52 | } 53 | 54 | /** 55 | * 文件上传 56 | * success: {"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789} 57 | * error: {"errcode":40004,"errmsg":"invalid media type"} 58 | * @return media_id 成功返回 media_id, 失败返回null 59 | */ 60 | public String upload(File file,MediaType type){ 61 | this.file = file; 62 | this.type = type; 63 | String url = uploadUrl(); 64 | String result = HttpUtils.postFile(url,PARAM_FILE, file); 65 | parseUploadResult(result); 66 | if(StringUtils.isNotBlank(this.mediaId)) 67 | return this.mediaId; 68 | return null; 69 | } 70 | 71 | private void parseUploadResult(String result){ 72 | JSONObject jsonObject = JSONObject.parseObject(result); 73 | if(jsonObject.containsKey(PARAM_MEDIA_ID)){ 74 | this.mediaId = jsonObject.getString(PARAM_MEDIA_ID); 75 | this.createdTimestamp = jsonObject.getString(PARAM_CREATE_TIME); 76 | } 77 | else{ 78 | this.mediaId = null; 79 | this.createdTimestamp = null; 80 | } 81 | } 82 | 83 | /** 84 | * 文件下载 85 | * @return byte[] 86 | */ 87 | public byte[] download(String mediaId){ 88 | this.mediaId = mediaId; 89 | String url = downloadUrl(); 90 | byte[] fb = HttpUtils.getFile(url); 91 | if(fb == null || fb.length == 0) 92 | return null; 93 | return fb; 94 | } 95 | 96 | public MediaType getType() { 97 | return type; 98 | } 99 | 100 | public String getMediaId() { 101 | return mediaId; 102 | } 103 | 104 | public String getCreatedTimestamp() { 105 | return createdTimestamp; 106 | } 107 | 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/Wechat.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | 8 | /** 9 | * @author ChengNing 10 | * @date 2014年12月7日 11 | */ 12 | public class Wechat extends WechatSupport{ 13 | 14 | public Wechat(HttpServletRequest request) { 15 | super(request); 16 | } 17 | 18 | @Override 19 | protected void onText() { 20 | // TODO Auto-generated method stub 21 | 22 | } 23 | 24 | @Override 25 | protected void onImage() { 26 | // TODO Auto-generated method stub 27 | 28 | } 29 | 30 | @Override 31 | protected void onVoice() { 32 | // TODO Auto-generated method stub 33 | 34 | } 35 | 36 | @Override 37 | protected void onVideo() { 38 | // TODO Auto-generated method stub 39 | 40 | } 41 | 42 | @Override 43 | protected void onLocation() { 44 | // TODO Auto-generated method stub 45 | 46 | } 47 | 48 | @Override 49 | protected void onLink() { 50 | // TODO Auto-generated method stub 51 | 52 | } 53 | 54 | @Override 55 | protected void onUnknown() { 56 | // TODO Auto-generated method stub 57 | 58 | } 59 | 60 | @Override 61 | protected void click() { 62 | // TODO Auto-generated method stub 63 | 64 | } 65 | 66 | @Override 67 | protected void subscribe() { 68 | // TODO Auto-generated method stub 69 | 70 | } 71 | 72 | @Override 73 | protected void unSubscribe() { 74 | // TODO Auto-generated method stub 75 | 76 | } 77 | 78 | @Override 79 | protected void scan() { 80 | // TODO Auto-generated method stub 81 | 82 | } 83 | 84 | @Override 85 | protected void location() { 86 | // TODO Auto-generated method stub 87 | 88 | } 89 | 90 | @Override 91 | protected void view() { 92 | // TODO Auto-generated method stub 93 | 94 | } 95 | 96 | @Override 97 | protected void templateMsgCallback() { 98 | // TODO Auto-generated method stub 99 | 100 | } 101 | 102 | @Override 103 | protected void scanCodePush() { 104 | // TODO Auto-generated method stub 105 | 106 | } 107 | 108 | @Override 109 | protected void scanCodeWaitMsg() { 110 | // TODO Auto-generated method stub 111 | 112 | } 113 | 114 | @Override 115 | protected void picSysPhoto() { 116 | // TODO Auto-generated method stub 117 | 118 | } 119 | 120 | @Override 121 | protected void picPhotoOrAlbum() { 122 | // TODO Auto-generated method stub 123 | 124 | } 125 | 126 | @Override 127 | protected void picWeixin() { 128 | // TODO Auto-generated method stub 129 | 130 | } 131 | 132 | @Override 133 | protected void locationSelect() { 134 | // TODO Auto-generated method stub 135 | 136 | } 137 | 138 | @Override 139 | protected void onShortVideo() { 140 | // TODO Auto-generated method stub 141 | 142 | } 143 | 144 | @Override 145 | protected void kfCreateSession() { 146 | // TODO Auto-generated method stub 147 | 148 | } 149 | 150 | @Override 151 | protected void kfCloseSession() { 152 | // TODO Auto-generated method stub 153 | 154 | } 155 | 156 | @Override 157 | protected void kfSwitchSession() { 158 | // TODO Auto-generated method stub 159 | 160 | } 161 | 162 | 163 | @Override 164 | protected void orderPaid() { 165 | // TODO Auto-generated method stub 166 | 167 | } 168 | 169 | 170 | 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/response/WechatResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.response; 5 | 6 | import java.util.List; 7 | 8 | import javax.xml.bind.annotation.XmlElement; 9 | import javax.xml.bind.annotation.XmlElementWrapper; 10 | import javax.xml.bind.annotation.XmlRootElement; 11 | 12 | 13 | /** 14 | * 用于回复的基本消息类型 15 | * @author ChengNing 16 | * @date 2014-12-4 17 | */ 18 | @XmlRootElement(name="xml") 19 | public class WechatResponse { 20 | 21 | private String ToUserName; 22 | private String FromUserName; 23 | private String CreateTime; 24 | private String MsgType; 25 | private String Content; 26 | private String ArticleCount; 27 | 28 | private ImageResponse Image; 29 | private VoiceResponse Voice; 30 | private VideoResponse Video; 31 | private MusicResponse Music; 32 | private List article; 33 | private TransInfoResponse TransInfo; 34 | 35 | 36 | 37 | public static String[] CDATA_TAG = {"ToUserName", 38 | "FromUserName","MsgType","Event","MsgId","Content","MediaId","Title","Description","MusicUrl","HQMusicUrl","ThumbMediaId", 39 | "PicUrl","Url" 40 | }; 41 | 42 | 43 | @XmlElement(name="ToUserName") 44 | public String getToUserName() { 45 | return ToUserName; 46 | } 47 | public void setToUserName(String toUserName) { 48 | ToUserName = toUserName; 49 | } 50 | @XmlElement(name="FromUserName") 51 | public String getFromUserName() { 52 | return FromUserName; 53 | } 54 | public void setFromUserName(String fromUserName) { 55 | FromUserName = fromUserName; 56 | } 57 | @XmlElement(name="CreateTime") 58 | public String getCreateTime() { 59 | return CreateTime; 60 | } 61 | public void setCreateTime(String createTime) { 62 | CreateTime = createTime; 63 | } 64 | @XmlElement(name="MsgType") 65 | public String getMsgType() { 66 | return MsgType; 67 | } 68 | public void setMsgType(String msgType) { 69 | MsgType = msgType; 70 | } 71 | @XmlElement(name="Content") 72 | public String getContent() { 73 | return Content; 74 | } 75 | public void setContent(String content) { 76 | Content = content; 77 | } 78 | @XmlElement(name="ArticleCount") 79 | public String getArticleCount() { 80 | return ArticleCount; 81 | } 82 | public void setArticleCount(String articleCount) { 83 | ArticleCount = articleCount; 84 | } 85 | 86 | @XmlElement(name="Image") 87 | public ImageResponse getImage() { 88 | return Image; 89 | } 90 | public void setImage(ImageResponse image) { 91 | Image = image; 92 | } 93 | @XmlElement(name="Voice") 94 | public VoiceResponse getVoice() { 95 | return Voice; 96 | } 97 | public void setVoice(VoiceResponse voice) { 98 | Voice = voice; 99 | } 100 | @XmlElement(name="Video") 101 | public VideoResponse getVideo() { 102 | return Video; 103 | } 104 | public void setVideo(VideoResponse video) { 105 | Video = video; 106 | } 107 | @XmlElement(name="Music") 108 | public MusicResponse getMusic() { 109 | return Music; 110 | } 111 | public void setMusic(MusicResponse music) { 112 | Music = music; 113 | } 114 | @XmlElementWrapper(name="Articles") 115 | @XmlElement(name="item") 116 | public List getArticle() { 117 | return article; 118 | } 119 | public void setArticle(List article) { 120 | this.article = article; 121 | } 122 | @XmlElement(name="TransInfo") 123 | public TransInfoResponse getTransInfo() { 124 | return TransInfo; 125 | } 126 | public void setTransInfo(TransInfoResponse transInfo) { 127 | TransInfo = transInfo; 128 | } 129 | 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/token/Token.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.token; 5 | 6 | import java.util.Date; 7 | 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.apache.log4j.Logger; 10 | import org.sword.lang.HttpUtils; 11 | 12 | 13 | import com.alibaba.fastjson.JSONObject; 14 | 15 | /** 16 | * @author ChengNing 17 | * @date 2015年1月29日 18 | */ 19 | public abstract class Token { 20 | private static Logger logger = Logger.getLogger(Token.class); 21 | 22 | private String token; //token 23 | private long expires; //token有效时间 24 | 25 | private long tokenTime; //token产生时间 26 | private int redundance = 10*1000; //冗余时间,提前10秒就去请求新的token 27 | 28 | /** 29 | * 得到access token 30 | */ 31 | public String getToken(){ 32 | return this.token; 33 | } 34 | 35 | /** 36 | * 得到有效时间 37 | */ 38 | public long getExpires() { 39 | return expires; 40 | } 41 | 42 | /** 43 | * 请求信的access token 44 | * http请求方式: GET 45 | https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET 46 | {"access_token":"ACCESS_TOKEN","expires_in":7200} 47 | {"errcode":40013,"errmsg":"invalid appid"} 48 | */ 49 | public boolean request(){ 50 | String url = accessTokenUrl(); 51 | String result = HttpUtils.get(url); 52 | if(StringUtils.isBlank(result)) 53 | return false; 54 | if(!parseData(result)){ 55 | return false; 56 | } 57 | logger.info("token获取成功"); 58 | return true; 59 | } 60 | 61 | /** 62 | * 解析token数据 63 | * @param data 64 | * @return 65 | */ 66 | private boolean parseData(String data){ 67 | JSONObject jsonObject = JSONObject.parseObject(data); 68 | String tokenName = tokenName(); 69 | String expiresInName = expiresInName(); 70 | try { 71 | String token = jsonObject.get(tokenName).toString(); 72 | if(StringUtils.isBlank(token)){ 73 | logger.error("token获取失败,获取结果" + data); 74 | return false; 75 | } 76 | this.token = token; 77 | this.tokenTime = (new Date()).getTime(); 78 | String expiresIn = jsonObject.get(expiresInName).toString(); 79 | if(StringUtils.isBlank(expiresIn)){ 80 | logger.error("token获取失败,获取结果" + expiresIn); 81 | return false; 82 | } 83 | else{ 84 | this.expires = Long.valueOf(expiresIn); 85 | } 86 | } catch (Exception e) { 87 | logger.error("token 结果解析失败,token参数名称: " + tokenName 88 | + "有效期参数名称:" + expiresInName 89 | + "token请求结果:" + data); 90 | e.printStackTrace(); 91 | return false; 92 | } 93 | return true; 94 | } 95 | 96 | /** 97 | * token的参数名称 98 | * @return 99 | */ 100 | protected abstract String tokenName(); 101 | /** 102 | * expireIn的参数名称 103 | * @return 104 | */ 105 | protected abstract String expiresInName(); 106 | 107 | /** 108 | * 组织accesstoken的请求utl 109 | * @return 110 | */ 111 | protected abstract String accessTokenUrl(); 112 | 113 | /** 114 | * accessToken 是否有效 115 | * @return true:有效,false: 无效 116 | */ 117 | public boolean isValid(){ 118 | //黑名单判定法 119 | if(StringUtils.isBlank(this.token)) 120 | return false; 121 | if(this.expires <= 0) 122 | return false; 123 | //过期 124 | if(isExpire()) 125 | return false; 126 | return true; 127 | } 128 | 129 | /** 130 | * 是否过期 131 | * @return true 过期 false:有效 132 | */ 133 | private boolean isExpire(){ 134 | Date currentDate = new Date(); 135 | long currentTime = currentDate.getTime(); 136 | long expiresTime = expires * 1000 - redundance; 137 | //判断是否过期 138 | if((tokenTime + expiresTime) > currentTime) 139 | return false; 140 | return true; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/message/TemplateMsg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 对应接口文档地址 3 | * http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html 4 | */ 5 | package org.sword.wechat4j.message; 6 | 7 | import org.apache.log4j.Logger; 8 | import org.sword.lang.HttpUtils; 9 | import org.sword.wechat4j.message.template.TemplateMsgBody; 10 | import org.sword.wechat4j.message.template.TemplateMsgData; 11 | import org.sword.wechat4j.token.TokenProxy; 12 | 13 | import com.alibaba.fastjson.JSONObject; 14 | 15 | /** 16 | * 模板消息接口 17 | * @author ChengNing 18 | * @date 2014年12月24日 19 | */ 20 | public class TemplateMsg { 21 | 22 | private static Logger logger = Logger.getLogger(TemplateMsg.class); 23 | 24 | //设置所属行业接口地址 25 | public static final String SET_INDUSTRY_URL = "https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token="; 26 | //添加模板id接口地址 27 | public static final String GET_TEMPLATE_ID_URL = "https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token="; 28 | //发送模板消息接口地址 29 | public static final String SEND_MSG_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="; 30 | 31 | private String accessToken; 32 | 33 | public TemplateMsg(){ 34 | this.accessToken = TokenProxy.accessToken(); 35 | } 36 | 37 | /** 38 | * 设置所属行业 39 | * 接口说明中没有给出 40 | */ 41 | public void setIndustry(String...industrys){ 42 | String url = SET_INDUSTRY_URL + this.accessToken; 43 | JSONObject json = new JSONObject(); 44 | for(int i=0;i openids = manager.allSubscriber(); 22 | for (String openid : openids) { 23 | System.out.println(openid); 24 | } 25 | } 26 | /** 27 | * 获取前10000个关注者列表 28 | */ 29 | @Test 30 | public void subscriberList(){ 31 | Follwers follwers = manager.subscriberList(); 32 | System.out.println("关注者数量:"+follwers.getCount()); 33 | } 34 | /** 35 | * 设置用户备注名 36 | */ 37 | @Test 38 | public void updateRemark(){ 39 | try { 40 | manager.updateRemark("otweTt8vRASrS-zji8v4YSStH-cc", "张永帅"); 41 | System.out.println("备注名设置成功"); 42 | } catch (WeChatException e) { 43 | System.out.println("备注名设置失败"); 44 | e.printStackTrace(); 45 | } 46 | } 47 | /** 48 | * 获取用户基本信息 49 | */ 50 | @Test 51 | public void getUserInfo(){ 52 | String openId = "otweTt8vRASrS-zji8v4YSStH-cc"; 53 | User user = manager.getUserInfo(openId); 54 | System.out.println(user.toString()); 55 | user = manager.getUserInfo(openId,LanguageType.en); 56 | System.out.println(user.toString()); 57 | } 58 | /** 59 | * 创建分组 60 | */ 61 | @Test 62 | public void createGroup(){ 63 | try { 64 | manager.createGroup("分组1"); 65 | System.out.println("创建分组成功"); 66 | } catch (WeChatException e) { 67 | System.out.println("创建分组失败"); 68 | e.printStackTrace(); 69 | } 70 | 71 | } 72 | /** 73 | * 查询所有分组 74 | */ 75 | @Test 76 | public void getGroup(){ 77 | List groups = manager.getGroup(); 78 | for (Group group : groups) { 79 | System.out.println("分组Id:"+group.getId()); 80 | System.out.println("分组名称:"+group.getName()); 81 | System.out.println("分组人数:"+group.getCount()); 82 | } 83 | } 84 | /** 85 | * 查询用户所在分组 86 | */ 87 | @Test 88 | public void getIdGroup(){ 89 | String openId ="otweTt8vRASrS-zji8v4YSStH-cc"; 90 | int groupId = manager.getIdGroup(openId); 91 | System.out.println("分组Id:"+groupId); 92 | } 93 | /** 94 | * 修改分组名 95 | */ 96 | @Test 97 | public void updateGroup(){ 98 | int groupId=106; 99 | String name = "分组4"; 100 | try { 101 | manager.updateGroup(groupId, name); 102 | System.out.println("操作成功"); 103 | } catch (WeChatException e) { 104 | System.out.println("操作失败"); 105 | e.printStackTrace(); 106 | } 107 | } 108 | /** 109 | * 移动用户分组 110 | */ 111 | @Test 112 | public void membersUpdateGroup(){ 113 | int groupId = 106; 114 | String openId="otweTt8vRASrS-zji8v4YSStH-cc"; 115 | try { 116 | manager.membersUpdateGroup(openId, groupId); 117 | System.out.println("操作成功"); 118 | } catch (WeChatException e) { 119 | System.out.println("操作失败"); 120 | e.printStackTrace(); 121 | } 122 | } 123 | /** 124 | * 批量移动用户分组 125 | */ 126 | @Test 127 | public void membersDatchUpdateGroup(){ 128 | String [] openIds={"otweTt8vRASrS-zji8v4YSStH-cc","otweTt4fjjPDZtGlQx_w5XfV42sc"}; 129 | int groupId=103; 130 | try { 131 | manager.membersDatchUpdateGroup(openIds, groupId); 132 | System.out.println("操作成功"); 133 | } catch (WeChatException e) { 134 | System.out.println("操作失败"); 135 | e.printStackTrace(); 136 | } 137 | } 138 | /** 139 | * 删除分组 140 | */ 141 | @Test 142 | public void deleteGroup(){ 143 | int groupId = 109; 144 | try { 145 | manager.deleteGroup(groupId); 146 | System.out.println("操作成功"); 147 | } catch (WeChatException e) { 148 | System.out.println("操作失败"); 149 | e.printStackTrace(); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/test/java/org/sword/wechat4j/menu/MenuTest.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.menu; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.sword.wechat4j.event.EventType; 9 | import org.sword.wechat4j.exception.WeChatException; 10 | /** 11 | * 微信自定义菜单接口测试 12 | * @author Zhangxs 13 | * @version 2015-7-4 14 | */ 15 | public class MenuTest { 16 | private MenuManager manager; 17 | @Before 18 | public void init(){ 19 | manager = new MenuManager(); 20 | } 21 | /** 22 | * 创建菜单 23 | */ 24 | @Test 25 | public void createMenu(){ 26 | //单击按钮 27 | MenuButton btnClick= new MenuButton(); 28 | btnClick.setName("单击按钮"); 29 | btnClick.setType(EventType.click); 30 | btnClick.setKey("单击按钮"); 31 | //跳转URL 32 | MenuButton btnView= new MenuButton(); 33 | btnView.setName("跳转URL"); 34 | btnView.setType(EventType.view); 35 | btnView.setUrl("http://www.baidu.com"); 36 | //扫码推事件 37 | MenuButton btnScanCodePush= new MenuButton(); 38 | btnScanCodePush.setName("扫码推事件"); 39 | btnScanCodePush.setType(EventType.scancode_push); 40 | btnScanCodePush.setKey("扫码推事件"); 41 | //扫码带提示 42 | MenuButton btnScanCodeWaitMsg= new MenuButton(); 43 | btnScanCodeWaitMsg.setName("扫码带提示"); 44 | btnScanCodeWaitMsg.setType(EventType.scancode_waitmsg); 45 | btnScanCodeWaitMsg.setKey("扫码带提示"); 46 | 47 | //弹出系统拍照发图 48 | MenuButton btnPicSysPhoto= new MenuButton(); 49 | btnPicSysPhoto.setName("拍照发图"); 50 | btnPicSysPhoto.setType(EventType.pic_sysphoto); 51 | btnPicSysPhoto.setKey("拍照发图"); 52 | //弹出拍照或者相册发图 53 | MenuButton btnPicPhotoOrAlbum= new MenuButton(); 54 | btnPicPhotoOrAlbum.setName("拍照/相册发图"); 55 | btnPicPhotoOrAlbum.setType(EventType.pic_photo_or_album); 56 | btnPicPhotoOrAlbum.setKey("拍照/相册发图"); 57 | //弹出微信相册发图器 58 | MenuButton btnPicWeixin= new MenuButton(); 59 | btnPicWeixin.setName("相册发图"); 60 | btnPicWeixin.setType(EventType.pic_weixin); 61 | btnPicWeixin.setKey("相册发图"); 62 | //弹出地理位置选择器 63 | MenuButton btnLocationSelect= new MenuButton(); 64 | btnLocationSelect.setName("地理位置"); 65 | btnLocationSelect.setType(EventType.location_select); 66 | btnLocationSelect.setKey("地理位置"); 67 | 68 | //下发消息(除文本消息) 69 | btnLocationSelect.setType(EventType.location_select); 70 | MenuButton btnMediaId = new MenuButton(); 71 | btnMediaId.setName(""); 72 | btnMediaId.setType(EventType.media_id); 73 | btnMediaId.setMediaId(""); 74 | //跳转图文消息URL 75 | MenuButton btnViewLimited = new MenuButton(); 76 | btnViewLimited.setName(""); 77 | btnViewLimited.setType(EventType.view_limited); 78 | btnViewLimited.setMediaId(""); 79 | 80 | List subBut1 = new ArrayList(); 81 | subBut1.add(btnScanCodePush); 82 | subBut1.add(btnScanCodeWaitMsg); 83 | subBut1.add(btnPicSysPhoto); 84 | subBut1.add(btnPicPhotoOrAlbum); 85 | subBut1.add(btnPicWeixin); 86 | List subBut2 = new ArrayList(); 87 | subBut2.add(btnClick); 88 | subBut2.add(btnView); 89 | //二级菜单 90 | MenuButton subButScanCode = new MenuButton(); 91 | subButScanCode.setName("扫码"); 92 | subButScanCode.setSubButton(subBut1); 93 | MenuButton sub1 = new MenuButton(); 94 | sub1.setName("单击"); 95 | sub1.setSubButton(subBut2); 96 | 97 | List button = new ArrayList(); 98 | button.add(sub1); 99 | button.add(subButScanCode); 100 | button.add(btnLocationSelect); 101 | Menu menu = new Menu(); 102 | menu.setButton(button); 103 | 104 | try { 105 | manager.create(menu); 106 | System.out.println("菜单创建成功"); 107 | } catch (WeChatException e) { 108 | System.out.println("菜单创建失败"); 109 | e.printStackTrace(); 110 | } 111 | } 112 | /** 113 | * 查询菜单 114 | */ 115 | @Test 116 | public void getMenu(){ 117 | Menu menu = manager.getMenu(); 118 | System.out.println(menu.getButton().size()); 119 | } 120 | /** 121 | * 删除菜单 122 | */ 123 | @Test 124 | public void delete(){ 125 | try { 126 | manager.delete(); 127 | System.out.println("菜单删除成功"); 128 | } catch (WeChatException e) { 129 | System.out.println("菜单删除失败"); 130 | e.printStackTrace(); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | wechat4j 2 | ======== 3 | 4 | ##What is wechat4j? 5 | wechat develop framework for java(微信开发框架JAVA版,最简单易用微信开发框架) 6 | 7 | ##wechat4j可以用来干什么? 8 | wechat4j是一个帮助你开发微信应用的jar包,使用它,你开发微信公众号应用只需要几秒钟的时间,完全不用关注太细节的东西。 9 | 10 | ##wechat4j快速开始 11 | 可以去下载wechat4j示例项目[wechat4jDemo](https://github.com/repoproject/wechat4jDemo),然后在其基础之上修改即可。如果你要自己搭建,那么使用wechat4j只需要三步就可以搭建微信开发环境。 12 | 1. 创建一个web工程,导入jdk和相关的web工程jar包。 13 | 2. 下载wechat4j.jar包,下载地址[wechat4j下载](https://github.com/sword-org/wechat4j/releases)。 14 | 3. 创建wechat4j配置文件,在src目录下(java根目录)创建wechat4j.properties文件,配置你微信公众号的相关信息。内容如下: 15 | ```properties 16 | #you wechat token 17 | wechat.token=token 18 | #wechat appid 19 | wechat.appid=appid 20 | #wechat app secret 21 | wechat.appsecret=secret 22 | ``` 23 | 你也可以在jar包的META-INF目录下找到wechat4j.properties.sample文件,复制到src目录下修改名称即可。wechat4j.properties配置文件的详细配置项意义参见[wechat4j配置文件解读](https://github.com/sword-org/wechat4j/wiki/wechat4j%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%A7%A3%E8%AF%BB) 24 | 25 | 通过以上步骤,你的微信工程就完全搭好了。 26 | 27 | ##wechat4j 运行环境 28 | wechat4j要求的最低java运行环境是jdk1.6 29 | 30 | wechat4j.jar的依赖jar包 31 | > * commons-codec.jar 1.3以上 32 | > * commons-lang3.jar 33 | > * log4j.jar 1.2以上 34 | > * fastjson-1.2.0.jar 35 | > * sword-lang-1.2 (https://github.com/sword-org/sword-lang/releases) 36 | > * fluent-hc-4.3.6.jar(httpclient依赖) 37 | > * httpclient-4.3.6.jar 38 | > * httpcore-4.3.3.jar (httpclient依赖) 39 | > * servlet-api.jar 如果你是web工程,导入支持web工程的包就会包括,例如tomcat包 40 | 41 | 你可以去集中下载这些jar包的集合[wechat4j所需jar下载](http://files.cnblogs.com/chengn/wechat4j-lib.rar),也可以去maven库或者对应jar包的项目官网下载. 42 | 43 | ##开发自己的微信应用 44 | wechat4j开发环境搭好之后,就可以开始开发自己的微信应用了。比如我有一个微信号的token是lejian,下面就以她为例子来说明。 45 | ###创建自己公众号服务类 46 | 创建自己的微信公众号服务类,需要继承wechat4j的WechatSupport类,然后实现其抽象方法即可,下面以文本消息处理为例子 47 | ```java 48 | public class Lejian extends WechatSupport{ 49 | public Lejian(HttpServletRequest request) { 50 | super(request); 51 | } 52 | 53 | @Override 54 | protected void onText() { 55 | this.wechatRequest.getFromUserName(); 56 | String content = "test ok"; 57 | responseText(content); 58 | } 59 | } 60 | ``` 61 | 上面代码中的``onText()``是WechatSupport的抽象方法,需要你自己的类来实现,表示对文本消息的处理,示例中是接收到用户的消息之后,返回给用户“test ok”文本消息。 62 | 63 | ###创建微信服务地址 64 | 创建微信服务地址(微信公众平台中配置的自己服务器地址)servlet类。如果是springmvc则创建对应的controller,如果是struts则创建对应的action类。servlet类示例如下: 65 | ```java 66 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 67 | Lejian lejian = new Lejian(request); 68 | String result = lejian.execute(); 69 | response.getOutputStream().write(result.getBytes()); 70 | } 71 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 72 | Lejian lejian = new Lejian(request); 73 | String result = lejian.execute(); 74 | response.getOutputStream().write(result.getBytes()); 75 | 76 | } 77 | ``` 78 | 通过上面两步你的微信服务就可以运行了 79 | 80 | ##如何得到微信的请求参数 81 | 继承了``WechatSupport``类之后,你可以通过``wechatRequest.getFromUserName()``类似的方法来得到微信服务器请求的参数。详细信息请阅读[微信请求参数](https://github.com/sword-org/wechat4j/wiki/%E5%BE%97%E5%88%B0%E5%BE%AE%E4%BF%A1%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0) 82 | ##如何设置响应参数 83 | 继承了``WechatSupport``类之后,你可以通过``wechatResponse.setFromUserName(fromUser)``类似的方法来设置给微信服务器的响应参数。详细信息请阅读[响应微信服务器参数](https://github.com/sword-org/wechat4j/wiki/%E8%AE%BE%E7%BD%AE%E5%93%8D%E5%BA%94%E5%BE%AE%E4%BF%A1%E5%8F%82%E6%95%B0) 84 | ##如何响应用户信息 85 | 以文本信息为例,响应文本信息只需要在你的``onText``方法中使用``responseText(content)``即可(参见上面的代码例子) 86 | 87 | ##wechat4j示例项目 88 | * [wechat4jDemo](https://github.com/repoproject/wechat4jDemo) 89 | 90 | 如果你有好的demo项目,请邮件或者修改本文件然后pull request给我,我会列在上面。 91 | 92 | ##技术支持 93 | * [wechat4j开发者文档中心](http://www.chengn.com/wechat4j/) 94 | * [wechat4j开发文档](https://github.com/sword-org/wechat4j/wiki) 95 | * wechat4j技术交流QQ群 **423134346** 96 | * 支持邮件 sword_org@163.com 97 | 98 | 99 | ##贡献代码 100 | 101 | 1. 如果你觉得本项目不错,希望你能够点击一下右上角的star 102 | 2. 如果你希望参与改进本项目,那么请点击右上角的fork,修改之后pull request即可。如果你的贡献不错,你就会收到加入[sword](https://github.com/sword-org)开源社区的邀请。 103 | 3. 如果你发现了一个bug,请你创建一个issue来报告。 104 | 非常非常欢迎你能够参与本项目的建设,每人做出一点点贡献,对整个项目来说就是一个非常大的贡献,希望集合众人的力量,让项目走的更好,能够为更多的人服务。 105 | 106 | ###贡献者列表 107 | * [@chengn](https://github.com/chengn) 108 | * [@truecn](https://github.com/truecn) 109 | * [@Zhangys-hh](https://github.com/Zhangys-hh) 110 | * [@uncoseason](https://github.com/uncoseason) 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/user/AccountManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.sword.wechat4j.user; 5 | 6 | import com.alibaba.fastjson.JSONObject; 7 | import org.apache.log4j.Logger; 8 | import org.sword.lang.HttpUtils; 9 | import org.sword.wechat4j.exception.WeChatException; 10 | import org.sword.wechat4j.token.TokenProxy; 11 | import org.sword.wechat4j.util.WeChatUtil; 12 | 13 | /** 14 | * 账户管理 15 | * 16 | * @author Zhangxs 17 | * @version 2015-7-5 18 | */ 19 | public class AccountManager { 20 | Logger logger = Logger.getLogger(AccountManager.class); 21 | 22 | //长链接转短链接接口 23 | private static final String SHORTURL_POST_URL = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token="; 24 | //生成带参数的二维码 25 | private static final String QRCODE_POST_URL = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="; 26 | private String accessToken; 27 | 28 | public AccountManager() { 29 | this.accessToken = TokenProxy.accessToken(); 30 | } 31 | 32 | /** 33 | * 长链接转短链接接口 34 | * 35 | * @param longUrl 需要转换的长链接 36 | * @return 37 | */ 38 | public String shortUrl(String longUrl) { 39 | JSONObject jsonObject = new JSONObject(); 40 | jsonObject.put("action", "long2short"); 41 | jsonObject.put("long_url", longUrl); 42 | String requestData = jsonObject.toString(); 43 | logger.info("request data " + requestData); 44 | String resultStr = HttpUtils.post(SHORTURL_POST_URL + this.accessToken, requestData); 45 | logger.info("return data " + resultStr); 46 | try { 47 | WeChatUtil.isSuccess(resultStr); 48 | } catch (WeChatException e) { 49 | logger.error(e.getMessage()); 50 | e.printStackTrace(); 51 | return null; 52 | } 53 | JSONObject resultJson = JSONObject.parseObject(resultStr); 54 | return resultJson.getString("short_url"); 55 | } 56 | 57 | /** 58 | * 创建永久二维码 59 | * 60 | * @param sceneId 场景值ID,目前参数只支持1--100000 61 | * @return 62 | */ 63 | public Qrcode createQrcodePerpetual(long sceneId) { 64 | return createQrcodeTicket(QrcodeType.QR_LIMIT_SCENE, null, sceneId, null); 65 | } 66 | 67 | /** 68 | * 创建永久二维码 69 | * 70 | * @param sceneStr 场景值ID,长度限制为1到64 71 | * @return 72 | */ 73 | public Qrcode createQrcodePerpetualstr(String sceneStr) { 74 | return createQrcodeTicket(QrcodeType.QR_LIMIT_STR_SCENE, null, null, sceneStr); 75 | } 76 | 77 | /** 78 | * 创建临时二维码 79 | * 80 | * @param sceneId 场景值ID 81 | * @param expireSeconds 二维码有效时间,以秒为单位,最大不超过604800(即7天)。 82 | * @return 83 | */ 84 | public Qrcode createQrcodeTemporary(long sceneId, int expireSeconds) { 85 | return createQrcodeTicket(QrcodeType.QR_SCENE, expireSeconds, sceneId, null); 86 | } 87 | 88 | private Qrcode createQrcodeTicket(QrcodeType qrcodeType, Integer expireSeconds, Long sceneId, String sceneStr) { 89 | JSONObject ticketJson = new JSONObject(); 90 | ticketJson.put("action_name", qrcodeType); 91 | JSONObject sceneJson = new JSONObject(); 92 | switch (qrcodeType) { 93 | case QR_SCENE: 94 | ticketJson.put("expire_seconds", expireSeconds); 95 | sceneJson.put("scene_id", sceneId); 96 | break; 97 | case QR_LIMIT_SCENE: 98 | sceneJson.put("scene_id", sceneId); 99 | break; 100 | case QR_LIMIT_STR_SCENE: 101 | sceneJson.put("scene_str", sceneStr); 102 | break; 103 | } 104 | JSONObject actionInfoJson = new JSONObject(); 105 | actionInfoJson.put("scene", sceneJson); 106 | ticketJson.put("action_info", actionInfoJson); 107 | String requestData = ticketJson.toString(); 108 | logger.info("request data " + requestData); 109 | String resultStr = HttpUtils.post(QRCODE_POST_URL + this.accessToken, requestData); 110 | logger.info("return data " + resultStr); 111 | try { 112 | WeChatUtil.isSuccess(resultStr); 113 | } catch (WeChatException e) { 114 | logger.error(e.getMessage()); 115 | e.printStackTrace(); 116 | return null; 117 | } 118 | Qrcode qrcode = JSONObject.parseObject(resultStr, Qrcode.class); 119 | return qrcode; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/sword/wechat4j/user/User.java: -------------------------------------------------------------------------------- 1 | package org.sword.wechat4j.user; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | 5 | /** 6 | * 用户实体类 7 | * @author Zhangxs 8 | * @version 2015-7-5 9 | */ 10 | public class User { 11 | private int subscribe;// 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。 12 | private String openId;// 用户的标识,对当前公众号唯一 13 | private String nickName;// 用户的昵称 14 | private int sex;// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知 15 | private String city;// 用户所在城市 16 | private String country;// 用户所在国家 17 | private String province;// 用户所在省份 18 | private LanguageType language;// 用户的语言,简体中文为zh_CN 19 | private String headimgUrl;// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。 20 | private String subscribeTime;// 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间 21 | private String unionId;// 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。详见:获取用户个人信息(UnionID机制) 22 | private String remark;// 公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注 23 | private int groupId;// 用户所在的分组ID 24 | 25 | /** 26 | * 用户是否订阅该公众号标识 27 | * 值为0时,代表此用户没有关注该公众号,拉取不到其余信息 28 | */ 29 | public int getSubscribe() { 30 | return subscribe; 31 | } 32 | public void setSubscribe(int subscribe) { 33 | this.subscribe = subscribe; 34 | } 35 | /** 36 | * 用户的标识,对当前公众号唯一 37 | */ 38 | @JSONField(name="openid") 39 | public String getOpenId() { 40 | return openId; 41 | } 42 | 43 | @JSONField(name="openid") 44 | public void setOpenId(String openId) { 45 | this.openId = openId; 46 | } 47 | 48 | /** 49 | * 用户的昵称 50 | */ 51 | @JSONField(name="nickname") 52 | public String getNickName() { 53 | return nickName; 54 | } 55 | @JSONField(name="nickname") 56 | public void setNickName(String nickName) { 57 | this.nickName = nickName; 58 | } 59 | /** 60 | * 用户的性别, 61 | * 值为1时是男性, 62 | * 值为2时是女性, 63 | * 值为0时是未知 64 | */ 65 | public int getSex() { 66 | return sex; 67 | } 68 | public void setSex(int sex) { 69 | this.sex = sex; 70 | } 71 | /** 72 | * 用户所在城市 73 | */ 74 | public String getCity() { 75 | return city; 76 | } 77 | public void setCity(String city) { 78 | this.city = city; 79 | } 80 | /** 81 | * 用户所在国家 82 | */ 83 | public String getCountry() { 84 | return country; 85 | } 86 | public void setCountry(String country) { 87 | this.country = country; 88 | } 89 | /** 90 | * 用户所在省份 91 | */ 92 | public String getProvince() { 93 | return province; 94 | } 95 | public void setProvince(String province) { 96 | this.province = province; 97 | } 98 | /** 99 | * 用户的语言 100 | */ 101 | public void setLanguage(LanguageType language) { 102 | this.language = language; 103 | } 104 | public LanguageType getLanguage() { 105 | return language; 106 | } 107 | /** 108 | * 用户头像, 109 | * 最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像), 110 | * 用户没有头像时该项为空。 111 | * 若用户更换头像,原有头像URL将失效。 112 | */ 113 | @JSONField(name="headimgurl") 114 | public String getHeadimgUrl() { 115 | return headimgUrl; 116 | } 117 | @JSONField(name="headimgurl") 118 | public void setHeadimgUrl(String headimgUrl) { 119 | this.headimgUrl = headimgUrl; 120 | } 121 | /** 122 | * 用户关注时间,为时间戳。 123 | * 如果用户曾多次关注,则取最后关注时间 124 | */ 125 | 126 | @JSONField(name="subscribe_time") 127 | public String getSubscribeTime() { 128 | return subscribeTime; 129 | } 130 | @JSONField(name="subscribe_time") 131 | public void setSubscribeTime(String subscribeTime) { 132 | this.subscribeTime = subscribeTime; 133 | } 134 | /** 135 | * 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。 136 | * 详见:获取用户个人信息(UnionID机制) 137 | */ 138 | 139 | @JSONField(name="unionid") 140 | public String getUnionId() { 141 | return unionId; 142 | } 143 | @JSONField(name="unionid") 144 | public void setUnionId(String unionId) { 145 | this.unionId = unionId; 146 | } 147 | /** 148 | * 公众号运营者对粉丝的备注, 149 | * 公众号运营者可在微信公众平台用户管理界面对粉丝添加备注 150 | */ 151 | public String getRemark() { 152 | return remark; 153 | } 154 | public void setRemark(String remark) { 155 | this.remark = remark; 156 | } 157 | /** 158 | * 用户所在的分组ID 159 | */ 160 | @JSONField(name="groupid") 161 | public int getGroupId() { 162 | return groupId; 163 | } 164 | @JSONField(name="groupid") 165 | public void setGroupId(int groupId) { 166 | this.groupId = groupId; 167 | } 168 | 169 | @Override 170 | public String toString() { 171 | return "User [subscribe=" + subscribe + ", openId=" + openId 172 | + ", nickName=" + nickName + ", sex=" + sex + ", city=" + city 173 | + ", country=" + country + ", province=" + province 174 | + ", language=" + language + ", headimgUrl=" + headimgUrl 175 | + ", subscribeTime=" + subscribeTime + ", unionId=" + unionId 176 | + ", remark=" + remark + ", groupId=" + groupId + "]"; 177 | } 178 | 179 | 180 | 181 | } 182 | -------------------------------------------------------------------------------- /doc/api/deprecated-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 已过时项目列表 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |


30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 已过时的 API

86 |
87 |
88 | 目录
    89 |
90 | 91 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 114 | 117 | 118 | 119 | 120 | 123 | 139 | 140 |
115 | 116 |
141 | 142 | 143 | 144 |
145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/package-use.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 软件包 org.sword.wechat4j 的使用 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 软件包 org.sword.wechat4j
的使用

86 |
87 | 没有 org.sword.wechat4j 的用法 88 |

89 |


90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 112 | 115 | 116 | 117 | 118 | 121 | 137 | 138 |
113 | 114 |
139 | 140 | 141 | 142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/user/package-use.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 软件包 org.sword.wechat4j.user 的使用 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 软件包 org.sword.wechat4j.user
的使用

86 |
87 | 没有 org.sword.wechat4j.user 的用法 88 |

89 |


90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 112 | 115 | 116 | 117 | 118 | 121 | 137 | 138 |
113 | 114 |
139 | 140 | 141 | 142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/param/package-use.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 软件包 org.sword.wechat4j.param 的使用 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 软件包 org.sword.wechat4j.param
的使用

86 |
87 | 没有 org.sword.wechat4j.param 的用法 88 |

89 |


90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 112 | 115 | 116 | 117 | 118 | 121 | 137 | 138 |
113 | 114 |
139 | 140 | 141 | 142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/message/package-use.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 软件包 org.sword.wechat4j.message 的使用 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 软件包 org.sword.wechat4j.message
的使用

86 |
87 | 没有 org.sword.wechat4j.message 的用法 88 |

89 |


90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 112 | 115 | 116 | 117 | 118 | 121 | 137 | 138 |
113 | 114 |
139 | 140 | 141 | 142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/token/timer/package-use.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 软件包 org.sword.wechat4j.token.timer 的使用 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 软件包 org.sword.wechat4j.token.timer
的使用

86 |
87 | 没有 org.sword.wechat4j.token.timer 的用法 88 |

89 |


90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 112 | 115 | 116 | 117 | 118 | 121 | 137 | 138 |
113 | 114 |
139 | 140 | 141 | 142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /doc/api/allclasses-noframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 所有类 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 所有类 21 |
22 | 23 | 24 | 25 | 112 | 113 |
AbsServer 26 |
27 | AccessToken 28 |
29 | AccessTokenMemServer 30 |
31 | AccessTokenServer 32 |
33 | AccessTokenTimer 34 |
35 | AccountManager 36 |
37 | ArticleResponse 38 |
39 | Config 40 |
41 | CustomerMsg 42 |
43 | CustomerServer 44 |
45 | EventType 46 |
47 | ImageResponse 48 |
49 | IServer 50 |
51 | Item 52 |
53 | JsApiTicketMemServer 54 |
55 | JsApiTicketServer 56 |
57 | JsApiTicketTimer 58 |
59 | MediaFile 60 |
61 | MediaType 62 |
63 | MsgType 64 |
65 | MusicResponse 66 |
67 | ScanCodeInfo 68 |
69 | SendLocationInfo 70 |
71 | SendPicsInfo 72 |
73 | SignatureParam 74 |
75 | TemplateMsg 76 |
77 | TemplateMsgBody 78 |
79 | TemplateMsgData 80 |
81 | Ticket 82 |
83 | TicketServer 84 |
85 | TicketType 86 |
87 | Token 88 |
89 | TokenListener 90 |
91 | TokenProxy 92 |
93 | TokenServer 94 |
95 | UserManager 96 |
97 | ValidateSignature 98 |
99 | VideoResponse 100 |
101 | VoiceResponse 102 |
103 | WechatParamName 104 |
105 | WechatRequest 106 |
107 | WechatResponse 108 |
109 | WechatSupport 110 |
111 |
114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/class-use/WechatSupport.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 类 org.sword.wechat4j.WechatSupport 的使用 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 类 org.sword.wechat4j.WechatSupport
的使用

86 |
87 | 没有 org.sword.wechat4j.WechatSupport 的用法 88 |

89 |


90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 112 | 115 | 116 | 117 | 118 | 121 | 137 | 138 |
113 | 114 |
139 | 140 | 141 | 142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/token/class-use/Ticket.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 类 org.sword.wechat4j.token.Ticket 的使用 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 类 org.sword.wechat4j.token.Ticket
的使用

86 |
87 | 没有 org.sword.wechat4j.token.Ticket 的用法 88 |

89 |


90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 112 | 115 | 116 | 117 | 118 | 121 | 137 | 138 |
113 | 114 |
139 | 140 | 141 | 142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/user/class-use/UserManager.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 类 org.sword.wechat4j.user.UserManager 的使用 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 类 org.sword.wechat4j.user.UserManager
的使用

86 |
87 | 没有 org.sword.wechat4j.user.UserManager 的用法 88 |

89 |


90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 112 | 115 | 116 | 117 | 118 | 121 | 137 | 138 |
113 | 114 |
139 | 140 | 141 | 142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/common/class-use/MediaFile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 类 org.sword.wechat4j.common.MediaFile 的使用 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 类 org.sword.wechat4j.common.MediaFile
的使用

86 |
87 | 没有 org.sword.wechat4j.common.MediaFile 的用法 88 |

89 |


90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 112 | 115 | 116 | 117 | 118 | 121 | 137 | 138 |
113 | 114 |
139 | 140 | 141 | 142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /doc/api/org/sword/wechat4j/token/class-use/TokenProxy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 类 org.sword.wechat4j.token.TokenProxy 的使用 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 52 | 55 | 56 | 57 | 58 | 61 | 77 | 78 |
53 | 54 |
79 | 80 | 81 | 82 |
83 |
84 |

85 | 类 org.sword.wechat4j.token.TokenProxy
的使用

86 |
87 | 没有 org.sword.wechat4j.token.TokenProxy 的用法 88 |

89 |


90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 112 | 115 | 116 | 117 | 118 | 121 | 137 | 138 |
113 | 114 |
139 | 140 | 141 | 142 |
143 | 144 | 145 | 146 | --------------------------------------------------------------------------------