天天看點

Lindorm Serverless + CQL + Springboot,快速搭建彈性Web服務背景前期準備工作生成SpringBoot項目構造使用者管理頁面啟動檢視更多進階功能

背景

作為面向大資料場景的半結構化、結構化存儲系統,Lindorm已經在阿裡發展了近十年,并始終保持着快速的能力更新和技術更新,是目前支撐阿裡經濟體業務的核心資料庫産品之一。其在功能、性能、穩定性等方面的諸多創新曆經了長時間的大規模實踐考驗,被全面應用于阿裡集團、螞蟻集團、菜鳥、大文娛等各個業務闆塊,成為目前為止公司内部資料體量最大、覆寫業務最廣的資料庫産品。

Lindorm Serverless 支援按需計費,彈性擴充,最大限度的降低了使用者使用門檻,運維難度和容量規劃操作。Lindorm CQL完全相容了cassandra社群的Query Language,提供了類SQL的查詢能力,可以非常快速的結合spring等架構,幫助業務邏輯快速開發。本文以一個簡單的使用者管理系統為例子,介紹如何給予Lindorm快速建構一個web服務,這個系列後續也會介紹更多複雜的使用方式。

前期準備工作

公有雲使用者

在阿裡雲首頁搜尋Lindorm,進入Lindorm管理控制台購買Lindorm Serverless叢集,可以根據需求選擇包年包月或者按量付費。

Lindorm Serverless + CQL + Springboot,快速搭建彈性Web服務背景前期準備工作生成SpringBoot項目構造使用者管理頁面啟動檢視更多進階功能
Lindorm Serverless + CQL + Springboot,快速搭建彈性Web服務背景前期準備工作生成SpringBoot項目構造使用者管理頁面啟動檢視更多進階功能

已經有叢集版執行個體子的同學可以跳過這個步驟。

購買成功之後,執行個體清單就包含了一個LindormServerless類型的執行個體在執行個體管理頁面找到連接配接資訊頁面,開通公網通路,擷取叢集連結串。

Lindorm Serverless + CQL + Springboot,快速搭建彈性Web服務背景前期準備工作生成SpringBoot項目構造使用者管理頁面啟動檢視更多進階功能

連結資訊中預設都存在"CQL連接配接",預設的連結位址是包括了VPC環境下的位址和端口,也可以執行公網開放功能擷取公網位址和端口。Lindorm使用CQL通路都是走認證的,預設使用者名和預設密碼在使用者控制台可以看到,通過該地方擷取的使用者名和密碼可以通路走CQL通路Lindorm。

Lindorm Serverless + CQL + Springboot,快速搭建彈性Web服務背景前期準備工作生成SpringBoot項目構造使用者管理頁面啟動檢視更多進階功能

至此Lindorm的叢集的購買工作就已經完成了。

了解Cqlsh

執行建表和KeySpace操作使用者可以通過cqlsh通路lindorm serverless,操作方式請參考

cqlsh使用指南

下載下傳到CQLSH的代碼後,可以通過如下指令通路Shell

./cqlsh $host $port -u $username -p $password           

其中host指的是CQL連結串中:9042之前的部分,port不填寫預設為9042

建立namespace和table

cqlsh> CREATE KEYSPACE test_keyspace WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}  AND durable_writes = true;
cqlsh> use test_keyspace;
cqlsh:test_keyspace> CREATE TABLE user (id BIGINT , username text,  age int, password text, PRIMARY KEY (id)) ;           

對應的CQL表結構

CREATE TABLE test_keyspace.user (   

id bigint PRIMARY KEY,   

username text,   

age int, 

password text);

生成SpringBoot項目

在開始實際編碼之前,建議先閱讀下官方文檔,了解

Spring Data for Cassandra項目

Spring模版生成器

中生成項目模版,所需配置如下圖:

Lindorm Serverless + CQL + Springboot,快速搭建彈性Web服務背景前期準備工作生成SpringBoot項目構造使用者管理頁面啟動檢視更多進階功能

生成出來的項目下載下傳後導入進Idea,大概如下

Lindorm Serverless + CQL + Springboot,快速搭建彈性Web服務背景前期準備工作生成SpringBoot項目構造使用者管理頁面啟動檢視更多進階功能

現在我們就擁有了一個完整spring on cql,接下來的工作就是完善代碼構造一個使用者管理頁面啦。

構造使用者管理頁面

定義域模型(實體類)

本文主要針對單個使用者主鍵場景,所有的讀寫操作都是針對主鍵ID來執行,注意主鍵需要标注PrimaryKey。使用者ID作為主鍵是全局唯一的,重複寫入一個使用者ID會發生覆寫。

/*
 * Copyright Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.lindorm.cqldemo.entity;
import org.springframework.data.cassandra.core.mapping.CassandraType;
import org.springframework.data.cassandra.core.mapping.PrimaryKey;
import org.springframework.data.cassandra.core.mapping.Table;
@Table(value = "user")
public class UserTable {
    @PrimaryKey
    @CassandraType(type = CassandraType.Name.BIGINT)
    private long id;
    private String username;
    private String password;
    private int age;
    public long getId() {
        return id;
    }
    public UserTable setId(long id) {
        this.id = id;
        return this;
    }
    public String getUserName() {
        return username;
    }
    public UserTable setUserName(String username) {
        this.username = username;
        return this;
    }
    public String getPassword() {
        return password;
    }
    public UserTable setPassword(String password) {
        this.password = password;
        return this;
    }
    public int getAge() {
        return age;
    }
    public UserTable setAge(int age) {
        this.age = age;
        return this;
    }
}           

定義spring-data接口

這裡主要繼承了CrudRepository,包括了比較常見的增删改查

* Copyright Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.lindorm.cqldemo.entity;
package com.alibaba.lindorm.cqldemo.repository;
import com.alibaba.lindorm.cqldemo.entity.UserTable;import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<UserTable, Long> {
    UserTable findById(long id);
    void deleteById(Long id);
}           

CrudRepository的接口定義如下

public interface CrudRepository<T, ID> extends Repository<T, ID> {
  <S extends T> S save(S var1);
  <S extends T> Iterable<S> saveAll(Iterable<S> var1);
  Optional<T> findById(ID var1);
  boolean existsById(ID var1);
  Iterable<T> findAll();
  Iterable<T> findAllById(Iterable<ID> var1);
  long count();
  void deleteById(ID var1);
  void delete(T var1);
  void deleteAll(Iterable<? extends T> var1);
  void deleteAll();
}           

定義service

咱們這個簡單的demo代碼支援拿到使用者清單,寫入使用者資訊,更新使用者資訊,删除使用者等基本功能,其支援的基本功能如圖。

/*
 * Copyright Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.lindorm.cqldemo.service;
import com.alibaba.lindorm.cqldemo.entity.UserTable;
import java.util.List;
public interface UserService {
    public List<UserTable> getUserList();
    public UserTable findUserById(long id);
    public void save(UserTable userTable);
    public void edit(UserTable userTable);
    public void delete(long id);
}
/*
 * Copyright Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.lindorm.cqldemo.service;
import com.alibaba.lindorm.cqldemo.entity.UserTable;
import com.alibaba.lindorm.cqldemo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;
    @Override
    public List<UserTable> getUserList() {
        List<UserTable> userList = new ArrayList<>();
        for (UserTable table : userRepository.findAll()) {
            userList.add(table);
        }
        return userList;
    }
    @Override
    public UserTable findUserById(long id) {
        return userRepository.findById(id);
    }
    @Override
    public void save(UserTable userTable) {
        userRepository.save(userTable);
    }
    @Override
    public void edit(UserTable userTable) {
        userRepository.save(userTable);
    }
    @Override
    public void delete(long id) {
        userRepository.deleteById(id);
    }
}
            

完成webcontroller

UserController實作基本的跳轉功能,将咱們的前段頁面跟service關聯起來。

* Copyright Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.lindorm.cqldemo.web;
import com.alibaba.lindorm.cqldemo.entity.UserTable;
import com.alibaba.lindorm.cqldemo.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
import java.util.List;
@Controller
public class UserController {
    @Resource UserService userService;
    @RequestMapping("/")
    public String index() {
        return "redirect:/list";
    }
    @RequestMapping("/list")
    public String list(Model model) {
        List<UserTable> userTables = userService.getUserList();
        model.addAttribute("userTables", userTables);
        return "user/list";
    }
    @RequestMapping("/toAdd")
    public String toAdd() {
        return "user/userAdd";
    }
    @RequestMapping("/add")
    public String add(UserTable userTable) {
        userService.save(userTable);
        return "redirect:/list";
    }
    @RequestMapping("/toEdit")
    public String toEdit(Model model,Long id) {
        UserTable userTable = userService.findUserById(id);
        model.addAttribute("userTable", userTable);
        return "user/userEdit";
    }
    @RequestMapping("/edit")
    public String edit(UserTable userTable) {
        userService.edit(userTable);
        return "redirect:/list";
    }
    @RequestMapping("/delete")
    public String delete(Long id) {
        userService.delete(id);
        return "redirect:/list";
    }
}           

完成前端頁面

前端頁面的具體代碼,請參考具體的示例代碼。總共實作了3個頁面,list.html負責使用者展示,userAdd.html負責使用者添加,userEdit.html負責使用者更新頁面。

完成main函數

* Copyright Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.lindorm.cql.springdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class CqlDemoApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(CqlDemoApplication.class);
    }
    public static void main(String[] args) throws Exception {
        System.out.println(System.getProperty("java.class.path"));
        SpringApplication.run(CqlDemoApplication.class, args);
    }
}           

增加cassandra連結參數

通過繼承AbstractCassandraConfiguration來指定連結的EndPoint,使用者名,密碼等資訊。使用者名密碼可以通過阿裡雲管控系統或者Afanty上擷取。

* Copyright Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.lindorm.cqldemo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.AbstractCassandraConfiguration;
import org.springframework.data.cassandra.config.CqlSessionFactoryBean;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
@Configuration
@EnableCassandraRepositories
public class CassandraConfig extends AbstractCassandraConfiguration {
  private String hostList = "ld-bp1r9jd815x6y8w4d-proxy-lindorm-pub.lindorm.rds.aliyuncs.com";
  private String keyspaceName = "test_keyspace";
    //需要填寫自己叢集的對應賬号
  private String userName = "xxx";
    //需要填寫自己叢集的對應密碼
  private String password = "xxx";
  @Override
  protected String getLocalDataCenter() {
    return "datacenter1";
  }
  protected String getContactPoints() {
    return hostList;
  }
  public String getKeyspaceName() {
    return keyspaceName;
  }
  @Override
  public CqlSessionFactoryBean cassandraSession() {
    CqlSessionFactoryBean cqlSessionFactoryBean = super.cassandraSession();
    cqlSessionFactoryBean.setPassword(password);
    cqlSessionFactoryBean.setUsername(userName);
    return cqlSessionFactoryBean;
  }
}           

當然,你也可以通過更改application.properties調整cassandra參數,需要注意contact-points, username,password這幾個參數是必須填寫的,詳細的參數請參考spring-cassandra的官方文檔。

啟動檢視

執行main函數,如果一切符合的預期的話,我們的webserver已經可以正常拉起,可以在本機localhost:8080端口通路這個簡易的使用者管理系統。

Lindorm Serverless + CQL + Springboot,快速搭建彈性Web服務背景前期準備工作生成SpringBoot項目構造使用者管理頁面啟動檢視更多進階功能

我們可以測試添加一個新的使用者3,也可以修改删除和删除某個使用者,一個擁有最基礎的功能的使用者管理系統就已經完成啦!

Lindorm Serverless + CQL + Springboot,快速搭建彈性Web服務背景前期準備工作生成SpringBoot項目構造使用者管理頁面啟動檢視更多進階功能

增加css修飾網頁

我們的頁面還沒有經過任何修飾,感覺很粗糙,在resources/static/css目錄加入bootstrap.css檔案,修飾下我們的網頁,使我們的網頁變得更加美觀!

Lindorm Serverless + CQL + Springboot,快速搭建彈性Web服務背景前期準備工作生成SpringBoot項目構造使用者管理頁面啟動檢視更多進階功能

更多進階功能

本文隻涉及了單一主鍵場景下基于主鍵進行增删改查的簡單例子。實際上spring + cql + lindorm serverless還可以支援更加強大的能力,比如複合主鍵,二級索引,多元索引等。想了解更多如何關于Lindorm的能力,請參考Lindorm使用文檔

https://help.aliyun.com/product/172543.html?spm=5176.15155444.J_5253785160.4.28925d80aDpnwq

。 也請期待本文的姊妹篇,springboot + lindorm建構使用者賬單系統,我們會更加詳盡的介紹如何設計複合主鍵,二級索引等能力。

Have fun with the demo!

DEMO位址:

https://yisu-emr-test.oss-cn-hangzhou.aliyuncs.com/cqldemosimple.tar.gz?Expires=1607326773&OSSAccessKeyId=TMP.3KiP9R7i9DAuKNBj819jEy4eGDUXkmP6VRftrYKvRvgFvChWLYtEjirTNXExELzg7M8at6w2YaK3EaFxSJfyq45mc2rM2v&Signature=KGJoI5QvXUd4ob4k2%2BTbl8u8EME%3D&versionId=CAEQGhiBgMC52YrOsRciIDBkYzIyMTM3ZjUzZjQyZGQ4ZDkzM2VjZTNmNjZmYmJk&response-content-type=application%2Foctet-stream