Bạn đang bắt đầu hành trình tìm hiểu về lập trình web với Java? Hay bạn đã từng nghe đến Spring Framework và tò mò không biết Spring MVC là gì, hoạt động ra sao và tại sao lại được dùng rộng rãi đến vậy? Nếu câu trả lời là “có”, thì bạn đang ở đúng nơi.
Trong bài viết này, mình sẽ cùng bạn khám phá Spring MVC – một phần không thể thiếu trong hệ sinh thái Spring để xây dựng các ứng dụng web hiện đại, linh hoạt và dễ bảo trì. Không cần bạn phải là chuyên gia Java hay đã từng làm việc với Spring, bài viết này sẽ hướng dẫn bạn từng bước một, từ những khái niệm cơ bản cho đến khi bạn có thể tự tay xây dựng một ứng dụng web hoàn chỉnh.
Vậy Spring MVC là gì?
Trước khi bắt tay vào code, hãy dành vài phút để hiểu bức tranh tổng thể. Spring MVC (Model-View-Controller) là một module trong Spring Framework, giúp bạn dễ dàng xây dựng các ứng dụng web theo mô hình phân tầng rõ ràng. Nói một cách đơn giản: bạn tách riêng phần xử lý logic (Model), phần giao diện (View), và phần điều phối (Controller). Điều này giúp mã của bạn dễ hiểu, dễ bảo trì và mở rộng trong tương lai.
Hướng dẫn xây Dựng Web App Java Đầu Tiên Của Bạn với Spring MVC
Trong hướng dẫn lần này, chúng ta sẽ cùng nhau tạo một ứng dụng web đơn giản sử dụng Spring MVC framework. Đừng lo nếu bạn chưa từng làm việc với Spring MVC trước đó – bài viết này sẽ dẫn dắt bạn từ A đến Z. Bạn hoàn toàn có thể sử dụng Eclipse hoặc IntelliJ IDEA để phát triển các dự án Spring, nhưng cá nhân mình rất khuyến khích dùng Spring Tool Suite (STS) – một IDE được tùy biến từ Eclipse và tối ưu hóa dành riêng cho các ứng dụng Spring. STS đi kèm với VMware vFabric tc Server (dựa trên Apache Tomcat) – một máy chủ được tinh chỉnh để chạy tốt với ứng dụng Spring, giúp bạn tiết kiệm khá nhiều thời gian cấu hình ban đầu. Mình sẽ sử dụng STS vì những lý do cực kỳ “đáng giá” sau đây:
- Hỗ trợ tạo sườn (skeletal) ứng dụng Spring nhanh chóngDù bạn đang định làm một dự án Spring MVC, REST API, hay Spring Batch, STS đều giúp bạn khởi tạo cấu trúc dự án chỉ trong vài cú nhấp chuột – rất tiện khi bắt đầu từ con số 0.
- Tạo và xử lý file cấu hình dễ dàngSTS cung cấp công cụ để tự động tạo các file cấu hình Spring như
applicationContext.xml
, đồng thời có khả năng phân tích các file cấu hình và class để hiển thị thông tin hữu ích. Bạn không cần phải nhớ hết mọi thứ – STS nhắc giùm bạn! - Tự động kiểm tra và xác thực ứng dụng SpringMột điểm mình rất thích: STS sẽ tự kiểm tra các file cấu hình và annotation trong ứng dụng của bạn, giúp phát hiện lỗi sớm – trước khi bạn mất cả buổi debugging!
- Hỗ trợ tái cấu trúc (refactor) toàn diệnKhi bạn đổi tên một class, method, STS sẽ cập nhật cả trong các file cấu hình liên quan. Việc thay đổi trong dự án trở nên trơn tru và không còn gây rối như trước.
- Gợi ý mã thông minh cho cả class và cấu hìnhKhông chỉ gợi ý khi bạn viết code Java, STS còn gợi ý khi bạn viết file cấu hình XML. Với những người hay quên như mình, việc được nhắc nhở đúng chỗ, đúng lúc là một điểm cộng rất lớn.
- Tích hợp AspectJ – hỗ trợ lập trình hướng khía cạnh (AOP)STS hỗ trợ rất tốt nhờ tích hợp sẵn với AspectJ, giúp bạn triển khai dễ dàng hơn bao giờ hết.
Với tất cả những tính năng tiện lợi mà Spring Tool Suite (STS) mang lại, mình đã hoàn toàn bị thuyết phục và quyết định gắn bó với nó cho toàn bộ các dự án Spring của mình. Cho đến thời điểm hiện tại, trải nghiệm với STS vẫn rất mượt mà – tiết kiệm được kha khá thời gian setup và debug.Để bắt đầu, bạn chỉ cần tải STS từ trang chính thức của Spring Tool Suite: STS Official Download Page
Sau khi tải về, chỉ cần cài đặt như một phần mềm thông thường – không có gì phức tạp cả. Trong bài viết này, mình sẽ sử dụng phiên bản STS 3.4.0.RELEASE, vốn được xây dựng dựa trên nền tảng Eclipse 4.3.1. Nếu bạn đang dùng phiên bản mới hơn cũng không sao – các bước cài đặt và thao tác cơ bản nhìn chung vẫn giống nhau.
Nếu bạn không muốn sử dụng Spring Tool Suite (STS) độc lập mà muốn tích hợp các tính năng của nó vào Eclipse hiện có, thì hoàn toàn có thể làm được bằng cách cài đặt plugin STS từ Eclipse Marketplace. Việc này khá đơn giản – bạn chỉ cần mở Eclipse, truy cập vào Help → Eclipse Marketplace, sau đó tìm với từ khóa “Spring Tools”. Dưới đây là hình ảnh tham khảo để bạn dễ hình dung quá trình cài đặt:
Bây giờ môi trường máy chủ và IDE của chúng ta đã sẵn sàng, hãy tiến hành tạo dự án Spring MVC đầu tiên của chúng ta. Các bước dưới đây áp dụng cho cả STS và Eclipse có plugin STS.
Tạo ứng dụng Spring MVC trong STS hoặc Eclipse
Bước 1 : Tạo Spring Project từ menu
Bước 2
Khi cửa sổ tạo project mới hiện ra, bạn hãy:
- Đặt tên dự án là
SpringMVCExample
- Chọn template là:
Spring MVC Project
Nếu đây là lần đầu tiên bạn sử dụng template này, STS sẽ tự động tải về từ trang web của SpringSource, nên hãy đảm bảo máy bạn đang kết nối internet nhé.
Ngoài ra, nếu bạn đang sử dụng Working Set để quản lý các dự án (ví dụ nhóm các project theo module hoặc theo mục đích), bạn cũng có thể thêm project mới này vào working set tương ứng – tuy nhiên đây là bước tùy chọn, có thể bỏ qua nếu chưa dùng đến.
Bước 3: Cấu hình package gốc cho ứng dụng
Sau khi template được tải xong, STS sẽ chuyển bạn đến màn hình cấu hình tiếp theo. Tại đây, bạn cần điền tên package cấp cao nhất (top-level package name) cho project của mình.
Đây chính là package gốc mà Spring sẽ sử dụng để quét và tìm kiếm các component như @Controller
, @Service
, @Repository
, v.v. Vì thế, bạn nên đặt tên theo chuẩn Java, ví dụ:
com.example.springmvc
Đặt tên rõ ràng, có tổ chức sẽ giúp dự án dễ bảo trì hơn, đặc biệt khi ứng dụng mở rộng sau này.
Sắp đến phần thú vị rồi đó – cấu trúc project Spring MVC đầu tiên của bạn sẽ được khởi tạo ngay sau bước này!
Bước 4: Review cấu trúc project sau khi được tạo
Sau khi bạn hoàn tất các bước và Spring MVC template tạo xong project, cấu trúc dự án sẽ hiển thị như hình dưới đây:
Nếu bạn không thấy các file như User.java
, login.jsp
hay user.jsp
trong project thì cũng đừng lo lắng nhé – đây là những file mình thêm vào sau để phục vụ cho phần demo trong bài viết. Ban đầu, project sẽ chưa có sẵn những file này.
Ngoài ra, nếu sau khi tạo project mà bạn thấy project chưa được biên dịch hoặc xuất hiện một vài lỗi, thì rất có thể do Maven chưa được cập nhật dependencies.
Cách xử lý:
- Click phải vào project trong STS → chọn Maven → Update Project
- Trong hộp thoại hiện ra, nhớ tick vào ô “Force update of Snapshots/Releases”
- Sau đó nhấn OK để Maven tải lại các dependency cần thiết
Nhìn chung, cấu trúc project lúc này khá giống với bất kỳ ứng dụng web nào sử dụng Maven, chỉ khác là có thêm một vài file cấu hình đặc trưng của Spring.
Mọi thứ đã sẵn sàng – bây giờ chính là lúc cùng nhau phân tích từng phần trong dự án để hiểu rõ vai trò của chúng, và bắt đầu mở rộng ứng dụng một chút để thấy Spring MVC hoạt động như thế nào trong thực tế.
Để ứng dụng Spring MVC hoạt động đúng cách, chúng ta cần khai báo một số thư viện phụ thuộc (dependencies) cần thiết trong file pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="<https://maven.apache.org/POM/4.0.0>" xmlns:xsi="<https://www.w3.org/2001/XMLSchema-instance>"
xsi:schemaLocation="<https://maven.apache.org/POM/4.0.0> <https://maven.apache.org/maven-v4_0_0.xsd>">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>SpringMVCExample</artifactId>
<name>SpringMVCExample</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>1.6</java-version>
<org.springframework-version>4.0.0.RELEASE</org.springframework-version>
<org.aspectj-version>1.7.4</org.aspectj-version>
<org.slf4j-version>1.7.5</org.slf4j-version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Trong phần cấu hình pom.xml
, artifactId
sẽ là tên đường dẫn gốc của ứng dụng web (servlet-context) của ứng dụng web. Bạn hoàn toàn có thể thay đổi giá trị này nếu muốn sử dụng một tên khác phù hợp với dự án của mình.
Bên cạnh đó, trong phần properties
, bạn sẽ thấy một số phiên bản được định nghĩa sẵn cho Spring Framework, AspectJ, và SLF4j. Tuy nhiên, mình nhận thấy các phiên bản mặc định này không phải là phiên bản mới nhất, nên đã chủ động cập nhật lên các bản stable mới nhất tại thời điểm viết bài để đảm bảo tính tương thích và bảo mật.
Dưới đây là những dependency chính mà mình quan tâm và sử dụng cho dự án này:
spring-context
– Thư viện cốt lõi của Spring (hay còn gọi là Spring Core Dependency), chịu trách nhiệm chính cho các tính năng như Dependency Injection (tiêm phụ thuộc) và quản lý vòng đời của Bean.Lưu ý: Trong phần cấu hình này, Spring loại trừ thư việncommons-logging
và ưu tiên sử dụng SLF4J – một thư viện logging trung gian hiện đại và linh hoạt hơn.spring-webmvc
– Là thành phần chính (artifact) hỗ trợ mô hình Spring MVC trong ứng dụng web. Thư viện này bao gồm các annotation quen thuộc như@Controller
,@RequestMapping
, đồng thời cấu hình DispatcherServlet và ViewResolver.aspectjrt
– Là thư viện runtime của AspectJ, cung cấp API tham chiếu (AspectJ API reference) cho việc triển khai lập trình hướng khía cạnh (AOP – Aspect-Oriented Programming). Điều này rất hữu ích để tách biệt các chức năng như logging, bảo mật, hay transaction ra khỏi logic nghiệp vụ chính.SLF4J
vàLog4j
– Hai thư viện được sử dụng cho mục đích ghi log (logging purposes). Nhờ Spring hỗ trợ tốt SLF4J, bạn có thể dễ dàng cấu hình logging với Log4j hoặc Java Logging API theo nhu cầu của mình. Việc này giúp hệ thống logging trở nên linh hoạt, dễ quản lý và đồng bộ hơn.javax.inject
– Đây là thư viện triển khai theo JSR-330 API – một chuẩn chính thức của Java cho Dependency Injection. Việc Spring hỗ trợ thư viện này giúp tăng tính tương thích giữa Spring và các framework Java EE khác.
Ngoài các thư viện chính mình đã đề cập ở trên, còn có một vài thư viện phụ trợ khác như Servlet API, JSP, JSTL và JUnit cũng được thêm vào trong phần cấu hình Maven. Tuy nhiên, vì đây chỉ là một ứng dụng Spring MVC đơn giản để bắt đầu, nên chúng ta có thể tạm thời bỏ qua các thư viện này và tập trung vào phần cốt lõi trước.
Sau khi đã thiết lập xong các dependency cần thiết cho Spring MVC, bước tiếp theo mình muốn giới thiệu là cách cấu hình hệ thống ghi log (logging) cho ứng dụng – một phần không thể thiếu trong bất kỳ dự án thực tế nào. Spring hỗ trợ nhiều framework ghi log khác nhau, nhưng trong hướng dẫn này, mình sẽ sử dụng Log4j thông qua SLF4J – combo phổ biến và mạnh mẽ giúp bạn kiểm soát log tốt hơn, dễ dàng phân loại và phân tích log trong quá trình phát triển và vận hành hệ thống.
Việc tích hợp Log4j với Spring khá đơn giản, và chúng ta chỉ cần vài bước cấu hình cơ bản là có thể bắt đầu sử dụng. Tệp log4j.xml được tạo trông như bên dưới.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="<https://jakarta.apache.org/log4j/>">
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p: %c - %m%n" />
</layout>
</appender>
<!-- Application Loggers -->
<logger name="com.journaldev.spring">
<level value="info" />
</logger>
<!-- 3rdparty Loggers -->
<logger name="org.springframework.core">
<level value="info" />
</logger>
<logger name="org.springframework.beans">
<level value="info" />
</logger>
<logger name="org.springframework.context">
<level value="info" />
</logger>
<logger name="org.springframework.web">
<level value="info" />
</logger>
<!-- Root Logger -->
<root>
<priority value="warn" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
Bạn có thể thấy rằng toàn bộ log hiện tại đang được in ra console. Tuy nhiên, Spring + Log4j cho phép chúng ta dễ dàng thêm các appender để chuyển hướng log sang file – rất hữu ích khi triển khai ứng dụng thực tế hoặc cần lưu trữ log để phân tích sau này.
Sau khi đã cấu hình xong hệ thống logging, bước tiếp theo chúng ta cần làm là thiết lập Deployment Descriptor, hay còn gọi là file web.xml
. Đây là một thành phần cốt lõi trong ứng dụng web sử dụng Servlet, giúp định nghĩa cách ứng dụng sẽ khởi tạo và xử lý request từ người dùng.
Trong Spring MVC, web.xml
thường được dùng để:
- Khai báo DispatcherServlet – trung tâm xử lý mọi request trong Spring MVC
- Định nghĩa các mapping URL
- Cấu hình encoding, context parameters, listener…
Việc cấu hình đúng web.xml
là bước quan trọng để đảm bảo ứng dụng Spring MVC hoạt động trơn tru ngay từ lúc khởi động.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="<https://java.sun.com/xml/ns/javaee>"
xmlns:xsi="<https://www.w3.org/2001/XMLSchema-instance>"
xsi:schemaLocation="<https://java.sun.com/xml/ns/javaee> <https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd>">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
ContextLoaderListener
giúp gắn vòng đời của ApplicationContext
với ServletContext
, đồng thời tự động khởi tạo ApplicationContext
khi ứng dụng được deploy. Đây chính là nơi lưu trữ các Spring Bean, và chúng ta có thể cấu hình nó thông qua tham số contextConfigLocation
trong web.xml
.
Thông thường, file root-context.xml
sẽ chứa các cấu hình liên quan đến WebApplicationContext – đây là phần nền tảng cho toàn bộ ứng dụng web Spring.
Tiếp theo là DispatcherServlet
– thành phần đóng vai trò như controller trung tâm trong ứng dụng Spring MVC. Mọi request từ phía client đều được chuyển về servlet này để xử lý. Cấu hình của DispatcherServlet
sẽ được load từ file servlet-context.xml
.
. Tiếp theo, chúng ta sẽ đi sâu hơn vào các file cấu hình chính của Spring MVC, bao gồm:
root-context.xml
– thường dùng để cấu hình các bean liên quan đến tầng service, repository hoặc các thành phần dùng chung trong toàn bộ ứng dụng.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="<https://www.springframework.org/schema/beans>"
xmlns:xsi="<https://www.w3.org/2001/XMLSchema-instance>"
xsi:schemaLocation="<https://www.springframework.org/schema/beans> <https://www.springframework.org/schema/beans/spring-beans.xsd>">
<!-- Root Context: defines shared resources visible to all other web components -->
</beans>
servlet-context.xml
– nơi cấu hình các thành phần liên quan đến Web MVC như: Controller, ViewResolver, ResourceHandler, và các annotation hỗ trợ như@ComponentScan
.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="<https://www.springframework.org/schema/mvc>"
xmlns:xsi="<https://www.w3.org/2001/XMLSchema-instance>"
xmlns:beans="<https://www.springframework.org/schema/beans>"
xmlns:context="<https://www.springframework.org/schema/context>"
xsi:schemaLocation="<https://www.springframework.org/schema/mvc> <https://www.springframework.org/schema/mvc/spring-mvc.xsd>
<https://www.springframework.org/schema/beans> <https://www.springframework.org/schema/beans/spring-beans.xsd>
<https://www.springframework.org/schema/context> <https://www.springframework.org/schema/context/spring-context.xsd>">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.journaldev.spring" />
</beans:beans>
Đây là cách mà một file cấu hình chuẩn trong Spring MVC thường trông như thế. Nếu bạn tưởng tượng phải ngồi tự viết toàn bộ từ đầu, mình tin là bạn sẽ nhanh chóng “phải lòng” công cụ STS vì nó giúp tạo sẵn tất cả những phần này, tiết kiệm rất nhiều thời gian.
- Dòng cấu hình
<annotation-driven>
cho Spring biết rằng chúng ta sẽ sử dụng các annotation như@Controller
,@RequestMapping
để định nghĩa các bean và xử lý request, thay vì cấu hình XML thủ công. - Thẻ
<resources>
dùng để chỉ định vị trí chứa các tài nguyên tĩnh như ảnh, CSS, JS hoặc các file HTML – những thứ mà bạn không muốn Spring xử lý thông qua DispatcherServlet. - Bean
InternalResourceViewResolver
là thành phần dùng để map tên view (JSP) trả về từ controller thành đường dẫn thật trên hệ thống. Chúng ta chỉ cần cấu hìnhprefix
vàsuffix
, ví dụ:Vớiprefix = "/WEB-INF/views/"
vàsuffix = ".jsp"
, khi controller trả về view"home"
, Spring sẽ hiểu và chuyển thành/WEB-INF/views/home.jsp
. - Cuối cùng, phần
<context:component-scan>
dùng để khai báo package gốc mà Spring sẽ quét để tìm các bean như@Controller
,@Service
, v.v… Đây chính là package mà bạn đã đặt tên khi tạo project lúc đầu – giờ nó được sử dụng lại để định hướng Spring quét tự động.
Hiểu rõ vai trò và cách sử dụng từng file cấu hình sẽ giúp bạn quản lý dự án một cách rõ ràng, linh hoạt và dễ mở rộng hơn khi ứng dụng ngày càng phức tạp. Sau khi đã cấu hình xong các file cơ bản, đặc biệt là servlet-context.xml
, giờ là lúc chúng ta bắt tay vào viết controller đầu tiên cho ứng dụng Spring MVC của mình. Tạo lớp điều khiển trong Spring MVC
Trong Spring MVC, controller là nơi tiếp nhận và xử lý các yêu cầu (request) từ người dùng, sau đó trả về dữ liệu hoặc chuyển hướng sang trang hiển thị tương ứng (view). Chúng ta chỉ cần sử dụng một vài annotation như @Controller
và @RequestMapping
là có thể dễ dàng xây dựng các luồng xử lý như ý.
Spring đã tự động tạo cho chúng ta một class có tên là HomeController
với sẵn một phương thức home()
. Tuy nhiên, để mở rộng chức năng cho ứng dụng, mình đã thêm vào hai phương thức nữa là loginPage()
để hiển thị trang đăng nhập và login()
để xử lý khi người dùng submit thông tin.
package com.journaldev.spring;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage(Locale locale, Model model) {
return "login";
}
@RequestMapping(value = "/home", method = RequestMethod.POST)
public String login(@Validated User user, Model model) {
model.addAttribute("userName", user.getUserName());
return "user";
}
}
Trong đoạn code trên, @Controller
được dùng để đánh dấu đây là một lớp controller web, chịu trách nhiệm xử lý các request trong ứng dụng Spring MVC.
@RequestMapping
được sử dụng ở cấp lớp và phương thức để định tuyến các yêu cầu từ client đến đúng handler method tương ứng.
Điểm đáng chú ý là các phương thức xử lý (handler methods) đều trả về kiểu String
, đại diện cho tên của view sẽ được render (thường là tên file JSP). Ví dụ:
home()
→ trả về"home"
→ cần có filehome.jsp
loginPage()
→ trả về"login"
→ cần có filelogin.jsp
login()
→ trả về"user"
→ cần có fileuser.jsp
Như bạn thấy, mỗi phương thức trả về một view khác nhau, vậy nên chúng ta cần tạo các trang JSP tương ứng để hiển thị dữ liệu hoặc giao diện.
Trong phương thức login()
, bạn sẽ thấy nó được map với phương thức HTTP POST
. Điều này có nghĩa là nó sẽ xử lý dữ liệu được gửi từ form đăng nhập. Dữ liệu từ form này sẽ được tự động gắn vào một đối tượng User
, và mình đã đánh dấu đối tượng này với annotation @Validated
để kích hoạt kiểm tra tính hợp lệ (validation).
Cuối cùng, tham số Model
được truyền vào mỗi phương thức cho phép chúng ta gửi dữ liệu từ controller sang view bằng cách thêm các thuộc tính thông qua model.addAttribute()
– giúp JSP dễ dàng hiển thị các thông tin như serverTime
hay userName
.
Sau khi đã thiết lập controller và cấu hình view thành công, bước tiếp theo chúng ta cần làm là xây dựng lớp Model – chính là nơi đại diện cho dữ liệu mà ứng dụng của bạn sẽ xử lý.
Tạo lớp mô hình trong Spring MVC
Trong Spring MVC, Model thường là một POJO (Plain Old Java Object) – đơn giản, không chứa logic phức tạp, nhưng có thể được trang bị thêm các annotation để hỗ trợ việc gắn dữ liệu từ form và xác thực (validation). Trong ví dụ này, chúng ta sẽ tạo một lớp model có tên là User
, dùng để chứa thông tin đăng nhập mà người dùng nhập vào từ form.
package com.journaldev.spring;
public class User {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
Một lớp đơn giản với tên biến và các phương thức getter và setter.
Sau khi đã xây dựng xong controller và model, bước cuối cùng trong quy trình xử lý request là tạo ra các view page để hiển thị dữ liệu ra giao diện người dùng.
Tạo View Pages trong Spring MVC
Trong Spring MVC, view thường là các file JSP được đặt trong thư mục /WEB-INF/views/
, như chúng ta đã cấu hình trong InternalResourceViewResolver
. Các phương thức trong controller trả về dữ liệu hiển thị dưới dạng String
, và Spring sẽ ánh xạ đến các file .jsp
tương ứng.
- Trả về
"home"
→ ánh xạ đến/WEB-INF/views/home.jsp
<%@ taglib uri="<https://java.sun.com/jsp/jstl/core>" prefix="c" %> <%@ page session="false" %> <html> <head> <title>Home</title> </head> <body> <h1> Hello world! </h1> <P> The time on the server is ${serverTime}. </P> </body> </html>
- Trả về
"login"
→ ánh xạ đến/WEB-INF/views/login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "<https://www.w3.org/TR/html4/loose.dtd>"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Login Page</title> </head> <body> <form action="home" method="post"> <input type="text" name="userName"><br> <input type="submit" value="Login"> </form> </body> </html>
- Trả về
"user"
→ ánh xạ đến/WEB-INF/views/user.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "<https://www.w3.org/TR/html4/loose.dtd>"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>User Home Page</title> </head> <body> <h3>Hi ${userName}</h3> </body> </html>
Sau khi đã hoàn tất việc cấu hình controller, model và view, ứng dụng của chúng ta đã sẵn sàng để được kiểm thử thực tế.
Kiểm tra ứng dụng
Ứng dụng của chúng ta đến đây là đã sẵn sàng để chạy. Bạn chỉ cần deploy ứng dụng lên VMware vFabric tc Server (hoặc bất kỳ servlet container nào bạn đang sử dụng như Tomcat), và bạn sẽ thấy các trang giao diện như bên dưới được hiển thị khi truy cập.
Vậy là chúng ta đã hoàn thành việc tạo ra một web cơ bản. Bạn có thể thấy rằng việc tạo một ứng dụng Spring MVC với sự hỗ trợ của STS plugin thực sự rất đơn giản và nhanh chóng.
Qua bài viết này, bạn đã có cái nhìn tổng quan và thực tiễn về cách xây dựng một ứng dụng web cơ bản với Spring MVC thông qua Spring Tool Suite (STS). Từ khâu tạo project, cấu hình controller, model, view cho đến kiểm thử ứng dụng – tất cả đều được đơn giản hóa nhờ sự hỗ trợ mạnh mẽ từ Spring framework và các công cụ đi kèm.
Điều tuyệt vời là bạn không cần phải viết quá nhiều cấu hình phức tạp – Spring MVC đã giúp chúng ta “dọn đường”, để bạn có thể tập trung phát triển nghiệp vụ và trải nghiệm lập trình sạch sẽ, rõ ràng hơn.
Nếu bạn đang bắt đầu hành trình học Spring Framework, thì Spring MVC là một bước khởi đầu lý tưởng – vừa đơn giản, vừa thực tế. Hãy tải về source code mẫu, thử thay đổi, thêm mới tính năng và từng bước khám phá sức mạnh của hệ sinh thái Spring.