• 使用新浪云 Java 环境搭建一个简单的微信处理后台

    前一段时间,写了一篇在新浪云上搭建自己的网站的教程,通过简单构建了一个 maven 的项目,展示部署的整个流程,具体的操作可以参看这里

    新浪云服务器除了可以搭建自己的网站以外,也非常的适合作为微信公众号回调地址来使用(熟悉微信公众号开发的朋友可能已经了解了,如果不太清楚请参看微信公众平台),微信公众号的开发需要一个公网可以访问的服务器,用于处理消息的 token 的验证,以及自身业务的定制开发。在这里,写了一些简单操作的例子,给大家参考。

    准备

    开发微信公众号首先要申请自己的公众号,或者获得相关需要开发的公众号的操作权限,如何申请,这里就不具体讲了,具体的流程大家可以参看微信公众号的申请流程,需要注意的是自己的 AppID 和自己的 AppSecret ,不要泄漏,还需要自己设置一个 token 令牌,这里还有一个消息的加密密钥 EncodingAESKey ,可以随机生成,用于消息的加密解密。如下图所示:

    weixin-config

    这里 URL 填写在新浪云申请的服务器的地址,当然具体指向到那个 path 我们需要自己去写一个 servlet,这里我自己定义了一个 WX 的 servlet,令牌我自己定义了一个,消息加密密钥使用了系统随机生成的,为了便于开发,所以消息加密方式,使用了明文的方式,这样消息就可以直观的看到,在填写完这些配置之后,在提交之后,微信的服务器会发一个 get 请求到我们填写的 URL 地址,去验证下 token,所以这里我们就预先要将这个 servlet 写好,简单的验证一步 token(代码会在下面列出),当验证通过后,修改才会成功,点击启用后,微信的服务器才会将客户端的消息,发送到我们提供的服务器。这里有具体的 接入指南

    我在我的项目中建立了一个叫 WX 的 servlet。添加了如下的代码。

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String sig =  request.getParameter("signature");
        String timestamp =  request.getParameter("timestamp");
        String nonce =  request.getParameter("nonce");
        String echostr =  request.getParameter("echostr");
        String token = "xxxx"; // 这里填写自己的 token
        List<String> list = new ArrayList<String>();
        list.add(nonce);
        list.add(token);
        list.add(timestamp);
        Collections.sort(list);
        String hash = getHash(list.get(0)+list.get(1)+list.get(2), "SHA-1");
        if(sig.equals(hash)){ // 验证下签名是否正确
            response.getWriter().println(echostr);
        }else{
            response.getWriter().println("");
        }
    }
    
    public  String getHash(String source, String hashType) {
        StringBuilder sb = new StringBuilder();
        MessageDigest md5;
        try {
            md5 = MessageDigest.getInstance(hashType);
            md5.update(source.getBytes());
            for (byte b : md5.digest()) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }
    

    在验证完成后, 原样返回 echostr 字符串就行了。这样填写服务器配置之后就可以成功的保存配置了。注意需要点击启用微信才会将客户端的消息转发给自己的服务器。

    以上这个环节条中通过之后,我们来处理下消息,根据消息的输入做一些简单的返回,比如输入 hello 返回特定的字符串,返回定义的字符串,输入 time,返回当前的时间。这里要注意,咱们服务器接受的请求是由微信的服务器 post 过来的,所以,我们的处理过程要写在 doPost 方法里。

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String sig =  request.getParameter("signature");
        System.out.println("sig : "+sig);
        String timestamp =  request.getParameter("timestamp");
        String nonce =  request.getParameter("nonce");
        String echostr =  request.getParameter("echostr");
        String token = "nero";
        String responseContent = defaultStr;
        List<String> list = new ArrayList<String>();
        list.add(nonce);
        list.add(token);
        list.add(timestamp);
        Collections.sort(list);
        String hash = getHash(list.get(0)+list.get(1)+list.get(2), "SHA-1").toLowerCase();
        if(sig.equals(hash)){
            if(request.getMethod().equals("POST")){
                Map<String,String> map = XMLParse.extract(convertStreamToString(request.getInputStream()));
                if(map.get("Content").equals("hello")){
                    responseContent = "Hello,This message from SinaCloud";
                }
                if(map.get("Content").equals("time")){
                    sf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
                    responseContent = sf.format(new Date());
                }
                responseMsg = formatResponseMsg(responseContent, map);
            }
            response.setCharacterEncoding("utf-8");
            response.getWriter().println(responseMsg);
        }else{
            response.getWriter().println("success");
        }
    }
    
    public String convertStreamToString(InputStream is) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
    
    public String formatResponseMsg(String content,Map map){
        String responseMsg = "<xml>"
                + "<ToUserName><![CDATA[%1$s]]></ToUserName>"
                + "<FromUserName><![CDATA[%2$s]]></FromUserName>"
                + "<CreateTime>%3$s</CreateTime>"
                + "<MsgType><![CDATA[%4$s]]></MsgType>"
                + "<Content><![CDATA[%5$s]]></Content>"
                + "<MsgId>%6$s</MsgId>"
                + "</xml>";
        return String.format(responseMsg, map.get("FromUserName"),map.get("ToUserName"),map.get("CreateTime"),map.get("MsgType"),content,map.get("MsgId"));
    }
    

    以上的代码就是处理的大概的过程,处理的效果如下。

    wx-msg

    以上就是使用新浪云大概搭建一个微信处理的后端程序,简单的实现了一些文本信息的交互功能,以后有时间继续写点其他消息的交互过程。

  • 如何在新浪云上部署一个 Hubot 机器人

    hubot

    What is Hubot? Hubot is your company's robot. Install him in your company to dramatically improve and reduce employee efficiency.

    Hubot 是 GitHub 开源的一个聊天机器人,可以用来在公司的在线聊天室(Slack、Campfire、Bearychat 等)里接受指令并完成一些自动化的工作(比如运维中重启机器、查看机器信息等)。

    下文我们以 Hubot + Bearychat 为例,一步一步说明一下如何在新浪云上部署一个 Hubot 机器人。

    创建一个新 bot

    首先,按照 Hubot 官方文档的说明,使用 yo 创建一个新的 Hubot 项目。

    $ npm install -g hubot coffee-script yo generator-hubot
    $ cd /path/to/hubot
    $ yo hubot
    

    yo 提示输入 Bot adapter 时,输入 bearychat ,yo 会自动安装完 Hubot 以及 Bearychat adapter 所有相关的依赖包。

    本地运行

    进入 Hubot 代码目录,执行以下命令进入一个本地调试的命令行。检查调试 Hubot 功能是否 OK。

    $ cd /path/to/hubot
    $ bin/hubot
    

    部署到线上

    进入新浪云的控制台,创建一个新的云应用,语言选择 NodeJS

    进入 Bearychat 的机器人管理页面,选择添加一个 Hubot 机器人,在 Hubot URL 框里填入应用的 URL 地址。复制 Hubot Token ,进入新浪云应用控制台的 应用/环境变量 页面,创建一个新的环境变量。变量名为 HUBOT_BEARYCHAT_TOKENS ,值为刚才复制过来的 Token 。

    最后我们进入刚才创建好的 Hubot 目录中,执行以下命令将代码部署到线上。

    $ git remote add origin https://git.sinacloud.com/应用名
    $ git push -u origin master
    

    完成,现在,我们可以在 Bearychat 里调戏一把我们新加的 Hubot 机器人了。

    hubot-remchan

    给机器人添加新的命令

    给 Hubot 添加新的命令非常的简单,在 scripts 目录下建一个 .coffee 或者 .js 结尾的文件,按照 scripts/example.coffee 中的示例添加你自己需要的命令即可。

    参考:

  • 手把手教你用新浪云容器 Java 搭建自己的网站

    经过一段时间的开发,更新,迭代,新浪云容器 Java 环境逐渐成熟起来,相比过去的 Java 运行环境,可用性和易用性都得到了大量的提升。同时也收到了不少用户反馈的使用问题,特此在这篇文章里综合介绍一下容器 Java 使用以及相关服务的整合。

    环境说明

    新浪云容器 Java 环境基于 Docker 搭建,支持多实例负载均衡,近乎原生虚拟机环境,使用无门槛。

    • JDK 1.8
    • Web 容器 tomcat-8.0.35

    注意:这里以后可能会提供相应的 Web 容器定制服务

    准备

    开发自己的应用之前,我们先要准备好自己的开发环境,新浪云的容器 Java 应用所需的环境和一般开发环境类似。

    • JDK(最好是能与线上同步,当然低版本也可以) version:1.7 以上
    • 开发 IDE(推荐 eclipse,有相应的开发插件,能够快速上传) version:eclipse(Mars.1 Release (4.5.1) 此版本自带了 maven 插件,不需要另装了)
    • maven(推荐使用,能够方便使用新浪云提供的 sdk) version:3.3.9

    安装方式就不累述了,各个环境下如何安装配置,大家可以自行用百度谷歌一下

    创建初始化应用

    首先我们要创建自己的新浪云账号,这个就不累述了,具体参看新浪云

    然后我们来着手建立一个 maven 的项目,当然我们可以通过 maven 的命令来创建一个项目,不过我们有 IDE,可以方便的利用可视化界面操作,而且也方便使用插件。

    好了,我们打开 Eclipse,接下来我们就开始创建自己的 Web 项目,点击"File"->"New"->"Maven project",如下图

    create-project

    然后点击"Next",注意接下来选择的"Archetype",咱们是 Web 项目,所以一定要选择"maven-archetype-webapp",如下图

    create-project

    然后点击"Next",填写 Group Id 和 Artifact Id,然后在点击"Finish"。

    create-project

    然后咱们的项目就建好了,目录结构如下图,接下来我们就开始开发我们自己的项目

    create-project

    首先我们建立一下源码目录,在 src->main 下面新建一个文件夹 java,然后就可以看到如图的应用结构了

    create-project

    这里还有一个注意的地方,建立好新的 maven 项目之后,可能需要一些简单的配置,如果默认配置好了可以忽略了,主要注意两个方面的配置,一是 Servlet 版本,一是 JDK 版本,以及项目结构。

    改下 JDK,点击项目右键 ->proerties->java compile,如下图

    create-project

    将 JDK 版本调整为 1.7 以上以匹配线上版本。

    在修改下项目的结构,如下图。点击 Project Facet,修改下 Java 的版本和刚刚修改的版本一致。

    create-project

    修改下 Dynamic Web Module,改成 3.1 版本(如果点击下面提示无法改变版本的话,就先反选 Dynamic Web Module 然后确定,在重新进入这个界面在勾选即可修改)。如下图

    create-project

    注意图中的标注位置,点击进去,配置一下 Web 目录,如下图

    create-project

    将我们建立项目的 Web 目录配置下。

    最后,我们在来安装下新浪云的 Eclipse 插件,具体安装的方法参见使用 Eclipse 插件部署 Java 应用

    至此,我们开发前的准备工作就完成了,接下来我们可以开始开发了。

    接下来的 Web 应用就可以根据自己的业务需求开始开发,就不说具体的开发过程了,下面着重介绍下新浪云相关服务的使用方法和注意事项。 我们先来建立一个 Servlet,通过这个 Servlet 来演示相关功能的展示,建立一个如下图的 package 在建立一个名为 test 的 Servlet。

    create-servlet

    然后可以通过 Eclipse 插件将应用上传到新浪云,插件使用见使用 Eclipse 插件部署 Java 应用,也就是你刚刚创建的应用,注意填写相关的信息。部署时间大约为 3 分钟,然后可以在浏览器里访问我们创建的 servlet 了,如下图。

    create-servlet

    这样,我们的 Servlet 的就建立好了,接下来我们的演示就基于这个 Servlet 展开介绍。

    MySQL

    新浪云的数据库服务有两种,一种是共享型数据库,一种是独享型数据库,但其实操作方式都是一样的,具体参看相关文档。以共享型数据库为例子吧,通过 jdbc 方式即可连接。

    首先,在新浪云控制面板中创建自己的共享型 mysql 实例,然后在pom.xml里添加下 jdbc 驱动

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.20</version>
    </dependency>
    

    然后,在咱们刚刚创建的 Serlvet 中,添加如下代码。

    String driver = "com.mysql.jdbc.Driver";
    String username = System.getenv("ACCESSKEY");
    String password = System.getenv("SECRETKEY");
    String dbName = System.getenv("MYSQL_DB");
    String host = System.getenv("MYSQL_HOST");
    String port = System.getenv("MYSQL_PORT");
    String dbUrl = "jdbc:mysql://"+host+":"+port + "/" +dbName;
    try {
        Class.forName(driver);
        Connection conn = DriverManager.getConnection(dbUrl,username,password);
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("show status");
        while(rs.next()){
            response.getWriter().println(rs.getString("Variable_name") + " : " +rs.getString("value"));
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    

    通过插件在上传到你的应用上,稍等一会就能看到如下的效果。

    mysql

    这里只是展示了最基本的使用方法,有些项目中会使用连接池,连接池只需要注意一项,将 idle 时间调整到 10 秒以下即可,无论是独享型还是共享型都是如此。

    Memcached

    Memcached 服务同样也要在你创建的应用中开启面板,初始化一下。容器使用的 memcache 有 auth 认证,需要使用支持 SASL 协议的客户端,推荐使用spymemcached客户端,首先在pom.xml文件中添加如下依赖。

    <dependency>
        <groupId>net.spy</groupId>
        <artifactId>spymemcached</artifactId>
        <version>2.12.0</version>
    </dependency>
    

    同样,我们在刚刚我们新建的 servlet 中添加如下的代码。

    String username = System.getenv("ACCESSKEY");
    String password = System.getenv("SECRETKEY");
    String server = System.getenv("MEMCACHE_SERVERS");
    AuthDescriptor ad = new AuthDescriptor(new String[] { "PLAIN" },
            new PlainCallbackHandler(username, password));
    MemcachedClient mc = new MemcachedClient(
            new ConnectionFactoryBuilder().setProtocol(Protocol.BINARY).setAuthDescriptor(ad).build(),
            AddrUtil.getAddresses(server));
    OperationFuture<Boolean> of = mc.set("key", 0, "sinacloud");
    try {
        response.setCharacterEncoding("gbk");
        response.getWriter().println("设置结果是否成功:"+ of.get());
        response.getWriter().println("获取结果:"+mc.get("key"));
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    

    上传服务器后效果如下

    memcache

    这里只是简单的实现了 set 和 get 方法,其他的可以参看 spymemcached

    Redis

    新浪云 Redis 服务,类似于 Memcache 服务,先在pom.xml里添加一个 redis 的客户端,如 jedis

    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.0.0</version>
    </dependency>
    

    然后还是在刚刚建立的 Servlet 里添加如下代码。

    String redis_url = System.getenv("REDIS_URL");
    try {
        URI redisUri = new URI(redis_url);
        JedisPool pool = new JedisPool(new JedisPoolConfig(),redisUri.getHost(),redisUri.getPort(),Protocol.DEFAULT_TIMEOUT,redisUri.getUserInfo().split(":",2)[1]);
        Jedis jedis = pool.getResource();
        response.getWriter().println(jedis.set("key".getBytes(), "sinacloud".getBytes()));
        response.getWriter().println(jedis.get("key"));
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }
    

    最后上传到新浪云上,可以看到效果。如下图。

    redis

    MongoDB

    首先还是在pom.xml中添加一下依赖。

    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongo-java-driver</artifactId>
        <version>3.2.2</version>
    </dependency>
    

    同时也需要在面板里初始化服务。然后可以根据自己的需要在 mongodb 实例中创建库或者是集合,我自己建立了一个叫"test"的库,然后建立了一个叫"users"的集合。

    还是在那个 servlet 中插入如下的代码。

    MongoClientURI uri = new MongoClientURI("YOUR_MONGODB_URL");
    MongoClient client = new MongoClient(uri);
    MongoDatabase db = client.getDatabase("test");
    MongoCollection<Document> users = db.getCollection("users");
    Document user = new Document("key", "sinacloud");
    users.insertOne(user);
    response.getWriter().println(users.find(user).iterator().next().get("key"));
    

    然后上传到新浪云,可以看到如下结果

    mongodb

    存储服务

    这里还是在上面建立的那个 Servlet 演示操作。对于容器 Java,我们提供了一套 SDK 支持,相关存储的操作,SDK 已经放在了 maven 的中央仓库上,可以通过 maven 进行下载,在项目的pom.xml中添加如下依 赖。

    <dependency>
        <groupId>com.sinacloud.java</groupId>
        <artifactId>java-sdk</artifactId>
        <version>1.2.1</version>
    </dependency>
    

    目前,SDK 里包含了 kvdb(已经在 1.2.2 版本中去除)、云存储、Storage,以后新的服务,会在不断的增加。

    Storage

    Storage 服务是新浪云开发的一套对象存储服务,首先也要在面板上开启服务,初始化,然后在 servlet 中添加如下的代码。

    StorageClient sc = new StorageClient();
    sc.createBucket("testbucket");
    sc.putObjectFile("testbucket", "test.txt", "test storage client upload text".getBytes(), null);
    

    然后上传到新浪云上,然后访问一下 Servlet,之后可以在自己 Storage 面板里,可以看到文件。如下图

    storage

    云存储

    参见云存储,有详细的 API

    分布式 Session

    多实例的情况下,准备了两种解决方案,一种是粘滞会话,另一种是第三方 Session 存储。粘滞会话可以在创建应用的时候开启。下面演示一下使用第三方 Redis 服务存储 Session

    为了方便演示,我先把我测试的容器实例扩展到多个,到了 3 个 JVM,如图所示。

    session

    然后我们创建一个 redis 服务,具体创建参见 Redis 文档,然后进入"应用"->"环境变量面板",点击添加环境变量,添加以下两个环境变量。添加如下的环境变量。

    • REDISURL="YOURREDIS_URL"
    • SESSION_MANAGER=REDIS

    然后我们重启下我们的应用。

    还是在我们上面创建的 Servlet 里演示

    HttpSession session = request.getSession();
    session.setAttribute("key", "sinacloud");
    response.getWriter().println(session.getAttribute("key"));
    

    然后我们访问下我们的 Servlet,如下图。

    session

    最后我们在确认下是否将 Session 的数据存储到了 Redis,进入到 Redis 控制面板,点击管理,输入如下命令。

    • keys *

    可以看到如下的效果。

    session

    可以看到,由 Tomcat 自主存的 Session 信息,都在我们的 Redis 里了,这样就可以实现多实例之间的 Session 共享了。如果使用过程中需要存储对象,要预先对对象进行序列化

    最后

    以上简单的介绍了一下,新浪云容器环境 Java 相关的问题,主要是在新浪云相关的服务上,如果以后有新的服务或者问题,我会继续更新相关的使用方法和文档。当然使用中如果遇到上面问题,可以提交工单 求助。

    具体相关的服务可以参看容器服务的文档中心

  • 全文搜索服务下线通知

    由于产品的升级调整,我们将于本月底(2016-08-31)下线『全文搜索』服务。

    现有全文搜索服务用户可以迁移至我们新的 『Elasticsearch』 服务,详细见:https://www.sinacloud.com/doc/sae/services/es.html

    为了方便用户尽快的迁移,我们提供了一个基于 Elasticsearch 的全文搜索兼容客户端( 点击这里下载 ),你可以直接使用这个客户端替换之前的全文搜索客户端。详细的使用说明见客户端文档。

    如果你在迁移过程中遇到问题,可以通过 工单系统 联系我们,我们提供迁移数据所需的全部支持。

  • PHP Web 服务器添加.htaccess 配置文件支持

subscribe via RSS