So sánh Java Spring Boot sang Golang Iris Framework bằng một số đoạn code ngắn so sánh side-by-side bạn nắm bắt nhanh sự khác biệt và tương đồng.


1. Tạo một API cơ bản trả về “Hello, World!”

Java Spring Boot

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class HelloWorldApplication {

    public static void main(String[] args) {
        SpringApplication.run(HelloWorldApplication.class, args);
    }

    @GetMapping("/hello")
    public String sayHello() {
        return "Hello, World!";
    }
}
java
  • Giải thích:
    • @SpringBootApplication kết hợp cấu hình tự động, quét bean và khởi động ứng dụng.
    • @RestController đánh dấu lớp này xử lý REST API.
    • @GetMapping("/hello") ánh xạ yêu cầu GET tới /hello.

Golang Iris Framework

package main

import "github.com/kataras/iris/v12"

func main() {
    app := iris.New()
    app.Get("/hello", func(ctx iris.Context) {
        ctx.Text("Hello, World!")
    })
    app.Listen(":8080")
}
go
  • Giải thích:
    • Iris sử dụng cách tiếp cận nhẹ nhàng hơn, không cần cấu hình phức tạp như Spring Boot.
    • app.Get ánh xạ yêu cầu GET tới /hello.
    • ctx.Text trả về chuỗi văn bản trực tiếp.

2. Xử lý tham số từ URL

Java Spring Boot

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

@RestController
public class UserController {

    @GetMapping("/user/{id}")
    public String getUserById(@PathVariable Long id) {
        return "User ID: " + id;
    }
}
java
  • Giải thích:
    • @PathVariable trích xuất tham số id từ URL.

Golang Iris Framework

package main

import "github.com/kataras/iris/v12"

func main() {
    app := iris.New()
    app.Get("/user/{id}", func(ctx iris.Context) {
        id := ctx.Params().Get("id")
        ctx.Text("User ID: " + id)
    })
    app.Listen(":8080")
}
go
  • Giải thích:
    • {id} là cú pháp định nghĩa tham số trong Iris.
    • ctx.Params().Get("id") lấy giá trị của tham số.

3. Xử lý JSON Request và Response

Java Spring Boot

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    static class User {
        private String name;
        // Getters và Setters
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }

    @PostMapping("/user")
    public User createUser(@RequestBody User user) {
        return user; // Echo back the input
    }
}
java
  • Giải thích:
    • @RequestBody ánh xạ dữ liệu JSON từ request vào đối tượng User.
    • Spring tự động serialize/deserialize JSON.

Golang Iris Framework

package main

import "github.com/kataras/iris/v12"

func main() {
    app := iris.New()
    app.Post("/user", func(ctx iris.Context) {
        type User struct {
            Name string `json:"name"`
        }
        var user User
        if err := ctx.ReadJSON(&user); err != nil {
            ctx.StatusCode(iris.StatusBadRequest)
            return
        }
        ctx.JSON(user) // Echo back the input
    })
    app.Listen(":8080")
}
  • Giải thích:
    • ctx.ReadJSON đọc JSON từ request và ánh xạ vào struct User.
    • ctx.JSON trả về phản hồi JSON.

4. Middleware (Xác thực cơ bản)

Java Spring Boot

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;

@RestController
public class AuthController implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("Authorization");
        if (token == null || !token.equals("secret")) {
            response.setStatus(401);
            return false;
        }
        return true;
    }

    @GetMapping("/secure")
    public String secureEndpoint() {
        return "Secure Data";
    }
}
java
  • Giải thích:
    • HandlerInterceptor được dùng để chặn request và kiểm tra header.

Golang Iris Framework

package main

import "github.com/kataras/iris/v12"

func authMiddleware(ctx iris.Context) {
    token := ctx.GetHeader("Authorization")
    if token != "secret" {
        ctx.StatusCode(iris.StatusUnauthorized)
        return
    }
    ctx.Next()
}

func main() {
    app := iris.New()
    app.Use(authMiddleware)
    app.Get("/secure", func(ctx iris.Context) {
        ctx.Text("Secure Data")
    })
    app.Listen(":8080")
}
  • Giải thích:
    • app.Use đăng ký middleware toàn cục.
    • ctx.Next() chuyển tiếp request nếu hợp lệ.

5. Render một HTML page sử dụng View Template

Java Spring Boot

  • Cấu hình: Dùng Thymeleaf làm template engine.
  • File cấu hình (application.properties):
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
  • Template (src/main/resources/templates/hello.html):
<!DOCTYPE html>
<html>
<head><title>Hello</title></head>
<body>
    <h1>Hello, <span th:text="${name}"></span>!</h1>
</body>
</html>
  • Controller:
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class TemplateController {

    @GetMapping("/hello")
    public String renderHello(Model model) {
        model.addAttribute("name", "Spring User");
        return "hello"; // Tên file template (hello.html)
    }
}
  • Giải thích:
    • @Controller (khác @RestController) cho phép render template.
    • Model truyền dữ liệu vào template.

Golang Iris Framework

  • Template (views/hello.html):
<!DOCTYPE html>
<html>
<head><title>Hello</title></head>
<body>
    <h1>Hello, {{.Name}}!</h1>
</body>
</html>
html
  • Code:
package main

import "github.com/kataras/iris/v12"

func main() {
    app := iris.New()
    app.RegisterView(iris.HTML("./views", ".html"))
    app.Get("/hello", func(ctx iris.Context) {
        ctx.ViewData("Name", "Iris User")
        ctx.View("hello.html")
    })
    app.Listen(":8080")
}
  • Giải thích:
    • RegisterView đăng ký thư mục chứa template.
    • ctx.ViewData truyền dữ liệu, ctx.View render file.

6. Upload file binary

Java Spring Boot

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;

@RestController
public class FileController {

    @PostMapping("/upload")
    public String uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
        if (!file.isEmpty()) {
            byte[] bytes = file.getBytes();
            return "Uploaded " + file.getOriginalFilename() + " (" + bytes.length + " bytes)";
        }
        return "No file uploaded";
    }
}
java
  • Giải thích:
    • @RequestParam("file") nhận file từ form multipart.
    • MultipartFile cung cấp API để xử lý file.

Golang Iris Framework

package main

import "github.com/kataras/iris/v12"

func main() {
    app := iris.New()
    app.Post("/upload", func(ctx iris.Context) {
        file, info, err := ctx.FormFile("file")
        if err != nil {
            ctx.Text("No file uploaded")
            return
        }
        defer file.Close()
        ctx.Text("Uploaded " + info.Filename)
    })
    app.Listen(":8080")
}
go
  • Giải thích:
    • ctx.FormFile lấy file từ request multipart.
    • info chứa metadata như tên file.

7. Kết nối PostgreSQL, truy vấn bảng và render HTML

  • Giả định: Có bảng users(id, name) trong PostgreSQL.

Java Spring Boot

  • Cấu hình (application.properties):
spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
spring.datasource.username=postgres
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
  • Entity (User.java):
import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class User {
    @Id
    private Long id;
    private String name;

    // Getters và Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}
java
  • Repository (UserRepository.java):
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}
java
  • Template (src/main/resources/templates/users.html):
<!DOCTYPE html>
<html>
<head><title>Users</title></head>
<body>
    <h1>Users</h1>
    <ul>
        <li th:each="user : ${users}" th:text="${user.name}"></li>
    </ul>
</body>
</html>
  • Controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {

    @Autowired
    private UserRepository userRepo;

    @GetMapping("/users")
    public String getUsers(Model model) {
        model.addAttribute("users", userRepo.findAll());
        return "users";
    }
}
java
  • Giải thích:
    • Spring JPA tự động quản lý kết nối và truy vấn.
    • userRepo.findAll() lấy toàn bộ dữ liệu từ bảng users.

Golang Iris Framework

  • Dependency: Cần cài go get -u github.com/lib/pq.
  • Template (views/users.html):
<!DOCTYPE html>
<html>
<head><title>Users</title></head>
<body>
    <h1>Users</h1>
    <ul>
        {{range .Users}}
            <li>{{.Name}}</li>
        {{end}}
    </ul>
</body>
</html>
html
  • Code:
package main

import (
    "database/sql"
    _ "github.com/lib/pq"
    "github.com/kataras/iris/v12"
)

func main() {
    app := iris.New()
    app.RegisterView(iris.HTML("./views", ".html"))

    db, _ := sql.Open("postgres", "postgres://postgres:password@localhost:5432/testdb?sslmode=disable")
    defer db.Close()

    app.Get("/users", func(ctx iris.Context) {
        type User struct {
            ID   int
            Name string
        }
        rows, _ := db.Query("SELECT id, name FROM users")
        defer rows.Close()

        var users []User
        for rows.Next() {
            var u User
            rows.Scan(&u.ID, &u.Name)
            users = append(users, u)
        }

        ctx.ViewData("Users", users)
        ctx.View("users.html")
    })
    app.Listen(":8080")
}
go
  • Giải thích:
    • sql.Open thiết lập kết nối thủ công tới PostgreSQL.
    • db.Query thực hiện truy vấn, kết quả được quét vào slice users.
    • Dữ liệu truyền vào template qua ctx.ViewData.

So sánh nhanh

  1. Template:

    • Spring Boot: Thymeleaf mạnh mẽ, tích hợp chặt với Java, nhưng cấu hình phức tạp hơn.
    • Iris: Dùng Go template, đơn giản, nhẹ, nhưng ít tính năng hơn.
  2. Upload file:

    • Spring Boot: MultipartFile cung cấp API tiện lợi, phù hợp với hệ sinh thái lớn.
    • Iris: FormFile đơn giản, trực tiếp, phù hợp với phong cách tối giản của Go.
  3. Database:

    • Spring Boot: JPA tự động hóa nhiều thứ (ORM), giảm code nhưng cần hiểu cấu hình.
    • Iris: Yêu cầu viết SQL thủ công, kiểm soát tốt hơn nhưng mất công hơn.

Lời khuyên

  • Thực hành: Tạo một dự án nhỏ với Iris (ví dụ: CRUD app) để làm quen với cách tổ chức code.
  • Tài liệu: Xem thêm về Iris ViewsGo PostgreSQL.
  • Debug: Với Go, chú ý xử lý lỗi (error handling) cẩn thận vì không có try-catch như Java.