OTS构建SpringMVC REST风格的准实时系统

一、简介

        利用OTS为系统提供准实时系统交易流水持久化和离线批量数据存储服务。各系统的支撑系统,所有信息都会调用该服务,访问量大,存储和访问速度要求快,故服务的构建采用REST风格(SpringMVC框架天然的支持REST风格请求),对于准实时请求的响应和数据存储,采用NoSQL数据存储,即OTS。

 

        在网站访问量还不大的情况下,单个数据库完全可以应付。随着访问量的上升,几乎大部分使用MySQL架构的网站在数据库上都开始出现了性能问题,web程序不再仅仅专注在功能上,同时也在追求性能。RDS for MySQL会从主从读写分离、分库分表(DRDS)多方面解决高并发的问题。大数据量高并发环境下的MySQL应用开发越来越复杂,分表分库的规则把握都是需要经验的。虽然有像淘宝这样技术实力强大的公司开发了透明的中间件层来屏蔽开发者的复杂性,但是避免不了整个架构的复杂性。

        MySQL数据库也经常存储一些大文本字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库。比如1000万4KB大小的文本就接近40GB的大小,如果能把这些数据从MySQL省去,MySQL将变得非常的小。关系数据库很强大,但是它并不能很好的应付所有的应用场景。MySQL的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySQL的开发人员面临的问题。

        而采用NoSQL可以避免如上的细节问题,NoSQL的优势:
        NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。
        NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。
        NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。这点在大数据量的web2.0时代尤其明显。

 

        阿里云表格存储(TableStore)OTS是 NoSQL 数据库的一种,提供海量 NoSQL 数据存储,支持 schemafree 的数据模型,提供单行级别的事务。服务端自动对数据进行分区和负载均衡,让单表数据从 GB 到 TB 再到 PB,访问并发从 0 至百万都无需繁琐的扩容流程,写性能在 TB 及 PB 级数据规模都能保持在单个毫秒,读性能只依赖结果数据集,而不受数据量的影响。所以相比 OLTP(联机事务处理)场景,表格存储更适用于 Web 规模级应用程序,包括社交网络、游戏、媒体共享和 IoT(物联网)、日志监控等场景。

 

 

二、框架搭建

    

1、浏览器发送rest请求


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

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

<!-- Head -->

<head>

    <meta charset="utf-8" />

    <title>SpringMVC - Rest</title>

     

    <meta name="description" content="Dashboard" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <meta http-equiv="X-UA-Compatible" content="IE=edge" />

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <link rel="shortcut icon" href="assets/img/favicon.png"

        type="image/x-icon">

</head>

<!-- /Head -->

<!-- Body -->

<body>

    <!-- Page Body -->

    <div class="page-body">

        <div class="row">

            <div class="col-lg-12 col-sm-12 col-xs-12">

                <div class="widget flat radius-bordered">

                    <div class="widget-header bordered-bottom bordered-themeprimary">

                        <i class="widget-icon fa fa-text-width"></i> <span

                            class="widget-caption">OTS构建SpringMVC REST风格的准实时系统</span>

                        <div class="widget-buttons">

                            <a href="#" data-action="refresh"> <i class="fa fa-undo"></i>

                            </a> <a href="#" data-toggle="config"> <i class="fa fa-cog"></i>

                            </a> <a href="#" data-toggle="maximize"> <i class="fa fa-expand"></i>

                            </a> <a href="#" data-toggle="collapse"> <i class="fa fa-minus"></i>

                            </a> <a href="#" data-toggle="dispose"> <i class="fa fa-times"></i>

                            </a>

                        </div>

                        <!--Widget Buttons-->

                    </div>

                    <!--Widget Header-->

                    <div class="widget-body no-padding">

                        <div class="widget-main">

                            <table class="table">

                                <thead>

                                    <tr>

                                        <th width="30%">返回类型</th>

                                        <th>请求示例</th>

                                    </tr>

                                </thead>

                                <tbody>

                                    <tr>

                                        <td>Web Page</td>

                                        <td>

                                            <h5>

                                                查询用户name为

                                                <a href="./getPageResult/许士">许士</a> 的记录.

                                            </h5>

                                            <h5>

                                                查询用户name为

                                                <a href="./getPageResult/柯思">柯思</a> 的记录.

                                            </h5>

                                        </td>

                                    </tr>

                                    <tr>

                                        <td>JSON</td>

                                        <td>

                                            <h5>

                                                查询用户name为

                                                <a href="./getJsonResult/许士">许士</a> 的记录.

                                            </h5>

                                            <h5>

                                                查询用户name为

                                                <a href="./getJsonResult/柯思">柯思</a> 的记录.

                                            </h5>

                                        </td>

                                    </tr>

                                    </tbody>

                            </table>

                        </div>

                        <!--Widget Main Container-->

                    </div>

                    <!--Widget Body-->

                </div>

                <!--Widget-->

            </div>

        </div>

    </div>

</body>

<!--  /Body -->

</html>

 

2、Controller层映射对应方法

返回界面:


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

package com.zt.mvc.web.controller;

import java.util.List;

import org.springframework.stereotype.Controller;

import org.springframework.ui.ModelMap;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import com.zt.mvc.web.model.User;

import com.zt.ots.OTSOperation;

 

@Controller

@RequestMapping("/getPageResult")

class WebController {

     

    /**

     * 查询name=传入值的OTS记录

     * @param name

     * @param model

     * @return

     */

    @RequestMapping(value = "/{name}", method = RequestMethod.GET)

    public String getName(@PathVariable String name, ModelMap model) {

        // 调用OTS查询功能

        List<User> users = OTSOperation.getRowByFilter(name);

         

        if(users != null && users.size() > 0)

            model.addAttribute("user", users.get(0));

        else

            model.addAttribute("user"new User());

        return "result";

    }

}

 

返回JSON:


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

39

40

41

42

43

44

45

46

47

48

package com.zt.mvc.web.controller;

import java.util.List;

import org.slf4j.Logger;

import org.springframework.http.HttpStatus;

import org.springframework.http.ResponseEntity;

import org.springframework.stereotype.Controller;

import org.springframework.ui.ModelMap;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import com.zt.mvc.web.error.ErrorHolder;

import com.zt.mvc.web.exception.ResourceNFException;

import com.zt.mvc.web.model.User;

import com.zt.ots.OTSOperation;

@Controller

@RequestMapping("/getJsonResult")

class JSonController {

     

    /**

     * 根据name查询,返回user对象

     * @param name

     * @param model

     * @return

     * @throws ResourceNFException

     */

    @RequestMapping(value = "/{name}", method = RequestMethod.GET)

    @ResponseBody

    public User getName(@PathVariable String name, ModelMap model) throws ResourceNFException {

        System.out.println("Name: " + name);

        List<User> users = OTSOperation.getRowByFilter(name);

         

        if(users != null && users.size() > 0)

            return users.get(0);

        else

            return new User();

    }

 

    @ExceptionHandler

    @ResponseBody

    public ResponseEntity<ErrorHolder> handle(ResourceNFException e) {

        Logger logger = null;

        logger.warn("The resource was not found", e);

        return new ResponseEntity<ErrorHolder>(new ErrorHolder("The resource was not found"),

            HttpStatus.NOT_FOUND);

    }

}

 

3、OTS过滤器查询


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

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

package com.zt.ots;

import java.util.Iterator;

import java.util.LinkedList;

import java.util.List;

import com.aliyun.openservices.ots.ClientException;

import com.aliyun.openservices.ots.OTSClient;

import com.aliyun.openservices.ots.OTSException;

import com.aliyun.openservices.ots.model.ColumnValue;

import com.aliyun.openservices.ots.model.PrimaryKeyValue;

import com.aliyun.openservices.ots.model.RangeIteratorParameter;

import com.aliyun.openservices.ots.model.Row;

import com.aliyun.openservices.ots.model.RowPrimaryKey;

import com.aliyun.openservices.ots.model.condition.RelationalCondition;

import com.zt.mvc.web.model.User;

/**

 * @author wanglu

 * 描述:OTS 操作类

 *

 */

public class OTSOperation {

    private static final String COLUMN_GID_NAME     = "gid";

    private static final String COLUMN_UID_NAME     = "uid";

    private static final String COLUMN_NAME_NAME    = "name";

    private static final String COLUMN_ADDRESS_NAME = "address";

    private static final String COLUMN_AGE_NAME     = "age";

    private static final String COLUMN_MOBILE_NAME  = "mobile";

    /**

     * 使用过滤功能读取一行数据

     * @param gid

     * @param uid

     */

    public static List<User> getRowByFilter(String name) {

        final String endPoint = "http://cloud-report.cn-shanghai-zty-d01.ots.dcp.dev.ect-it.com";

        final String accessId = "<access_key_id>";

        final String accessKey = "<access_key_sceret>";

        final String instanceName = "cloud-report";// 仅做测试的project

        OTSClient client = new OTSClient(endPoint, accessId, accessKey, instanceName);

        final String tableName = "User_Info";

        try {

            // 查询范围为:start primary key = (gid=0, INF_MIN)

            //         end primary key   = (gid=500, INF_MAX)

            // 且满足条件为:name == '方法输入name值'的所有行。

            RangeIteratorParameter param = new RangeIteratorParameter(tableName);

            RowPrimaryKey startPk = new RowPrimaryKey();

            startPk.addPrimaryKeyColumn(COLUMN_GID_NAME, PrimaryKeyValue.fromLong(0));

            startPk.addPrimaryKeyColumn(COLUMN_UID_NAME, PrimaryKeyValue.INF_MIN);

            RowPrimaryKey endPk = new RowPrimaryKey();

            endPk.addPrimaryKeyColumn(COLUMN_GID_NAME, PrimaryKeyValue.fromLong(500));

            endPk.addPrimaryKeyColumn(COLUMN_UID_NAME, PrimaryKeyValue.INF_MAX);

            param.setInclusiveStartPrimaryKey(startPk);

            param.setExclusiveEndPrimaryKey(endPk);

            RelationalCondition filter = new RelationalCondition(COLUMN_NAME_NAME, RelationalCondition.CompareOperator.EQUAL, ColumnValue.fromString(name));

            param.setFilter(filter);

            Iterator<Row> rowIter = client.createRangeIterator(param);

            int totalRows = 0;

            List<User> result = new LinkedList<User>();

            User user;

            while (rowIter.hasNext()) {

                Row row = rowIter.next();

                user = new User();

                user.setGid(row.getColumns().get(COLUMN_GID_NAME).toString());

                user.setUid(row.getColumns().get(COLUMN_UID_NAME).toString());

                user.setName(row.getColumns().get(COLUMN_NAME_NAME).toString());

                user.setAddress(row.getColumns().get(COLUMN_ADDRESS_NAME).toString());

                user.setAge(row.getColumns().get(COLUMN_AGE_NAME).toString());

                user.setMobile(row.getColumns().get(COLUMN_MOBILE_NAME).toString());

                result.add(user);

                totalRows++;

                System.out.println(row);

            }

            System.out.println("Total rows read: " + totalRows);

             

            // 如果没有抛出异常,则说明成功

            System.out.println("Get row succeeded.");

            return result;

        catch (ClientException ex) {

            // 如果抛出客户端异常,则说明参数等有误

            System.out.println("Get row failed.");

        catch (OTSException ex) {

            // 如果抛出服务器端异常,则说明请求失败

            System.out.println("Get row failed.");

        finally {

            client.shutdown();

        }

         

        return null;

    }

}

 

 

4、查询结果返回前端显示


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

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

<!-- Head -->

<head>

    <meta charset="utf-8" />

    <title>SpringMVC - Rest</title>

     

    <meta name="description" content="Dashboard" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <meta http-equiv="X-UA-Compatible" content="IE=edge" />

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <link rel="shortcut icon" href="../assets/img/favicon.png"

        type="image/x-icon">

</head>

<body>

    <!-- Page Body -->

    <div class="page-body">

        <!-- Stacked To horizontal -->

        <h5 class="row-title before-blue">Rest请求结果:</h5>

        <div class="grid-example">

            <div class="row">

                <div class="col-md-3">Name - ${user.name}</div>

                <div class="col-md-3">Address - ${user.address}</div>

                <div class="col-md-3">Age - ${user.age}</div>

                <div class="col-md-3">Mobile - ${user.mobile}</div>

            </div>

        </div>

    </div>

</body>

<!--  /Body -->

</html>

 

 

三、示例运行

1、首界面

    将项目部署到Tomcat中,启动Tomcat,浏览器中输入地址:localhost:8080/rest-springmvc-ots/,回车

2、返回结果为web page的请求

    在返回类型为web page中,点击‘许士’超链接,经过OTS准实时查询,观察到浏览器的链接变为:localhost:8080/rest-springmvc-ots/getPageResult/许士,该rest请求表示发送查询name为‘许士’的请求,返回OTS准实时查询结果。当然,不过不通过超链接,直接在浏览器窗口输入rest请求localhost:8080/rest-springmvc-ots/getPageResult/许士,也是可以的。

    再如,查询name为‘柯思’的记录:localhost:8080/rest-springmvc-ots/getPageResult/柯思

 

3、返回结果为json的请求

    在返回类型为json时,点击首页中的超链接,或者发送rest请求,即可得到OTS返回结果为JSON格式的结果:localhost:8080/rest-springmvc-ots/getJsonResult/许士:

    再如,查询name为‘柯思’的记录:localhost:8080/rest-springmvc-ots/getJsonResult/柯思

 

 

四、开发建议

     开发参考:OTS 开发参考 Git:https://github.com/aliyun/aliyun-tablestore-java-sdk

     开发参考:SpringMVC REST开发参考:http://jinnianshilongnian.iteye.com/blog/1996071

     使用参考:Gogs:https://www.oschina.net/p/gogs

时间: 2024-11-02 20:50:12

OTS构建SpringMVC REST风格的准实时系统的相关文章

快速构建Windows 8风格应用17-布局控件

原文:快速构建Windows 8风格应用17-布局控件 本篇博文主要介绍三种常用的布局控件:Canvas.Grid.StackPanel. Panel类是开发Windows 8 Store应用中一个重要类,它在Windows 8 Store应用布局系统中扮演非常重要角色. Panel可以承载多个子元素,面板类可以把子元素存放在栈中.或网格里面.或把子元素停靠在其边缘等. Panel类自身是一个抽象类,下面是Panel类的层次结构: Windows 8 Store应用中包含的三个标准布局控件:Ca

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【四】——实现模型工厂,依赖注入以及格式配置

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[四]--实现模型工厂,依赖注入以及格式配置 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在上一篇中,我们已经初步开始使用Web Api了,但同时出现了一些很多不足之处,本章我们就着重来解决这些不足. 上篇导航:http://www.cnblogs.com/fzrain/p/3510035.html 配置JSON的格式 Web Api提供Xml和JSON作

快速构建Windows 8风格应用21-构建简单媒体播放器

原文:快速构建Windows 8风格应用21-构建简单媒体播放器 本篇博文主要介绍如何构建一个简单的媒体播放器. <快速构建Windows 8风格应用20-MediaElement>博文中提到了如何使用MediaElement对象进行播放视频的简单功能,但是在实际应用中需要更复杂的功能,例如:控制视频播放的控件.全屏模式.进度条等等其他功能. 本篇博文中示例使用应用程序中包含的媒体文件,当然我们也可以通过网络或者本地[使用FileOpenPicker]进行加载某一媒体文件. MSDN中关于媒体

快速构建Windows 8风格应用2-创建调试应用

原文:快速构建Windows 8风格应用2-创建调试应用 本篇博文主要介绍的是创建应用时可以选择哪些模版,生成默认的Windows 8风格应用解决方案中含哪些文件,最后是如何调试Windows 8风格应用. 我们如何使用Visual Studio 2012创建Windows 8风格应用呢?可归结为以下几步: 1.选择我们要使用的开发语言,例如:JavaScript.C++.C#.Visual Basic. 2.选择项目模版,可以选择以下常用的项目模版: 1)拆分应用(Split App)模版  

快速构建Windows 8风格应用25-数据绑定

原文:快速构建Windows 8风格应用25-数据绑定 本篇博文主要介绍如何将UI元素与数据进行绑定.数据绑定的方向.数据更改通知.数据转换.数据绑定支持的绑定方案. 数据绑定是一种简单方式来显示数据,UI元素与数据对象之间的连接或绑定是允许数据在两者之间流动的.另外建立了绑定且数据发生变化时,相应的UI元素会自动显示变化.   如何将UI元素与数据进行绑定   从上面图可以知道,每个绑定必须指定一个源和一个目标. 其中源对象可以是任何CLR对象,包括目标元素自身和其他UI元素.目标可以是Fra

快速构建Windows 8风格应用20-MediaElement

原文:快速构建Windows 8风格应用20-MediaElement 本篇博文主要介绍MediaElement概述.MediaElement对象介绍.MediaElement常用属性.如何控制媒体播放.   MediaElement概述 通常在Windows 8风格应用中播放音频或视频文件时是使用MediaElement类进行构建的. MediaElement对象提供了用于播放视频或音频的属性和方法. 相关MediaElement的开发示例可参考该链接:XAML media playback

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【十】——使用CacheCow和ETag缓存资源

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[十]--使用CacheCow和ETag缓存资源 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 本文将使用一个开源框架CacheCow来实现针对Http请求资源缓存,本文主要介绍服务器端的缓存. 使用缓存技术可以很好的提高Web Api的性能,减小服务器的开销.我们把这种缓存形式称之为:条件化请求(Conditional Requests).具体表现为:客户

快速构建Windows 8风格应用36-商店应用发布流程

原文:快速构建Windows 8风格应用36-商店应用发布流程 引言 在发布应用之前,我们需要注册开发者账号才能够发布应用.我们可以登录https://appdev.microsoft.com/StorePortals/ 该网址进行注册开发者账号,同时我们也可以点击这里来浏览MSDN给到的开发者账号注册的详细步骤.那么注册完成开发者账号后,如何发布Windows Store 应用程序呢? Windows Store App 发布流程 1,使用Visual Studio 2012打开要上传的应用,

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【开篇】【持续更新中。。。】

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[开篇][持续更新中...] 最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http://bitoftech.net/2013/11/25/detailed-tutorial-building-asp-net-web-api-restful-service/.于是打算跟着学一下,把学习过程记录在博客园的同时也分享给大家. 每一篇结束后我都会把代码共享 由于