Bộ sưu tập

Giới thiệu về Spring MVC


https://codersontrang.com/2013/03/25/gioi-thieu-ve-spring-mvc/

Bài viết này xin được phép trình bày về việc ứng dụng mô hình thiết kế MVC vào việc xây dựng các ứng dụng web của Spring. Để triển khai mô hình trên, Spring có xây dựng một cơ chế có tên Spring MVC mà ở đó có các API cho phép việc xây dựng ứng dụng web được dễ dàng hơn và có quy tắc hơn. Quy tắc hơn thể hiện ở chỗ mọi thành phần được tạo ra, cài đặt và vận hành tuân theo một chuẩn thiết kế thống nhất.

Đầu tiên, có lẽ ta nói qua một chút về khái niệm MVC. MVC lần lượt là ba chữ cái đầu tiên của ba từ Model, ViewController. MVC là một mô hình ứng dụng mà ở đó các thành phần được phân tách ra thành các lớp riêng biệt với các nhiệm vụ đặc trưng. View sẽ là lớp cho các thành phần có chức năng hiển thị, giao tiếp trực tiếp với người dùng. Nhiệm vụ của các thành phần trong View là trình bày các dữ liệu từ Model đến người dùng cuối. Model là các thành phần có khả năng lưu trữ và vận chuyển thông tin. Quá trình ném dữ liệu vào Model sẽ được thực hiện bởi Controller. Controller là các thành phần giúp cho việc xử lý logic các thao tác nghiệp vụ. Nhiệm vụ của Controller là lấy dữ liệu từ Model, xử lý dữ liệu, và cập nhật lại dữ liệu vào Model.

Ta cụ thể hóa ý tưởng trên vào trong trường hợp của Spring MVC. Ở đây View sẽ là các trang .jsp giúp cho việc hiển thị dữ liệu lên browser. Dữ liệu được lấy ra từ Model là các POJO (Plain Old Java Object) hay ta còn gọi là các Domain Object. Cụ thể hơn, nó là các đối tượng có các thuộc tính có khả năng mang vác dữ liệu trong các luồng nghiệp vụ của ứng dụng. Cuối cùng là Controller, là các lớp đặc biệt, có chứa các phương thức có khả năng nhận yêu cầu, xử lý yêu cầu, cập nhật dữ liệu, và chuyển tiếp dữ liệu trong ứng dụng.

Dưới đây ta sẽ có một ví dụ về Spring MVC. Tạo một Web Project trong Eclipse IDE có cấu trúc như hình dưới đây:

codersontrang_springmvcdemo_1

Ở ví dụ này, ta sử dụng thư viện Spring MVC 3.x, cũng như đã thấy, ta có trang index.jsp là phần View, phần Controller sẽ là các lớp được đặt trong package springmvcdemo.controller, ở đây ta có lớp DemoController.java. Cuối cùng là phần Model là các lớp được đặt trong package có tên springmvcdemo.model, trong ví dụ này ta có lớp Student.java. Ngoài ra ta còn có một số các file web.xml, springmvc-demo.xml là nơi chỉ ra các thông tin cấu hình cho ứng dụng web.

web.xml

 <?xml version="1.0" encoding="UTF-8"?>  
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xmlns="http://java.sun.com/xml/ns/j2ee" 
             xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
                                 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
                                 version="2.4">  

       <servlet>  
          <servlet-name>springmvcdemo</servlet-name>  
          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
          <load-on-startup>1</load-on-startup>  
       </servlet>  
       <servlet-mapping>  
          <servlet-name>springmvcdemo</servlet-name>  
          <url-pattern>/</url-pattern>  
       </servlet-mapping>  
 </web-app>  

Để sử dụng Spring MVC, ta phải cấu hình trong file web.xml để tạo một servlet từ lớp org.springframework.web.servlet.DispatcherServlet. Servlet này còn gọi là front servlet, là nơi đón tiếp tất cả các yêu cầu đến ứng dụng web, sau đó dựa vào thông tin cấu hình mà chuyển tiếp các yêu cầu này đến các controller tương ứng để xử lý chúng. Ở đây, servlet có tên springmvcdemo sẽ đón nhận tất cả các yêu cầu từ các đường dẫn có chứa “/“, cái này được định nghĩa trong thẻ <url-pattern>.

springmvcdemo-servlet.xml

 <?xml version="1.0" encoding="UTF-8"?>  
 <beans xmlns="http://www.springframework.org/schema/beans"  
      xmlns:context="http://www.springframework.org/schema/context"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd">  

      <context:component-scan base-package="springmvcdemo.controller" />  

 </beans>  

Toàn bộ thông tin cấu hình cần thiết cho một ứng dụng web sử dụng Spring MVC được khai báo trong file springmvcdemo-servlet.xml. Ở trong ví dụ này, ta để ý rằng tên của file cấu hình sẽ là tên của front servlet mà ta khai báo ở web.xml ghép với đuôi “-servlet“. Làm như thế sẽ là một cách chỉ thị để Spring tự động biết được đó là file có chứa các thông tin cấu hình và cần phải load lên trong quá trình khởi tạo lúc đầu. Trong ví dụ này, ta sử dụng thẻ <context:component-scan> để chỉ ra tên của package mà ở đó có chứa các controller của ứng dụng.

Student.java


 package springmvcdemo.model;  

 import java.util.List;  

 public class Student {  
      private String name;  
      private List<String> books; 
 
      public List<String> getBooks() {  
           return books;  
      }  
      public void setBooks(List<String> books) {  
           this.books = books;  
      }  
      public String getName() {  
           return name;  
      }  
      public void setName(String name) {  
           this.name = name;  
      }  
 }  

Như trên đã nói, Student ở đây chính là một model, model có chứa các thuộc tính và các getter, setter tương ứng. Student có khả năng mang vác các thông tin trong quá trình các thông tin được trao đổi từ View sang Controller.

DemoController.java


 package springmvcdemo.controller;  

 import java.util.ArrayList;  
 import java.util.List;  
 import javax.servlet.http.HttpServletRequest;  
 import javax.servlet.http.HttpServletResponse;  
 import org.springframework.stereotype.Controller;  
 import org.springframework.ui.ModelMap;  
 import org.springframework.web.bind.annotation.ModelAttribute;  
 import org.springframework.web.bind.annotation.RequestMapping;  
 import org.springframework.web.bind.annotation.RequestMethod;  
 import org.springframework.web.servlet.ModelAndView;  
 import springmvcdemo.model.Student;  

 @Controller  
 public class DemoController{  

      @RequestMapping(value="/home", method=RequestMethod.GET)  
      public ModelAndView handleRequest(HttpServletRequest request,  
                HttpServletResponse response) throws Exception {  

           Student student = new Student();  
           student.setName("Coder Tien Sinh");  

           List<String> books = new ArrayList<String>();  
           books.add("book1");  
           books.add("book2");  
           student.setBooks(books);  

           ModelAndView mav = new ModelAndView("index.jsp", "model", student);  
           return mav;  
      }  

      @RequestMapping(value="/submitStudentInfo", method = RequestMethod.POST)  
      public ModelAndView submitStudentInfo(ModelMap model, @ModelAttribute("model") Student student){  

           List<String> listBooks = student.getBooks();  
           boolean bookSameName = checkSameBookName(listBooks);  

           String message = "Update success !!!";  
           if(bookSameName){  
                message = "Books must have different name !!!";  
           }  
           model.addAttribute("message", message);  

           ModelAndView mav = new ModelAndView("index.jsp", "model", student);  
           return mav;  
      }  

      private boolean checkSameBookName(List<String> listBooks) {  
           for(int i =0; i<listBooks.size(); i++){  
                String firstBookName = listBooks.get(i);  
                for(int j = i+1; j<listBooks.size(); j++){  
                     String secondBookName = listBooks.get(j);  
                     if(firstBookName.equalsIgnoreCase(secondBookName)){  
                          return true;  
                     }  
                }  
           }  
           return false;  
      }  
 }  

Để nhận biết được một lớp có phải là một controller thì Spring MVC phải dựa vào hai điều kiện. Thứ nhất, là lớp đó phải nằm trong package được khai báo trong file cấu hình, package này là vị trí có chứa các controller. Thứ hai là bên trên khai báo của lớp có annotation @Controller.

Bên trong mỗi controller sẽ chứa các phương thức, các phương thức sẽ đảm nhiệm việc nhận yêu cầu từ các URL. Để biết phương thức nào sẽ nhận yêu cầu từ URL nào, ta đặt annotation @RequestMapping với tham số là url tương ứng bên trên phương thức mỗi phương thức.

Tham số trong mỗi phương thức trên có thể biến đổi tùy vào việc ta muốn lấy gì từ yêu cầu gửi lên server. Tham số có thể là một đối tượng của HttpRequest, HttpResponse, hoặc như trong ví dụ này chính là đối tượng của model Student. Trong đối tượng của lớp Student, sẽ lưu các thông tin được gửi lên từ View (*.jsp), phương thức trong controller sẽ tiếp nhận các thông tin này và xử lý chúng.

Mỗi một phương thức trong controller sẽ trả về một đối tượng của lớp ModelAndView. Lớp này là đại diện cho một view, là nơi mà sẽ được ứng dụng chuyển tiếp đến sau khi controller xử lý xong nghiệp vụ. Ở ví dụ của chúng ta, view của chúng ta chính là file index.jsp, ngoài ra chúng ta cũng chỉ ra model gắn với view index.jsp này trong ModelAndView, chính là đối tượng của lớp Student.

Trong ví dụ của chúng ta, ta có hai đường dẫn, “/home“, và “/submitStudentInfo“. Các yêu cầu được gửi từ “/home” sẽ được phương thức handleRequest() trong controller xử lý, và tương tự các yêu cầu được gửi từ “/submitStudentInfo” sẽ được phương thức submitStudentInfo() trong controller xử lý. Tuy nhiên không phải yêu cầu nào từ “/home” cũng sẽ được phương thức handleRequest() xử lý, ở đây chỉ nhưng yêu cầu có kiểu GET mới được chuyển tiếp đến handleRequest(), ngược lại chỉ những yêu cấu có kiểu POST mới được chuyển tiếp đến phương thức submitStudentInfo(). Điều này được thực hiện qua việc chỉ ra RequestMethod trong annotation RequestMapping.

index.jsp

 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  
 <%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>  
 <html>  
  <head><title>Example :: Spring Application</title></head>  
  <body>  
   <h1>CoderSonTrang - Spring MVC Demo</h1>  
   <h3>Student Book Show</h3>  
   <form:form method="POST" action="submitStudentInfo" commandName="model">  
        Your name: <c:out value="${model.name }"/><form:hidden path="name"/><br/><br/>  
        Edit your list of books:   
        <c:forEach items="${model.books}" var="book" varStatus="status">  
             <form:input path="books[${status.index}]"></form:input>  
        </c:forEach>  
        <input type="submit" value="Submit"/>  
   </form:form>
   <div style="background:#972F2C;color: #FFF;"><c:out value="${message}"/></div>  
  </body>  
 </html>  

File index.jsp chính là View trong ví dụ của chúng ta. Là nơi lấy dữ liệu từ model và hiển thị về phía người dùng. Ở đây dữ liệu được lấy ra từ model sử dụng JSTL và thẻ của Spring MVC.

Deploy và chạy ứng dụng trên web server Apache Tomcat, ví dụ của chúng ta khi chạy sẽ giống như dưới đây:

Khi request đến url “/home“, phương thức handleRequest() sẽ được gọi, kế tiếp tạo ra một model là một đối tượng của kiểu Student, thực hiện đặt dữ liệu vào trong model và chuyển tiếp đến trang index.jsp. Khi đó ta nhận kết quả hiển thị trên browswer sẽ như sau:

codersontrang_springmvcdemo_2

Khi bấm vào nút Submit, yêu cầu sẽ được gửi đến phương thức submitStudentInfo() trong controller, trong phương thức này sẽ lấy ra thông tin về tên các quyển sách từ model, kiểm tra xem trong số đó có 2 quyển sách nào đó bị trùng tên không. Trong trường hợp phát hiện ra trùng tên thì sẽ gửi một message là “Books must have different name !!!” về phía view như hình dưới đây:

codersontrang_springmvcdemo_3

Trong trường hợp không có quyển sách nào bị trùng tên, màn hình sẽ hiện ra messsage “Update success !!!
codersontrang_springmvcdemo_4

Mô hình MVC là một mô hình nổi tiếng và được ứng dụng rất nhiều trong thiết kế ứng dụng web. Có muôn vàn cài đặt cho mô hình này cho các ngôn ngữ khác nhau. Spring MVC chỉ là một cài đặt cho ngôn ngữ Java mà thôi. Chính vì vậy, cái ta cần nắm được chính là tư tưởng của mô hình thay vì chi tiết của ngôn ngữ. Khi đó chúng ta sẽ rất dễ dàng thích ứng khi phải chuyển từ cài đặt này sang cài đặt khác.

Tái bút: Ví dụ trong bài viết này còn được nhắc lại trong bài viết “Một cách nhìn khác về ứng dụng web với Spring MVC, Spring Boot, Tomcat dạng nhúng và Thymeleaf

Good luck!!!!

Advertisements

12 comments on “Giới thiệu về Spring MVC

  1. To Sơn Trang
    Mình không thấy có phần tạo DB, cấu hình DB. Cách thức truy vấn như thế nào. Bạn có thể thêm phần này vào để những người đọc như mình dễ hiểu hơn được không?
    Xin lỗi bạn vì đã đòi hỏi nhiều.
    Cảm ơn những bài viết của bạn.
    Lanh Pham

    Số lượt thích

  2. Bạn ơi mình làm theo cách của bạn thì bị lỗi 500. trong đó nó báo “No WebApplicationContext found: no ContextLoaderListener registered?” mình tìm hiểu thì thấy đa số trường hợp trả lời là mình thiếu:

    org.springframework.web.context.ContextLoaderListener

    nhưng khi thêm vao lại tiếp tục bị lỗi:
    cvc-complex-type.2.4.a: Invalid content was found starting with element ‘listener’. One of ‘{“http://java.sun.com/
    xml/ns/javaee”:init-param, “http://java.sun.com/xml/ns/javaee”:load-on-startup, “http://java.sun.com/xml/ns/
    javaee”:enabled, “http://java.sun.com/xml/ns/javaee”:async-supported, “http://java.sun.com/xml/ns/
    javaee”:run-as, “http://java.sun.com/xml/ns/javaee”:security-role-ref, “http://java.sun.com/xml/ns/
    javaee”:multipart-config}’ is expected.
    bạn giúp mình nha. cảm ơn bạn nhiều

    Số lượt thích

  3. Pingback: Spring framework 5 phiên bản mới có gì vui | Coder Sơn Trang

  4. Pingback: Một cách nhìn khác về ứng dụng web với Spring MVC, Spring Boot, Tomcat dạng nhúng và Thymeleaf | Coder Sơn Trang

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất /  Thay đổi )

Google photo

Bạn đang bình luận bằng tài khoản Google Đăng xuất /  Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất /  Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất /  Thay đổi )

Connecting to %s