Nội dung:
- Giới thiệu
- Tạo một dự án
- Kết nối MVC mùa xuân
- Tạo trang và bộ điều khiển
- Cấu hình
- Người mẫu
- Bộ điều khiển xem mô hình
Giới thiệu
Tôi bắt đầu làm quen với các công nghệ và khuôn khổ mới đối với mình bằng cách nghiên cứu các ví dụ khác nhau mà chúng được sử dụng, bởi vì tôi thường hiểu điều gì đó tốt nhất khi tôi thấy nó hoạt động bằng cách sử dụng một ví dụ về một ứng dụng chính thức. Thông thường, những ví dụ như vậy là các ứng dụng CRUD ( C reate, Read , U pdate, Delete ), Internet có đầy đủ các ví dụ như vậy với mức độ phức tạp khác nhau. Vấn đề là họ thường không giải thích chi tiết cách thức, cái gì và tại sao được thực hiện ở đó, tại sao sự phụ thuộc như vậy và như vậy lại được thêm vào, tại sao lại cần một lớp như vậy, v.v. Trong hầu hết các trường hợp, họ lấy một ứng dụng hoàn chỉnh, với tệp POM cuối cùng, với các phiên bản cuối cùng của các lớp và chỉ cần chạy qua từng ứng dụng mà không tập trung vào những điều nhỏ nhặt mà người có kinh nghiệm có thể thấy rõ. Tôi đã xem xét rất nhiều ví dụ như vậy và thường thấy rõ mọi thứ hoạt động như thế nào, nhưng cách chúng đi đến điều này thì không hoàn toàn rõ ràng. Vì vậy, tôi quyết định rằng một ví dụ như vậy sẽ hữu ích, không phải từ vị trí của một nhà phát triển có kinh nghiệm, mà từ vị trí của một người mới bắt đầu chưa bao giờ xử lý Spring, Hibernate và những thứ khác.Tạo một dự án
Vì vậy, vì tôi là người mới nên chúng tôi sẽ không sử dụng bất kỳ nguyên mẫu khó hiểu nào. Khởi tạo mùa xuân nghe vẫn quá đáng sợ. Vì vậy, chúng ta sẽ tạo dự án Maven đơn giản thông thường nhất. Tôi không có tên miền nên trong groupid tôi sẽ chỉ viếttestgroup
, còn trong Artifactid tôi sẽ viết tên chẳng hạn filmography
(đây sẽ là danh sách các bộ phim). Chúng tôi tạo ra một dự án và chọn Enable auto-import
thời điểm ý tưởng gợi ý nó. Nhờ đó, mỗi khi chúng ta thực hiện bất kỳ thay đổi nào đối với file POM (Project Object Model, file này mô tả toàn bộ cấu trúc của dự án Maven) thì mọi thứ sẽ ngay lập tức được tự động áp dụng cho dự án. Các thư viện sẽ được lấy từ kho lưu trữ cục bộ của chúng tôi nếu chúng tôi đã có chúng hoặc nếu chúng tôi sử dụng một số phần phụ thuộc mới mà chúng tôi chưa xử lý trước đó, Maven sẽ chỉ cần tải chúng xuống qua Internet từ kho lưu trữ trung tâm. Maven còn có chức năng tải nguồn và tài liệu (Download Sources and/hoặc Documentation). Nó cũng rất thuận tiện, nếu có điều gì đó không rõ ràng với một số lớp hoặc phương thức, bạn có thể truy cập mã nguồn và xem tất cả hoạt động bên trong như thế nào. Hãy thêm một vài chi tiết. Đây sẽ là một ứng dụng web và chúng ta sẽ sử dụng Tomcat . Để triển khai một ứng dụng lên Tomcat, bạn cần chuyển nó đến đó dưới dạng kho lưu trữ chiến tranh (Tài nguyên ứng dụng web, một định dạng đặc biệt cho các ứng dụng web). Để thực hiện việc này, hãy thêm dòng sau vào tệp POM để ứng dụng được biên dịch thành kho lưu trữ chiến tranh:
<packaging>war</packaging>
Chà, bạn cũng sẽ cần một thư mục đặc biệt cho các nguồn web, trong trường hợp của chúng tôi sẽ có các trang jsp và một số tài nguyên web. Hãy tạo một main
thư mục webapp
. Nó phải được gọi chính xác như vậy và được đặt theo main
cách giống hệt như java
, resources
vì đây là cấu trúc thư mục Maven tiêu chuẩn. Khi chúng tôi đã cài đặt gói vào war
và xác định rằng đây là một dự án web, thư mục webapp
sẽ tự động được đánh dấu là nguồn ứng dụng Web (sẽ có một chấm màu xanh trên đó) và mọi thứ liên quan đến web sẽ được tìm kiếm trong thư mục này. Và một khoảnh khắc. Theo mặc định, Maven sử dụng ngôn ngữ phiên bản 1.5, nhưng tôi muốn sử dụng, ví dụ: phiên bản 1.8 - Java 8 (Bạn có thể lấy 10 hoặc 11, nhưng vẫn chưa có kế hoạch sử dụng bất kỳ tính năng nào từ đó, vì vậy hãy để nó là 8 ). Điều này có thể được giải quyết rất đơn giản, chúng tôi viết vào Google một cái gì đó giống như “Maven java 8” và xem những gì cần thêm vào tệp POM để Maven biên dịch các lớp của chúng tôi cho phiên bản được yêu cầu. Kết quả là chúng ta có những điều sau đây:
Kết nối MVC mùa xuân
Bạn phải bắt đầu từ đâu đó. Theo kế hoạch, chúng tôi sẽ kết nối cơ sở dữ liệu và sử dụng Hibernate, nhưng hiện tại tất cả điều này nghe có vẻ hơi quá đáng sợ. Trước tiên chúng ta cần làm điều gì đó đơn giản hơn. Spring MVC thì cái này đã tốt hơn rồi, chúng ta đã quen với mẫu MVC từ lâu rồi, nó được sử dụng trong một nửa số task lớn của khóa học. Từ đây chúng ta sẽ bắt đầu khiêu vũ. Để tạo một ứng dụng web với Spring MVC, chúng ta cũng cần có Servlet-API, tức là. thứ mà sự tương tác yêu cầu-phản hồi sẽ diễn ra. Hãy thử kết nối điều này. Chúng tôi truy cập Google, tìm kiếm các phần phụ thuộc cần thiết trong kho lưu trữ Maven và thêm chúng vào tệppom.xml
. Trong phần Thư viện bên ngoài, bạn có thể thấy rằng không chỉ spring-webmvc đã được tải mà còn có rất nhiều thứ khác. Những thứ kia. chúng ta không cần thêm các phần phụ thuộc cho spring core , context , Beans , v.v. mà chúng tôi cần, mọi thứ chúng tôi cần đều được đưa lên cùng với spring-webmvc .
Chúng ta cần đưa ra một tuyên bố từ chối trách nhiệm nhỏ. Thông thường, bạn vẫn nên thêm một phần phụ thuộc riêng biệt cho từng thư viện được sử dụng, ngay cả khi chúng đã được gói cùng với những thư viện đã được thêm vào, bởi vì điều này có thể giúp tránh được một số vấn đề và trục trặc. Một ví dụ đơn giản. Giả sử chúng tôi đã thêm một phần phụ thuộc sử dụng một số API, đồng thời nó sẽ đưa ra một số hình thức triển khai cho API này. Sau đó, chúng tôi đã thêm một phần phụ thuộc khác sử dụng cùng một API và cũng đưa ra một số cách triển khai cho việc này, nhưng lần này thì khác. Vì vậy, chúng ta sẽ có 2 cách triển khai khác nhau của cùng một API. Và nếu bản thân chúng ta muốn sử dụng một số phương thức của API này ở đâu đó thì sẽ nảy sinh một vấn đề, vì hệ thống sẽ không biết nên sử dụng cách triển khai nào, nó sẽ chọn ngẫu nhiên, có thể không phải là phương pháp mà chúng ta mong đợi. Và nếu bạn chỉ định rõ ràng phần phụ thuộc cho một trong các cách triển khai thì nó sẽ được ưu tiên. Tuy nhiên, đây không phải là một khuyến nghị nghiêm ngặt; nó chủ yếu áp dụng cho các dự án lớn sử dụng nhiều thư viện khác nhau từ các công ty khác nhau. Chúng tôi sẽ không làm điều đó ở đây để không tải tệp POM quá nhiều; sẽ không có vấn đề gì. Nhưng tuy nhiên, nó vẫn đáng để ghi nhớ điều này. |
provided
Tùy thuộc nghĩa là gì javax.servlet-api
? Phạm vi là phạm vi của phần phụ thuộc, provided
nghĩa là phần phụ thuộc sẽ có sẵn ở giai đoạn biên dịch và kiểm tra ứng dụng, nhưng nó sẽ không được lưu trữ. Thực tế là để triển khai ứng dụng, chúng tôi sẽ sử dụng một thùng chứa servlet, Tomcat và nó đã có sẵn các thư viện như vậy bên trong, vì vậy không cần phải chuyển chúng đến đó và tạo gánh nặng cho kho lưu trữ với tải không cần thiết. Nhìn về phía trước, vì lý do tương tự, chúng tôi sẽ thực hiện mà không cần phương pháp thông thường main
, bởi vì nó đã tồn tại bên trong Tomcat.
Tạo trang và bộ điều khiển
Bây giờ chúng ta hãy thử nấu một cái gì đó đơn giản. Trước tiên, hãy tạo mộtwebapp
thư mục bổ sung, ví dụ pages
: trong đó các chế độ xem của chúng tôi sẽ được lưu trữ, tức là. jsp và tạo một vài trang. Chúng tôi sẽ cần một trang mà trong tương lai sẽ hiển thị danh sách các bộ phim, chẳng hạn như films.jsp
và có lẽ chúng tôi có thể tạo một trang riêng để chỉnh sửa, hãy để nó như vậy editPage.jsp
. Hiện tại, chúng tôi sẽ không điền vào chúng bất kỳ thông tin nghiêm trọng nào; chỉ để thử nghiệm, chúng tôi sẽ tạo liên kết trên trang này với trang khác. Bây giờ chúng ta cần một lớp sẽ xử lý các yêu cầu, tức là. bộ điều khiển. Chúng ta hãy thêm một gói mới controller
và tạo một lớp trong đó FilmController
(nói chung không cần thiết phải đóng gói mọi thứ trong các gói khác nhau, ứng dụng này sẽ rất nhỏ và đơn giản, nhưng trong một dự án bình thường có thể có nhiều bộ điều khiển, lớp cấu hình, mô hình , v.v., vì vậy ngay cả khi bắt đầu với những dự án nhỏ, tốt hơn hết bạn nên làm quen ngay với việc thực hiện mọi thứ một cách có trật tự và có cấu trúc để không bị lộn xộn). Trong lớp này, chúng ta sẽ tạo các phương thức trả về các khung nhìn của chúng ta để đáp ứng các yêu cầu.
package testgroup.filmography.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class FilmController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView allFilms() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("films");
return modelAndView;
}
@RequestMapping(value = "/edit", method = RequestMethod.GET)
public ModelAndView editPage() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("editPage");
return modelAndView;
}
}
Vấn đề ở đây là gì? Spring MVC có một thứ gọi là DispatcherServlet
. Điều này giống như bộ điều khiển chính, tất cả các yêu cầu đến đều đi qua nó và sau đó chuyển chúng đến một bộ điều khiển cụ thể. Chú thích @Controller
chỉ cho Spring MVC biết rằng lớp này là một bộ điều khiển (nói chung là logic), bộ điều phối sẽ kiểm tra các chú thích @RequestMapping
để gọi phương thức thích hợp. Chú thích @RequestMapping
cho phép bạn đặt địa chỉ cho các phương thức điều khiển, theo đó chúng sẽ có sẵn trong máy khách (trình duyệt). Nó cũng có thể được áp dụng cho lớp trình điều khiển để đặt, có thể nói, địa chỉ gốc cho tất cả các phương thức. allFilms()
Tham số cho phương thức value
được đặt thành " /
", do đó, nó sẽ được gọi ngay lập tức khi nhập tổ hợp http://host:port/ vào trình duyệt (tức là theo mặc định là http://localhost:8080/ hoặc http ://127.0 .0.1:8080/ ). Tham số chỉ method
định loại yêu cầu nào được hỗ trợ (GET, POST, PUT, v.v.). Vì ở đây chúng ta chỉ nhận dữ liệu nên GET được sử dụng. Sau này, khi các phương thức thêm và chỉnh sửa xuất hiện thì sẽ có sẵn các yêu cầu POST. (Nhân tiện, thay vì một chú thích @RequestMapping
chỉ ra một phương thức, bạn có thể sử dụng các chú thích @GetMapping
, @PostMapping
v.v. @GetMapping
tương đương @RequestMapping(method = RequestMethod.GET
)). Trong các phương thức của chúng tôi, chúng tôi tạo một đối tượng ModelAndView
và đặt tên của chế độ xem cần được trả về.
Cấu hình
Hãy chuyển sang thiết lập cấu hình.config
Hãy tạo một lớp trong gói WebConfig
. Nó sẽ chỉ có một phương thức trả về một đối tượng thuộc loại ViewResolver
, đây là giao diện cần thiết để tìm một biểu diễn theo tên.
package testgroup.filmography.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "testgroup.filmography")
public class WebConfig {
@Bean
ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
@Configuration
cho Spring biết rằng lớp này là lớp cấu hình và chứa các định nghĩa cũng như phần phụ thuộc bean
của các thành phần. Bean là đối tượng được quản lý bởi Spring. Chú thích được sử dụng để xác định một hạt đậu @Bean
. @EnableWebMvc
cho phép bạn nhập cấu hình Spring MVC từ tệp WebMvcConfigurationSupport
. Ví dụ: bạn cũng có thể triển khai một giao diện WebMvcConfigurer
có rất nhiều phương thức và tùy chỉnh mọi thứ theo ý thích của mình, nhưng chúng ta chưa cần đi sâu vào đó, cài đặt tiêu chuẩn là đủ. @ComponentScan
cho Spring biết nơi tìm các thành phần mà nó sẽ quản lý, tức là. các lớp được đánh dấu bằng chú thích @Component
hoặc các dẫn xuất của nó như @Controller
, @Repository
, @Service
. Những chú thích này tự động xác định lớp đậu. Trong phương thức này, viewResolver()
chúng tôi tạo ra cách triển khai nó và xác định chính xác vị trí cần tìm các biểu diễn trong webapp
. Do đó, khi trong phương thức điều khiển, chúng ta đặt tên " films
", khung nhìn sẽ được tìm thấy là " /pages/films.jsp
" Vì vậy, chúng ta có một lớp cấu hình, nhưng hiện tại nó chỉ là một loại lớp riêng biệt nào đó, nó không ảnh hưởng đến ứng dụng của chúng ta theo bất kỳ cách nào . Chúng ta cần đăng ký cấu hình này trong ngữ cảnh Spring. Đối với điều này, bạn cần một lớp AbstractAnnotationConfigDispatcherServletInitializer
. Trong gói này, config
chúng tôi tạo ra phần kế tiếp của nó, chẳng hạn như AppInitializer và triển khai các phương thức của nó.
package testgroup.filmography.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
Phương thức cuối cùng đăng ký địa chỉ và có thêm 2 phương thức để đăng ký các lớp cấu hình. Các cấu hình web, trong đó ViewResolver
's và những thứ tương tự được xác định, được đặt trong getServletConfigClasses()
. Tốt hơn hết là bạn nên đọc về tất cả những điều này trong tài liệu và các hướng dẫn khác nhau, nhưng trong trường hợp của chúng tôi thì chưa cần thiết phải đi sâu vào vấn đề này, WebConfig
về nguyên tắc, của chúng tôi có thể được RootClasses
định nghĩa trong cả hai, thậm chí bạn có thể định nghĩa cả hai cùng một lúc, nó vẫn sẽ hoạt động . Một điều nữa. Có thể có vấn đề về mã hóa khi gửi các giá trị có ký tự tiếng Nga từ biểu mẫu, kết quả sẽ là những nét vẽ nguệch ngoạc. Để giải quyết vấn đề này, chúng tôi sẽ thêm một bộ lọc xử lý trước các yêu cầu. Chúng tôi đi đến lớp AppInitializer và ghi đè phương thức getServletFilters
, trong đó chúng tôi chỉ ra mã hóa mong muốn, tất nhiên, nó phải giống như mọi nơi khác, như trên các trang và trong cơ sở dữ liệu:
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[] {characterEncodingFilter};
}
Chà, mọi thứ dường như đã được thiết lập, bạn có thể thử chạy nó và xem điều gì sẽ xảy ra. Chạy -> Chạy -> Chỉnh sửa cấu hình -> Thêm cấu hình mới -> Máy chủ Tomcat -> Cục bộ Tiếp theo, bạn cần chọn một tạo phẩm để triển khai. Bản thân ý tưởng sẽ đưa ra gợi ý Cảnh báo: Không có tạo phẩm nào được đánh dấu để triển khai . Bấm vào nút sửa và chọn ...: chiến tranh bùng nổ . Hoặc bạn có thể vào Deployment -> add -> Artifact -> ...: war boom . Và bạn cũng cần vào phần Triển khai và đặt trường ngữ cảnh Applecation (đây sẽ là một phần của địa chỉ url nơi ứng dụng sẽ có sẵn trong trình duyệt) thành " /
". Sau đó, ứng dụng của chúng tôi sẽ có sẵn ngay lập tức tại http://localhost:8080/ (nhưng bạn cũng có thể chỉ định một cái gì đó ở đó, ví dụ: " /filmography
", và sau đó bạn sẽ chỉ cần thêm địa chỉ này vào tất cả các địa chỉ, ví dụ: sẽ không có " http://localhost:8080/edit" , nhưng nó sẽ là "http://localhost:8080/filmography/edit" ). Bấm vào Chạy và đợi cho đến khi nó bắt đầu. Đây là những gì tôi nhận được: Mọi thứ có vẻ ổn nhưng có một điều cần lưu ý. Thực tế là các trang của chúng tôi hiện có thể truy cập công khai và có thể được truy cập trực tiếp bằng cách viết đường dẫn vào thanh địa chỉ. Chúng tôi nhập http://localhost:8080/pages/films.jsp và bây giờ chúng tôi đã nhận được trang của mình mà người điều khiển không hề hay biết. Bằng cách nào đó điều này không chính xác lắm, vì vậy chúng tôi sẽ tạo một webapp
thư mục đặc biệt WEB-INF
. Những gì bên trong sẽ bị ẩn khỏi công chúng và chỉ có thể được truy cập thông qua bộ điều khiển. Chúng tôi đặt thư mục có các khung nhìn của chúng tôi ( pages
) trong WEB-INF
, và ViewResolver
theo đó thêm nó vào tiền tố:
viewResolver.setPrefix("/WEB-INF/pages/");
Bây giờ chúng tôi nhận được trang của mình tại http://localhost:8080 , nhưng nếu chúng tôi thử truy cập trực tiếp vào http://localhost:8080/WEB-INF/pages/films.jsp thì chúng tôi gặp lỗi 404. Tuyệt vời, chúng tôi có ứng dụng web đơn giản nhất, Hello World như người ta nói. Cấu trúc dự án hiện tại trông như thế này:
Người mẫu
Chúng tôi đã có chế độ xem và bộ điều khiển, nhưng trong MVC cũng có chữ cái thứ 3, vì vậy để hoàn thiện bức tranh, chúng tôi cũng sẽ thêm một mô hình. Trong gói,model
hãy tạo một lớp Film
, chẳng hạn, với các trường sau: int id
, String title
(tiêu đề), int year
(năm phát hành), String genre
(thể loại) và boolean watched
(tức là bạn đã xem phim này hay chưa).
package testgroup.filmography.model;
public class Film {
private int id;
private String title;
private int year;
private String genre;
private boolean watched;
// + Getters and setters
}
Không có gì đặc biệt, chỉ là một lớp bình thường, các trường riêng, getters và setters. Các đối tượng của các lớp như vậy còn được gọi là POJO
(Đối tượng Java cũ đơn giản), tức là. "đối tượng java đơn giản". Bây giờ chúng ta hãy thử tạo một đối tượng như vậy và hiển thị nó trên trang. Hiện tại, chúng ta sẽ không lo lắng quá nhiều về cách tạo và khởi tạo nó. Để dùng thử, chúng ta hãy ngu ngốc tạo nó trực tiếp trong bộ điều khiển, ví dụ như thế này:
public class FilmController {
private static Film film;
static {
film = new Film();
film.setTitle("Inception");
film.setYear(2010);
film.setGenre("sci-fi");
film.setWatched(true);
}
Và thêm đối tượng này vào đối tượng của chúng tôi ModelAndView
bằng phương thức addObject
:
@RequestMapping(method = RequestMethod.GET)
public ModelAndView allFilms() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("films");
modelAndView.addObject("film", film);
return modelAndView;
}
Bây giờ chúng ta có thể hiển thị đối tượng này trên trang của mình. Thay films.jsp
vì Hello World, chúng ta sẽ viết ${film}
và đối tượng tương ứng với tên thuộc tính " film
" sẽ được thay thế ở đây. Hãy thử chạy nó và xem điều gì đã xảy ra (để có kết quả rõ ràng về đối tượng, lớp Film
đã được xác định lại toString()
):
Bộ điều khiển xem mô hình
Ở giai đoạn này, chúng ta dường như đã có một ứng dụng Spring MVC hoàn chỉnh. Trước khi tiếp tục, bạn nên xem lại mọi thứ một lần nữa và tìm hiểu xem mọi thứ hoạt động như thế nào. Trên Internet bạn có thể tìm thấy nhiều hình ảnh và sơ đồ về điều này, tôi thích cái này:Dispatcher Servlet
, sau đó nó sẽ tìm một bộ điều khiển phù hợp để xử lý yêu cầu này bằng cách sử dụng HandlerMapping
(đây là giao diện để chọn bộ điều khiển, kiểm tra xem bộ điều khiển nào có sẵn có phương thức chấp nhận địa chỉ đó) , gọi một phương thức phù hợp và Controller
trả về thông tin về chế độ xem, sau đó người điều phối tìm thấy chế độ xem mong muốn theo tên bằng cách sử dụng ViewResolver
'a, sau đó dữ liệu mô hình được chuyển đến chế độ xem này và chúng tôi lấy trang của mình làm đầu ra. Một cái gì đó như thế này. Còn tiếp... Giới thiệu Maven, Spring, MySQL, Hibernate và ứng dụng CRUD đầu tiên (phần 1) Giới thiệu Maven, Spring, MySQL, Hibernate và ứng dụng CRUD đầu tiên (phần 2) Giới thiệu Maven, Spring, MySQL, Hibernate và Ứng dụng CRUD đầu tiên (phần 3) Giới thiệu về Maven, Spring, MySQL, Hibernate và ứng dụng CRUD đầu tiên (phần 4)
GO TO FULL VERSION