Giter Site home page Giter Site logo

weixin-java-open-demo's People

Contributors

007gzs avatar binarywang avatar langinteger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

weixin-java-open-demo's Issues

建议demo pom中添加spring-boot-maven-plugin插件

有些 spring boot 新手java -jar 执行时会遇到 no main manifest attribute,错误

java -jar target/weixin-java-open-demo-1.0-SNAPSHOT.jar 

建议添加spring-boot-maven-plugin插件

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

开放平台自动回复不生效,提示出现 该公众号提供的服务出现故障

开放平台开发

@RequestMapping("{appId}/callback")
    public Object callback(@RequestBody(required = false) String requestBody,
                           @PathVariable("appId") String appId,
                           @RequestParam("signature") String signature,
                           @RequestParam("timestamp") String timestamp,
                           @RequestParam("nonce") String nonce,
                           @RequestParam(value = "openid", required = false) String openid,
                           @RequestParam("encrypt_type") String encType,
                           @RequestParam("msg_signature") String msgSignature,
                           HttpServletResponse response) throws Exception {
        this.logger.info(
                "\n接收微信请求:[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                appId, openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
        if (!StringUtils.equalsIgnoreCase("aes", encType)
                || !wxOpenService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
        }

        String out = "";
        // aes加密的消息
        WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(requestBody,
                wxOpenService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
        this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
//         全网发布测试用例
        if (StringUtils.equalsAnyIgnoreCase(appId, "wx90d8a37adac76a84")
        ) {
            try {
                if (StringUtils.equals(inMessage.getMsgType(), "text")) {
                    logger.info("msg:[{}]", inMessage.getContent());
                    if (StringUtils.equals(inMessage.getContent(), "TESTCOMPONENT_MSG_TYPE_TEXT")) {
                        out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(
                                WxMpXmlOutMessage.TEXT()
                                        .content("TESTCOMPONENT_MSG_TYPE_TEXT_callback")
                                        .fromUser(inMessage.getToUser())
                                        .toUser(inMessage.getFromUser())
                                        .build(),
                                wxOpenService.getWxOpenConfigStorage()
                        );
                        logger.info("回复内容:[{}]", out);
                    } else if (StringUtils.startsWith(inMessage.getContent(), "QUERY_AUTH_CODE:")) {
                        String msg = inMessage.getContent().replace("QUERY_AUTH_CODE:", "") + "_from_api";
                        WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(msg).toUser(inMessage.getFromUser()).build();
                        wxOpenService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
                    }
                } else if (StringUtils.equals(inMessage.getMsgType(), "event")) {
                    WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content("你好").toUser(inMessage.getFromUser()).build();
                    wxOpenService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
                }
            } catch (WxErrorException e) {
                logger.error("callback", e);
            }
        } else {
        }
        return out;
    }

后台日志

接收微信请求:[appId=[wx90d8a37adac76a84], openid=[oHbsv1F61YlvqWx00o4QrUz3qe5s], signature=[11f19338aed39d31518a51602d2816e72f9b98a1], encType=[aes], msgSignature=[45e6ab812329891f90e0626c500445bfdbcb94e1], timestamp=[1556439461], nonce=[344102969], requestBody=[
<xml>
    <ToUserName><![CDATA[gh_8ffc5b7009e8]]></ToUserName>
    <Encrypt><![CDATA[KxKVw4S5c1FEK34MISDgm1GBFm7Nh/2oXBOqibbm3Vo9Du0IIpxWFzesBBCGRkBMLncy39MZUJ9u/CiwDvdXUg8MIUk4DWQqjzAMAEKvBQG4DCgjNi9s5Oph+N7U+RuiPJJXNjUbuO2pNCLPS4yvab4b+afZ+i310a5o7yGqQMbJcykm0Pr8TvQ01gvzxzHzsa+KZkL5l5/xIgoQV45sjixiVgV2qjCJmoeRHsDkU+yIJxkoKguJWlQNosWMmuqa3OuXNgv+4dX7WdIvxHGfX+l0/g9h+bgSrtZJJEGxRUvPl0kdBbxbddf3JQGcCBWcRWT0ua4j4q/3TdnmkLVH/+ZZt+0uB5DRsis+qA00rA40yuNFNGzQHejWNrRMPhJe+I7D/yeemfkVTaJgYl+TivfdUe2jS6YqibNqoPaXA4b+FL+ri4xh8znt4THApcw/KHfNVriid8Qvp4i7ncvZLA==]]></Encrypt>
</xml>

]
2019-04-28 16:17:42.161 [http-nio-7023-exec-1] INFO  c.g.i.w.c.WechatNotifyController [callback:128]     - msg:[TESTCOMPONENT_MSG_TYPE_TEXT]
2019-04-28 16:17:42.183 [http-nio-7023-exec-1] INFO  c.g.i.w.c.WechatNotifyController [callback:138]     - 回复内容:[<xml>
<Encrypt><![CDATA[mLKkLUUY1gzildkY0kicuS5Z2pKjgYqenDJn/mLxrSvF0AVE8h+0xsO02JjKA6N+kSXyie4hI45M1ARAmKpaUcLQqczXfub+c5hMqmEi/ERbIPR31w1ynKX1fKWO5W6sR5LT9LB7n8fCaHiRkMYOFfjsXW+47YeUzZ/XUc9jda2i0SCAAdVoIanl9wDRm4cmdRqC0/qOcaaTnc67yq3mQXJJ0ZUuzpC76dyeTQ4AJB/D0PA8V4llbFpIixKowqINm2DKfnu7hr5+udTeD69RvwJzLs6tQph2b2jsSubKARibWoS7i+5s7ahXzTsBjVgClpOdW4utq+l3ZFMF/ca++F2BO4hPXPEFlsvHWo2rC7JEUrpMJV4sd7yNaTJ2geiSMFWV5fJT+/o1WjJduuGSsXkhn+T3zU9G5gv34X/j2kiQxwJC4OSad+AVID2zSm9brvrPrsLnLtq5xUPBcq0WYw==]]></Encrypt>
<MsgSignature><![CDATA[bfda1a5e023b509537f67107f726af0a073edfbf]]></MsgSignature>
<TimeStamp>1556439462</TimeStamp>
<Nonce><![CDATA[PnobBQPLvJbUfTpX]]></Nonce>
</xml>]

客服消息可以回复,自动回复 有问题,请问如何排查
经测试,不加密可以回复,加密后回复有问题

回复内容:
WxMpXmlOutMessage outMessage = WxMpXmlOutMessage.TEXT()
.content("TESTCOMPONENT_MSG_TYPE_TEXT_callback")
.fromUser(inMessage.getToUser())
.toUser(inMessage.getFromUser())
.build();
不加密:
直接回复 outMessage.toXml()

加密:
out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(
outMessage,
wxOpenService.getWxOpenConfigStorage())
回复 out

接口无法获取“获取授权方的帐号基本信息”

代码如下:
方式一:
WxOpenAuthorizerInfoResult info = this.getWxOpenComponentService().getAuthorizerInfo(inMessage.getAuthorizerAppid()); logger.info(info);

控制台输出为空

方式二,自己写了一个http请求:

        HttpHeaders headers = new HttpHeaders();
        Map<String, Object> map = new HashMap<>();
        map.put("component_appid", this.getWxOpenConfigStorage().getComponentAppId());
        map.put("authorizer_appid", inMessage.getAuthorizerAppid());
        HttpEntity<Map<String, Object>> requestParams = new HttpEntity<Map<String, Object>>(map, headers);
        ResponseEntity<String> postStr = restTemplate.exchange(
                "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=" + this.getWxOpenConfigStorage().getComponentAccessToken(),
                HttpMethod.POST,
                requestParams,
                String.class);
        this.logger.info(postStr.getBody().toString());

有结果输出:

{"authorizer_info":{"nick_name":"平和县xxx百货店","servi
ce_type_info":{"id":2},"verify_type_info":{"id":0},"user_name":"gh_9867c54xxxxx"
,"alias":"","qrcode_url":"http:\/\/mmbiz.qpic.cn\/mmbiz_jpg\/mOVKxWcL1LUGzUmrKib
Bw7l7Cn3IfAURTNnYpt7oprX8HQp8R5Jibqic43p77PWXcy9ZhSdqoelsBdibD2tpiaCNE1Q\/0","bu
siness_info":{"open_pay":1,"open_shake":0,"open_scan":0,"open_card":0,"open_stor
e":0},"idc":1,"principal_name":"平和县xxx百货店","signature":"小小人儿"},"aut
horization_info":{"authorizer_appid":"wx3c795cd1cxxxxxx","authorizer_refresh_to
ken":"refreshtoken@@@8njaYHydAkiarMtH7AP_abAuDoHxxxxxxxxxxx","func_info":[{
"funcscope_category":{"id":1}},{"funcscope_category":{"id":4}}]}}

想问一下网页授权code 如何得到opneId 用户信息

正常第三方授权
WxOpenComponentService wxOpenComponentService = WxOpenConfiguration.getOpenService().getWxOpenComponentService();
//第一步url重定向
url=wxOpenComponentService.oauth2buildAuthorizationUrl(appid, redirectUri, scope, state);
//第二步,获取token等
WxMpOAuth2AccessToken accessToken=wxOpenComponentService.oauth2getAccessToken(appid, code);

提示 redirect_url 错误代码10003

集群部署

集群部署的话,相同的第三方平台配置,会不会有accessToken失效的问题啊, 怎么解决呢

授权二维码无法跳出

直接访问:/auth/goto_auth_url 会显示错误 原因:
请确认授权入口页所在域名,与授权后回调页所在域名相同,并且,此两者都必须与申请第三方平台时填写的授权发起页域名相同。授权入口页所在域名:空

只能先访问:/auth/goto_auth_url_show才会跳出二维码
那如果前后端分离 前端和后台的域名不是同一个怎么办?

全网发布时不通过

名称 状态
[组件ticket正确接收] 成功
[生成预授权码] 成功
[获取授权code] 成功
[授权] 成功
[返回Api文本消息] 失败
[返回普通文本消息] 成功
[发送事件消息] 失败
[取消授权] 成功

查看log时发现authorizer_refresh_token 是null,不知道是不是有影响

2018-03-20 15:41:25,647 ERROR [XNIO-2 task-13] WxOpenServiceDemo:
【请求地址】: https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=token
【请求参数】:{"component_appid":"component_appid","authorizer_appid":"authorizer_appid","authorizer_refresh_token":null}
【错误信息】:{"errcode":61023,"errmsg":"refresh_token is invalid hint: [458N06852994]"}
2018-03-20 15:41:25,647 ERROR [XNIO-2 task-13] NotifyController: callback
me.chanjar.weixin.common.exception.WxErrorException: {"errcode":61023,"errmsg":"refresh_token is invalid hint: [458N06852994]"}

错误代码:61006, 错误信息:无效 ticket,

"me.chanjar.weixin.common.error.WxErrorException: 错误代码:61006, 错误信息:无效 ticket,微信原始报文:{"errcode":61006,"errmsg":"component ticket is invalid rid: 6425c299-1d719673-32c6291c"}",

org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 9; 文件提前结束

授权的时候. 报这个错误, 请问是什么情况? 该怎么解决呢

me.chanjar.weixin.common.error.WxRuntimeException: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 9; 文件提前结束。

// aes加密的消息
WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(requestBody,
wxOpenService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);

Caused by: org.xml.sax.SAXParseException: 文件提前结束。

运行demo推送ticket的时候报错

{"timestamp":"Jul 2, 2018 6:18:59 PM","status":500,"error":"Internal Server Error","exception":"java.lang.RuntimeException","message":"org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; 前言中不允许有内容。","path":"/notify/receive_ticket"},调试发现WxCryptUtil类的bytesNetworkOrder2Number方法直接返回负数

Open包中获取网页授权二维码的路由错误?

官方文档中,开放平台获取网页授权二维码的路由为: https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

实际Open包中封装的路由为:CONNECT_OAUTH2_AUTHORIZE_URL("https://open.weixin.qq.com", "/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect"); 该陆游实际是公众号网页授权获取二维码的路由地址。

怎么支持多个第三方平台?

image
配置成多个账号的第三方平台可以吗? 有没有例子,谢谢!
因为主体不一样, 是不能直接获取unionid的,所以我们申请了多个第三方平台

管理员扫码后出现错误

已经添加测试公众号列表,但是管理员扫码后依然出现请全网发布或将尝试授权的公众号或小程序添加到授权测试公众号列表后再试

项目下载后启动报nested exception is java.lang.NoClassDefFoundError: com/github/jedis/lock/JedisLock错

2020-08-12 19:24:54.487 DEBUG 1072 --- [p-nio-80-exec-1] o.s.web.servlet.DispatcherServlet : Servlet 'dispatcherServlet' configured successfully
2020-08-12 19:24:54.495 DEBUG 1072 --- [p-nio-80-exec-1] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/api/auth/goto_auth_url]
2020-08-12 19:24:54.497 DEBUG 1072 --- [p-nio-80-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /api/auth/goto_auth_url
2020-08-12 19:24:54.498 DEBUG 1072 --- [p-nio-80-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public void com.github.binarywang.demo.wx.open.controller.WechatApiController.gotoPreAuthUrl(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]
2020-08-12 19:24:54.498 DEBUG 1072 --- [p-nio-80-exec-1] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/api/auth/goto_auth_url] is: -1
2020-08-12 19:24:54.521 DEBUG 1072 --- [p-nio-80-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [public void com.github.binarywang.demo.wx.open.controller.WechatApiController.gotoPreAuthUrl(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]: org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: com/github/jedis/lock/JedisLock
2020-08-12 19:24:54.523 DEBUG 1072 --- [p-nio-80-exec-1] .w.s.m.a.ResponseStatusExceptionResolver : Resolving exception from handler [public void com.github.binarywang.demo.wx.open.controller.WechatApiController.gotoPreAuthUrl(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]: org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: com/github/jedis/lock/JedisLock
2020-08-12 19:24:54.524 DEBUG 1072 --- [p-nio-80-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolving exception from handler [public void com.github.binarywang.demo.wx.open.controller.WechatApiController.gotoPreAuthUrl(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]: org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: com/github/jedis/lock/JedisLock
2020-08-12 19:24:54.529 DEBUG 1072 --- [p-nio-80-exec-1] o.s.web.servlet.DispatcherServlet : Could not complete request

org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: com/github/jedis/lock/JedisLock
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:982) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.16.jar:8.5.16]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_162]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.16.jar:8.5.16]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_162]
Caused by: java.lang.NoClassDefFoundError: com/github/jedis/lock/JedisLock
at me.chanjar.weixin.common.util.locks.JedisDistributedLock.(JedisDistributedLock.java:22) ~[weixin-java-common-3.8.0.jar:na]
at me.chanjar.weixin.common.redis.JedisWxRedisOps.getLock(JedisWxRedisOps.java:50) ~[weixin-java-common-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenInRedisConfigStorage.getLockByKey(WxOpenInRedisConfigStorage.java:138) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage.getComponentAccessTokenLock(WxOpenInMemoryConfigStorage.java:71) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.getComponentAccessToken(WxOpenComponentServiceImpl.java:117) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.post(WxOpenComponentServiceImpl.java:144) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.post(WxOpenComponentServiceImpl.java:139) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.createPreAuthUrl(WxOpenComponentServiceImpl.java:257) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.getPreAuthUrl(WxOpenComponentServiceImpl.java:231) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.getPreAuthUrl(WxOpenComponentServiceImpl.java:226) ~[weixin-java-open-3.8.0.jar:na]
at com.github.binarywang.demo.wx.open.controller.WechatApiController.gotoPreAuthUrl(WechatApiController.java:38) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_162]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_162]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_162]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
... 43 common frames omitted
Caused by: java.lang.ClassNotFoundException: com.github.jedis.lock.JedisLock
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_162]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_162]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338) ~[na:1.8.0_162]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_162]
... 65 common frames omitted

2020-08-12 19:24:54.532 ERROR 1072 --- [p-nio-80-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: com/github/jedis/lock/JedisLock] with root cause

java.lang.ClassNotFoundException: com.github.jedis.lock.JedisLock
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_162]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_162]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338) ~[na:1.8.0_162]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_162]
at me.chanjar.weixin.common.util.locks.JedisDistributedLock.(JedisDistributedLock.java:22) ~[weixin-java-common-3.8.0.jar:na]
at me.chanjar.weixin.common.redis.JedisWxRedisOps.getLock(JedisWxRedisOps.java:50) ~[weixin-java-common-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenInRedisConfigStorage.getLockByKey(WxOpenInRedisConfigStorage.java:138) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage.getComponentAccessTokenLock(WxOpenInMemoryConfigStorage.java:71) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.getComponentAccessToken(WxOpenComponentServiceImpl.java:117) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.post(WxOpenComponentServiceImpl.java:144) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.post(WxOpenComponentServiceImpl.java:139) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.createPreAuthUrl(WxOpenComponentServiceImpl.java:257) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.getPreAuthUrl(WxOpenComponentServiceImpl.java:231) ~[weixin-java-open-3.8.0.jar:na]
at me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl.getPreAuthUrl(WxOpenComponentServiceImpl.java:226) ~[weixin-java-open-3.8.0.jar:na]
at com.github.binarywang.demo.wx.open.controller.WechatApiController.gotoPreAuthUrl(WechatApiController.java:38) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_162]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_162]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_162]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) [tomcat-embed-core-8.5.16.jar:8.5.16]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.16.jar:8.5.16]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_162]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.16.jar:8.5.16]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_162]

多节点部署如何刷新accesstoken

WxMaService maService = new WxMaServiceImpl();
maService.setMultiConfigs(
configs.stream()
.map(a -> {
// WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
WxMaDefaultConfigImpl config = new WxMaRedissonConfigImpl(redissonClient);
// WxMaDefaultConfigImpl config = new WxMaRedisConfigImpl(new JedisPool());
// 使用上面的配置时,需要同时引入jedis-lock的依赖,否则会报类无法找到的异常
config.setAppid(a.getAppid());
config.setSecret(a.getSecret());
config.setToken(a.getToken());
config.setAesKey(a.getAesKey());
config.setMsgDataFormat(a.getMsgDataFormat());
return config;
}).collect(Collectors.toMap(WxMaDefaultConfigImpl::getAppid, a -> a, (o, n) -> o)));

这里只需要指定实现为WxMaRedisConfigImpl即可吗?还是需要去重写WxMaDefaultConfigImpl的方法

需要@Autowired注入WxOpenMaService怎么配置

示例提供的WxOpenServiceDemo注入没有问题。
但是要使用WxOpenMaService的话怎么注入配置呢?
看到实现类的构造方法是 WxOpenMaServiceImpl(WxOpenComponentService wxOpenComponentService, String appId, WxMaConfig wxMaConfig)

前后端分离问题请教

如果是springbood+vue的前后端分离项目,如何实现扫码授权?
微信扫码授权,需要入口域名和调用服务域名和回调域名一致。
故无法直接调用/auth/goto_auth_url,不知道这种情况下如何实现?

全网发布测试问题

显示的是检测成功,但是文本消息 和api消息是失败的状态,代码完全和demo一样 项目没报错,请问一下是我哪里配置没对吗

实现获取js-sdk签名, 代码如下, 报错了

WxMpService mpService = this.wxOpenServiceDemo.getWxOpenComponentService().getWxMpServiceByAppid(appId);
try {
WxJsapiSignature jsapiSignature = mpService.createJsapiSignature(url);
return ResponseUtil.buildSuccess(jsapiSignature);
} catch (WxErrorException e) {
e.printStackTrace();
}

Caused by: java.lang.AbstractMethodError: me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage$WxOpenInnerConfigStorage.getTicketLock(Lme/chanjar/weixin/mp/enums/TicketType;)Ljava/util/concurrent/locks/Lock;
at me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl.getTicket(BaseWxMpServiceImpl.java:95)
at me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl.getJsapiTicket(BaseWxMpServiceImpl.java:124)
at me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl.createJsapiSignature(BaseWxMpServiceImpl.java:131)
at cn.casair.wx.rest.WxMpUserController.getSignature(WxMpUserController.java:113)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
... 102 common frames omitted

请问如何对接开放平台中针对移动app的微信认证

你好,移动app的微信认证与网页版的还是有一些区别的,请问应该如何接入呢,另外我看

wechat:
  open:
    componentAppId: ""
    componentSecret: ""
    componentToken: ""
    componentAesKey: ""

看官方文档,一般只需要appid,secret,那token、aeskey是用来做什么用的?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.