Xây dựng app Chat đơn giản từ SpringBoot và React Native - Phần 2: Xây dựng API cho app Chat

Bài viết này gồm có 4 phần:

  • Dựng Database với Heroku PostgreSql
  • Xây dựng API cho ứng dụng Chat với Spring Boot
  • Deploy API lên Heroku
  • Xây dựng giao diện Chat đơn giản trên điện thoại với React Native

Kiến thức nền cho phần này:

Bước 1: Clone repository ChitChatAPI vào máy của bạn

Imgur

Hãy chắc chắn là làm được bước này nhé :sweat_smile: :sweat_smile:

Bước 2: Xây dựng ứng dụng Spring Boot đơn giản với Spring Initializr

Đối với tất cả các ứng dụng Spring, bạn nên bắt đầu với Spring Initializr. Initializr cung cấp một cách nhanh chóng tất cả các dependency bạn cần cho một ứng dụng và thực hiện sẵn configuration (cấu hình) cho bạn.

Imgur

Thực hiện từng bước như hình trên, trong đó số (1), (2), (3) có thể điền tùy ý. Ở đây mình đặt tên cho ứng dụng của mình là ChitChat. Sau khi nhấp vào số (4), hãy tìm kiếm và chọn dependency “Spring Web”, nó sẽ ra như số (5). Nhấp số (6) thì sẽ có một file zip được tải về. Các bạn giải nén và đưa vào thư mục ở bước 1.

Imgur

Bước 3: Mở project ChitChat bằng Eclipse

Thường là mình sẽ tạo một workspace riêng cho mỗi project mình làm, như vậy giúp cho mình đỡ rối rắm khi làm việc. Cách tạo workspace mới cũng khá đơn giản, chỉ cần tạo một thư mục mới (ở đây mình đặt tên là ChitChatWS) và trỏ vào thư mục đó thông qua File/Switch Workspace/Other. Nếu như bạn mới cài đặt Eclipse, thì Eclipse cũng yêu cầu bạn trỏ tới một workspace cụ thể ngay từ đầu. Sau đó nhấp Launch.

Imgur

Để mở project Spring trên Eclipse, mình thường dùng File/Import (Trong Select an import wizard: gõ Existing Maven Projects). Sau đó trỏ vào thư mục ChitChatAPI ở bước 1 và nhấp Finish.

Imgur

Sau đây là cấu trúc source code mà chúng ta sẽ tạo như sau:

Imgur

Lưu ý các package được tạo ra là riêng biệt, không có package nào là con của package nào.

Bước 4: Thiết lập các file Configuration

  • system.properties
java.runtime.version=1.8
  • Procfile

Tạo một file mới thông qua File/New/File, đặt tên là Procfile

web: java $JAVA_OPTS -jar target/chitchat-0.0.1-SNAPSHOT.jar --server.port=$PORT $JAR_OPTS
  • application.properties
#Port

server.port=${port:5000}



#Database

spring.datasource.url=${DATABASE_URL:}

spring.datasource.username=${DATABASE_USERNAME:}

spring.datasource.password=${DATABASE_PASSWORD:}

spring.datasource.driverClassName=${DATABASE_DRIVER:}



#Hibernate

spring.jpa.properties.hibernate.dialect=${SPRING_JPA_HIBERNATE_DIALECT:}

spring.jpa.properties.hibernate.id.new_generator_mappings = false

spring.jpa.properties.hibernate.show.sql = true

spring.jpa.properties.hibernate.format_sql = true

spring.jpa.generate-ddl=true

spring.jpa.properties.hibernate.hb2dll.auto = update

logging.level.org.hibernate.SQL=DEBUG

logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

  • .env

Tạo một file mới thông qua File/New/File, đặt tên là .env. Lưu ý file này sẽ cùng với Procfile ở trên, mặc định file .env sẽ chỉ thấy khi các bạn vào trong thư mục source code của project, tuy nhiên các bạn có thể mở trực tiếp file này trong Eclipse thông qua Navigate/Open Resources…, nhập tên .env.

Trong file này chúng ta sẽ khai báo các thông số kết nối Database Heroku mà đã làm ở phần 1 (trong bước 3).

Imgur

ENERGY=20 GeV

DATABASE_URL= //url your database

DATABASE_USERNAME= //your database username

DATABASE_PASSWORD= //your database password 

DATABASE_DRIVER=org.postgresql.Driver

SPRING_JPA_HIBERNATE_DIALECT=org.hibernate.dialect.PostgreSQL9Dialect

Bước 5: Tạo lớp Model

Message.java

import java.io.Serializable;
import java.sql.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "MESSAGES")
public class Message implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(name="username")
    private String username;
    @Column(name="password")
    private String password;
    @Column(name="messages")
    private String messages;
    @Column(name="status")
    private Integer status;
    @Column(name="created_on", insertable=false)
    private Date created_on;

    public Message() {}

    //getter setter here

}

Bước 6: Tạo lớp Repository

MessageRepository.java

import java.util.List;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import com.bienthaikieusa.chitchat.model.Message;

@Repository
public interface MessageRepository extends CrudRepository<Message, Long>{

    @Query("SELECT m FROM Message m WHERE LOWER(m.username) = LOWER(:username) ORDER BY m.id DESC")
    public List<Message> find(@Param("username") String username);

}

Bước 7: Tạo lớp Service

MessageService.java

import java.util.List;
import java.util.Optional;

import com.bienthaikieusa.chitchat.model.Message;

public interface MessageService {
    List<Message> findAll();
    Optional<Message> findLatestMessage(String username);
    void save(Message message);
    void remove(Message message);
    Optional<Message> findById(Long id);
    List<Message> findByUsername(String username);

}

Bước 8: Tạo lớp Service Implement

MessageServiceImpl.java

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.bienthaikieusa.chitchat.model.Message;
import com.bienthaikieusa.chitchat.repository.MessageRepository;
import com.bienthaikieusa.chitchat.service.MessageService;

@Service
public class MessageServiceImpl implements MessageService {

    @Autowired
    private MessageRepository messageRepository;

    @Override
    public Optional<Message> findLatestMessage(String username) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void save(Message message) {
        messageRepository.save(message);
    }

    @Override
    public void remove(Message message) {
        messageRepository.delete(message);

    }

    @Override
    public Optional<Message> findById(Long id) {
        return messageRepository.findById(id);
    }

    @Override
    public List<Message> findAll() {
        return (List<Message>) messageRepository.findAll();
    }

    @Override
    public List<Message> findByUsername(String username) {
        return messageRepository.find(username);
    }   
}

Bước 9: Tạo lớp Controller

MessageController.java

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import com.bienthaikieusa.chitchat.model.Message;
import com.bienthaikieusa.chitchat.service.MessageService;

@RestController
public class MessageController {

    @Autowired
    private MessageService messageService;

    @RequestMapping(value = "/messages", method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<List<Message>> findAllProduct() {
        List<Message> messages = messageService.findAll();
        if (messages.isEmpty()) {
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        }
        return new ResponseEntity<>(messages, HttpStatus.OK);
    }

    @RequestMapping(value = "/message/chat",method = RequestMethod.POST)
    public ResponseEntity<Message> createMessage(@RequestBody Message message, UriComponentsBuilder builder) {
        messageService.save(message);
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(builder.path("/message/{id}").buildAndExpand(message.getId()).toUri());
        return new ResponseEntity<>(message, HttpStatus.CREATED);
    }

    @RequestMapping(value = "/message/{id}", method = RequestMethod.DELETE)
    public ResponseEntity<Message> deleteProduct(@PathVariable("id") Long id) {
        Optional<Message> message = messageService.findById(id);
        if (!message.isPresent()) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        messageService.remove(message.get());
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    @RequestMapping(value = "/message/{id}",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Message> getMessageById(@PathVariable("id") Long id) {
        Optional<Message> message = messageService.findById(id);

        if (!message.isPresent()) {
            return new ResponseEntity<>(message.get(), HttpStatus.NO_CONTENT);
        }
        return new ResponseEntity<>(message.get(), HttpStatus.OK);
    }

    @RequestMapping(value = "/message",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<List<Message>> getMessageByUsername(@RequestParam(value="username") String username) {
         List<Message> messages = messageService.findByUsername(username);
         if (messages.isEmpty()) {
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
         }
         return new ResponseEntity<>(messages, HttpStatus.OK);
    }
}

Bước 10: Build project

Nhấp trái chuột project, chọn Run As/Run Configurations và làm theo như hình bên dưới:

Imgur

Trong đó số (1) là nhấp trái Maven Build, chọn New Configuration. Số (3) là nhấp vào Workspace, và chọn tên Project. Số (4) là gõ dòng lệnh spring-boot:run.

Nếu nhận được thông báo như sau tức là chúng ta đã build project thành công.

Imgur

Bước 11: Đẩy source code lên github.

Các bạn có thể clone source code của mình tại đây.

Nếu bạn thấy bài viết này hữu ích và muốn tiếp tục đọc các phần tiếp theo về chủ đề này, đừng ngần ngại like bài viết hay comment ý kiến của mình nhé.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

bienthaikieusa

11 bài viết.
1 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
7 1
Để tạo ra một sản phẩm bán chạy, bạn phải dựa trên đúng nhu cầu của các khách hàng tiềm năng. Cũng nguyên tắc tương tự, một trang Web không thể thà...
bienthaikieusa viết 7 tháng trước
7 1
White
4 0
"Master programmers think of systems as stories to be told rather than programs to be written.” – Robert C. Martin. (Tạm dịch: “Các lập trình viê...
bienthaikieusa viết 4 tháng trước
4 0
White
3 2
Đã bao giờ bạn nghĩ tới việc sẽ thử lòng người yêu, đồng nghiệp hay bất kỳ đối tượng nào bằng một khảo sát (survey) đơn giản? Và hơn nữa chỉ với mộ...
bienthaikieusa viết 7 tháng trước
3 2
Bài viết liên quan
White
48 26
Vừa rồi mình vừa tiết kiệm được $5 mỗi tháng sau khi migrate cái (Link) từ Digital Ocean sang Heroku Free Dyno. (Ảnh) Kết quả thật mĩ mãn vì hầu ...
Cẩm Huỳnh viết hơn 3 năm trước
48 26
White
3 0
I choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it. Bill Gates Mở bài Bác Gates đã bảo răng bác luôn ...
Nguyên Hoàng viết 1 năm trước
3 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
11 bài viết.
1 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!