Để xây dựng ứng dụng web Java hiện đại, cần chuẩn bị các thành phần sau: MySQL 8.0, IntelliJ IDEA 2022.x, Git 2.23+, Node.js phiên bản 16 trở lên (các phiên bản mới hơn có thể gây xung đột với một số thư viện cũ), và JDK 17 — mặc dù JDK 8 vẫn khả thi cho các dự án kế thừa.
Thiết lập dự án ban đầu
Khi tạo dự án mới trong IDE, cần xác định rõ cấu trúc thư mục ngay từ đầu để tránh sai lệch về đường dẫn và cấu hình sau này.
Cấu hình Maven toàn cục
Tệp settings.xml nên được điều chỉnh để tăng tốc độ tải dependency và đảm bảo tính ổn định:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>C:/Users/Developer/.m2/repository</localRepository>
<mirrors>
<mirror>
<id>aliyun-maven</id>
<mirrorOf>central</mirrorOf>
<name>Aliyun Central Mirror</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
</settings>Quản lý kho lưu trữ Git
Khi khởi tạo lại dự án hoặc chuyển sang kho mới, cần kiểm tra và cập nhật remote repository:
- Xem danh sách remote hiện tại:
git remote -v - Cập nhật URL của remote
origin:git remote set-url origin https://gitee.com/username/project.git - Thêm remote mới với tên khác (ví dụ
gitee):git remote add gitee https://gitee.com/username/project.git
Nếu sử dụng SSH key, hãy đảm bảo khóa đã được đăng ký tại nền tảng (Gitee/GitHub) thông qua tùy chọn SSH Keys trong cài đặt tài khoản.
Tối ưu hóa nhật ký khởi động
Trong lớp chính của ứng dụng Spring Boot, bổ sung thông tin hữu ích khi server chạy thành công:
@SpringBootApplication
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
Environment env = context.getEnvironment();
String port = env.getProperty("server.port", "8080");
logger.info("Ứng dụng đã khởi động thành công!");
logger.info("Truy cập tại: http://localhost:{}", port);
}
}Kiểm thử API bằng tệp HTTP tích hợp
IDEA hỗ trợ chạy yêu cầu HTTP trực tiếp từ tệp có phần mở rộng .http. Tạo thư mục http ở gốc dự án, sau đó thêm tệp test.http:
### Gửi yêu cầu POST
POST http://localhost:8080/api/greeting
Content-Type: application/x-www-form-urlencoded
name=NguyenVanA
### Xử lý trong controller
@PostMapping("/api/greeting")
public String greet(@RequestParam String name) {
return "Xin chào, " + name + "! (Phương thức POST)";
}Lưu ý: Khoảng trắng giữa header và body là bắt buộc đối với yêu cầu POST.
Quản lý cấu hình ứng dụng
Spring Boot tự động đọc các tệp cấu hình trong thư mục src/main/resources, bao gồm:
application.propertieshoặcapplication.yml— dùng cho cấu hình runtime.bootstrap.propertieshoặcbootstrap.yml— dành riêng cho Spring Cloud, dùng để tải cấu hình trước khi context khởi tạo.
Chuyển đổi giữa hai định dạng có thể thực hiện tại toyaml.com.
Tích hợp MyBatis với Spring Boot
Bước 1: Khai báo dependency trong pom.xml:
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency>
Bước 2: Cấu hình kết nối cơ sở dữ liệu trong application.yml:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/demo_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Ho_Chi_Minh
username: root
password: secret123
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/**/*.xml
configuration:
map-underscore-to-camel-case: trueBước 3: Kích hoạt quét mapper interface trong lớp chính:
@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application { /* ... */ }Bước 4: Định nghĩa service với dependency injection đúng chuẩn:
@Service
public class UserService {
@Autowired // hoặc @Resource — cả hai đều hợp lệ
private UserMapper userMapper;
public List<UserDto> fetchAllUsers() {
return userMapper.findAll();
}
}Bước 5: Interface mapper và file XML tương ứng:
public interface UserMapper {
List<UserDto> findAll();
}<?xml version="1.0" encoding="UTF-8"?>
<mapper namespace="com.example.mapper.UserMapper">
<select id="findAll" resultType="com.example.dto.UserDto">
SELECT id, full_name AS fullName, email FROM users
</select>
</mapper>Định dạng phản hồi thống nhất
Tạo lớp wrapper chung để chuẩn hóa cấu trúc JSON trả về:
public class ApiResponse<T> {
private boolean success = true;
private String message = "Thành công";
private T data;
// constructor, getter, setter
}Sử dụng trong controller:
@GetMapping("/users")
public ApiResponse<List<UserDto>> getUsers() {
List<UserDto> users = userService.fetchAllUsers();
return new ApiResponse<>().setData(users);
}Chuyển đổi dữ liệu giữa các lớp
Thay vì ánh xạ thủ công từng trường, sử dụng tiện ích sao chép linh hoạt:
public class BeanCopier {
public static <T> T copy(Object source, Class<T> targetClass) {
if (source == null) return null;
try {
T instance = targetClass.getDeclaredConstructor().newInstance();
BeanUtils.copyProperties(source, instance);
return instance;
} catch (Exception e) {
throw new RuntimeException("Không thể sao chép đối tượng", e);
}
}
public static <T> List<T> copyList(List<?> sources, Class<T> targetClass) {
return sources.stream()
.map(s -> copy(s, targetClass))
.collect(Collectors.toList());
}
}Ví dụ áp dụng:
List<User> dbResults = userMapper.findAll(); List<UserDto> dtos = BeanCopier.copyList(dbResults, UserDto.class);
Bộ lọc và trình chặn yêu cầu
Để ghi log toàn cục, tạo filter với chú giải @Component:
@Component
public class RequestLoggingFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(RequestLoggingFilter.class);
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
long start = System.currentTimeMillis();
chain.doFilter(req, res);
log.info("Yêu cầu {} {} hoàn tất trong {}ms",
request.getMethod(), request.getRequestURI(),
System.currentTimeMillis() - start);
}
}Với interceptor (được kích hoạt trên tầng MVC), khai báo trong cấu hình:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired private LoggingInterceptor loggingInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loggingInterceptor)
.excludePathPatterns("/health", "/actuator/**");
}
}Hướng dẫn bật log SQL
Thêm vào application.yml để theo dõi câu truy vấn thực thi:
logging:
level:
com.example.mapper: debug
org.springframework.jdbc: debug