598 words
3 minutes
User CRUD đơn giản với Java Spring Boot 3

Tạo project mới#

  • Có 2 cách tạo project Spring Boot:

    • Sử dụng Spring Initializr

    • Sử dụng Spring Tool Suite (STS) hoặc IntelliJ IDEA

  • Mình sẽ tạo trên Spring Initializr, vì nó đơn giản và nhanh chóng.

alt text- Project: Maven

  • Language: Java 17

  • Spring Boot: 3.4.1

  • Dependencies:

    • Lombok

    • H2 Database

    • Spring Data JPA

  • Cần thêm gì thì vô pom.xml add sau, 3 cái trên là cơ bản.

Coding#

  • User.java

    • @Table(name = “users”): một bảng trong DB với tên users

    • Điều kiện để trở thành một Entity là xài 2 annotation: @Entity, @Table

    • Sử dụng những annotation của Lombok để giảm Boilerplate Code

package com.lcaohoanq.demo.domain.user;
import jakarta.persistence.*;
import lombok.*;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //GenerationType.AUTO, GenerationType.SEQUENCE
@Column(name = "id", nullable = false, updatable = false) //if not provide name="id", JPA will automatically using the field name is userId
private Long userId;
private String username;
private String password;
}
  • UserDTO.java

    • DTO (Data Transfer Object): record java 16+, giống với data class của kotlin, mình có một bài viết về record tại đây Java Record,
package com.lcaohoanq.demo.domain.user;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
public record UserDTO(
@JsonProperty("username")
@NotEmpty(message = "Username is required")
@Size(min = 6, max = 20)
String username,
@JsonProperty("password")
@NotEmpty(message = "Password is required")
@Size(min = 6, max = 20)
String password
) {}
  • UserRepository.java

    • Sử dụng Repository Pattern DAO vs Repository thay vì dùng DAO (Data Access Object)

    • Có thể dùng @Repository hoặc không vì JpaRepository đã dùng @Repository

    • JpaRepository nhận 2 type là Entity và Data Type của PK của Entity đó (ở đây PK của User là Long userId) nên sẽ dùng Long

package com.lcaohoanq.demo.domain.user;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
public interface UserRepository extends JpaRepository<User, Long> {}
  • UserService.java

    • Bussiness Logic

    • @Transactional: hỗ trợ việc quản lý transaction, sử dụng ở class level hoặc method level, ở đây dùng method level

package com.lcaohoanq.demo.domain.user;
import com.lcaohoanq.demo.ResourceNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
@Override
@Transactional
public User create(UserDTO userDTO) {
User user = User.builder()
.username(userDTO.username()) //record do not have prefix get like getUsername, be aware at this point
.password(userDTO.password())
.build();
return userRepository.save(user);
}
@Override
@Transactional
public User update(Long id, UserDTO userDTO) {
User existingUser = findById(id);
existingUser.setUsername(userDTO.username());
existingUser.setPassword(userDTO.password());
return userRepository.save(existingUser);
}
@Override
@Transactional
public void delete(Long id) {
User user = findById(id);
userRepository.delete(user);
}
@Override
public User findById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found with id: " + id));
}
}
  • UserController.java:

    • @RestController: định nghĩa một REST API Endpoint

    • @RequestMapping: áp dụng prefix cho tất cả endpoint trong class

    • @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping,… cho những HTTP request tương ứng

    • Không khuyến khích sử dụng @Autowired -> Field Injection (tham khảo ở đây, Why using Autowired is not recommend, nên dùng @RequiredArgsContructor + private final -> Constructor Base Injection)

    • @Valid sẽ kích hoạt validation trong DTO, chỉ hoạt động với @RequestBody là một Object

package com.lcaohoanq.demo.domain.user;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.*;
@RestController
@RequestMapping("${API_PREFIX}/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
private final UserRepository userRepository;
@GetMapping("")
public ResponseEntity<?> findAll(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size)
{
return ResponseEntity.ok(userRepository.findAll(PageRequest.of(page, size)));
}
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return ResponseEntity.ok(user);
}
@PostMapping("/register")
public ResponseEntity<User> create(
@Valid @RequestBody UserDTO userDTO
) {
User createdUser = userService.create(userDTO);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
@PutMapping("/{id}")
public ResponseEntity<User> update(
@PathVariable Long id,
@Valid @RequestBody UserDTO userDTO
) {
User updatedUser = userService.update(id, userDTO);
return ResponseEntity.ok(updatedUser);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}

Swagger UI#

  • Add thêm dependency vào pom.xml
<dependencies>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.6.0</version>
</dependency>
<dependencies>

Config#

  • application.properties
spring.application.name=demo-crud-springboot-application
spring.output.ansi.enabled=ALWAYS
server.port=8080
# API
API_PREFIX=/api/v1
# H2 database configuration
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# JPA / Hibernate configuration
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
# Swagger config
springdoc.swagger-ui.operations-sorter=method
springdoc.swagger-ui.tags-sorter=alpha
springdoc.api-docs.path=/v3/api-docs
springdoc.swagger-ui.path=/swagger-ui.html

Test#

image

image

image

User CRUD đơn giản với Java Spring Boot 3
https://blog.lcaohoanq.works/posts/java-springboot-simple-crud/
Author
Thợ Dev
Published at
2025-01-22
License
CC BY-NC-SA 4.0