במדריך זה של Spring MVC, נלמד איך לפתח אפליקציית אינטרנט באמצעות Spring MVC באמצעות Spring Tool Suite. הסבר נוסף על ה-Spring MVC – מסגרת שרת יישומים רב-שכבתית הנמצאת בשימוש נרחב עבור יישומי רשת Java.
Spring MVC
בדיוק כמו Struts Framework, Spring MVC גם הוא מבוסס על טכנולוגיות Java EE של Servlet ו- JSP ומיישם את תבנית העיצוב Model–View–Controller.
מדריך Spring MVC
ראינו בעבר איך עובדת ה-Injection של תלות ב־Spring ובמדריך זה נלמד איך ליצור אפליקציה אינטרנט פשוטה באמצעות מסגרת Spring MVC. אנו יכולים להשתמש ב־Eclipse או ב־IntelliJ IDE לפיתוח פרוייקטים של Spring, אך SpringSource מספקת Spring Tool Suite (STS) שהוא סביבת פיתוח מבוססת על Eclipse ומגיע עם VMware vFabric tc Server המבוסס על תקן Apache Tomcat ומותאם ליישומים המבוססים על Spring. אני הייתי משתמש ב־STS עבור מדריך Spring MVC ולמדריכים עתידיים אחרים מכיוון שהוא מקל על חיי המפתח על ידי הספקת התכונות הבאות:
- תמיכה ביצירת אפליקציות Spring יסודיות (MVC, Rest, Batch וכו'), נהדר להתחיל את הפרוייקט מאפס. בקרוב נראה במדריך Spring MVC הזה כמה קל ליצור פרוייקט Spring MVC.
- ספקת תכונות שימושיות כגון יצירת קבצי הגדרת Spring, פירוק קבצי הגדרה וקבצים כיתות כדי לספק מידע שימושי עליהם.
- אימות אוטומטי של יישום Spring.
- תמיכה בביצוע שינויים בפרוייקט בקלות, השינויים מתבטאים בקבצי ההגדרה גם.
- עזרה בכתיבת קוד לא רק עבור כיתות אלא גם עבור קבצי הגדרה, אני אוהב מאוד את התכונה הזו מכיוון שברוב הפעמים אנו צריכים לדעת מה ניתן להשתמש בו ופרטיו.
- תמיכה מיטבית בתכנות מונחי הרכיבים (AOP) דרך אינטגרציה של AspectJ.
מבט על כל התכונות ש-STS מספק, גרם לי להתחבר אליו ולהחליט להשתמש בו עבור יישום Spring ועד כה אני מאוד מרוצה ממנו. פשוט הורידו את STS מ- עמוד ההורדה הרשמי של STS והתקינו אותו. אני משתמש ב- STS 3.4.0.RELEASE שמבוסס על שחרור של Eclipse 4.3.1. אם אינך רוצה להשתמש ב- STS ורוצה לקבל את היתרונות שלו ב- Eclipse הקיימת, אז עליך להתקין את התוסף שלו מ- Eclipse Marketplace. השתמש בתמונה למטה כהתייחסות וודא שבחרת בגרסת STS הנכונה להתקנה. התוסף למטה מתאים ל- Eclipse Kepler.
אם אינך רוצה להשתמש בשרת SpringSource, תוכל להפעיל את היישום בכל מעטפת Java EE אחרת כמו Tomcat, JBoss וכו '. למדריך זה, אני אשתמש בשרת שנשלח עם STS אך בדקתי את היישום על ידי ייצואו כקובץ WAR אל שרת Tomcat נפרד והוא עובד בסדר. עכשיו שהסביבת השרת וה-IDE שלנו מוכנים, בואו נמשיך וניצור את פרויקט MVC שלנו הראשון ב-Spring. השלבים למטה תקפים גם עבור STS וגם עבור Eclipse עם התוספות של STS.
יצירת יישום Spring MVC ב- STS או Eclipse
שלב 1: צור פרויקט חדש של Spring מהתפריט. שלב 2: בחלון הפרויקט החדש, תן לו את השם "SpringMVCExample" ובחר את התבנית "פרויקט MVC של Spring". אם אתה משתמש בתבנית זו לפעם הראשונה, STS יוריד אותה מאתר SpringSource. אם ברצונך, תוכל להוסיף את הפרויקט לכל סט עבודה.
שלב 3: כאשר התבנית נורדה, במסך הבא עליך לספק את שם החבילה ברמה העליונה. חבילה זו תשמש כחבילת-בסיס עבור רכיבי Spring.
שלב 4: לאחר שהפרויקט נוצר על ידי תבנית MVC של Spring, הוא ייראה כמו התמונה למטה.
אל תדאג אם אינך רואה את הקובץ User.java, קבצי login.jsp וְ-user.jsp, הם נוספו על ידי. אם הפרויקט שלך לא מודרך ואתה רואה שגיאות מסוימות, הפעל את Maven/Update Project. וודא שביצעת בדיקה עבור אפשרויות "Force update of Snapshots/Releases", עיין בתמונה למטה.
הפרויקט באופן כללי נראה כמו כל יישום אינטרנטי מבוסס על Maven עם כמה קבצי הגדרת Spring. עכשיו זה הזמן לנתח את חלקי הפרויקטים השונים ולהרחיב אותו קצת.
תלותי Spring MVC
הקובץ 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>
artifactId יהיה servlet-context לאפליקציית האינטרנט, ולכן תוכל לשנות אותו אם תרצה משהו אחר. יש כמה מאפיינים מוגדרים עבור גרסאות Spring Framework, AspectJ ו-SLF4j. גיליתי שהם לא מתעדכנים לגרסה האחרונה, ולכן שיניתי אותם לגרסה היציבה ביותר כיום. התלות בפרויקט שאני מעוניין בהן הן;
- spring-context: תלות ב־Spring Core. שים לב להוצאת commons logging למען SLF4J.
- spring-webmvc: ארטיפקט Spring לתמיכה ב-MVC
- aspectjrt: הפנייה ל-API של AspectJ
- SLF4J ו־Log4j: לצורך יומומאות, קל להגדיר את Spring לתמיכה ב־log4j או Java Logging API בזכות השקפה של SLF4J.
- javax.inject – API של JSR330 להתנגדות התלות
יש עוד תלות אחרות, כמו Servlet, JSP, JSTL ו-API של JUnit, אך עבור אפליקציה מתחילה, אפשר להתעלם מהן.
מדריך Spring MVC – הגדרת Log4j
קובץ ה- log4j.xml שנוצר נראה כמו מטה.
<?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>
שימו לב שהוא מדפיס הכל לקונסולה, אנו יכולים בקלות להוסיף מפעילים כדי להפנות את הלוגים אל קבצים.
מדריך Spring MVC – הגדרת מחדש של תיאור האפליקציה
בואו נסתכל על web.xml שלנו וננתח אותו.
<?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
מקשר את מחזיק ההקשר של ApplicationContext
למחזיק ההקשר של ServletContext
ומאופטמת את יצירת ה- ApplicationContext
. ApplicationContext
הוא המקום שבו מתארגנים הבונים של Spring ואנו יכולים לספק את התצורה שלו דרך הפרמטר ההקשר contextConfigLocation. קובץ root-context.xml מספק את פרטי התצורה עבור WebApplicationContext. DispatcherServlet
הוא מחלקת הבקרה עבור אפליקציית Spring MVC וכל בקשות הלקוח מתוך ניהול על ידי סרבל זה. ההגדרה נטענת מקובץ servlet-context.xml.
הדרכה ל Spring MVC – קבצי הגדרה
קובץ root-context.xml:
<?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:
<?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>
כך נראית קובץ התצורה הסטנדרטי של Spring, פשוט תדמיין שכותבים את כל זה בעצמך ותתחיל לאהוב את כלי ה-STS. הרכיב annotation-driven משמש כדי להודיע לסרבל הבקרה שהוא ישתמש באנוטציות להגדרת הפוליים. רכיב resources מגדיר את המיקום שבו ניתן לשים קבצים סטטיים כמו תמונות, דפי HTML וכו' שאינם רוצים להשיג דרך מסגרת ה-Spring. InternalResourceViewResolver
הוא המפרש של התצורת התצורה, ניתן לספק מיקום של עמודי תצוגה דרך הנכסים prefix ו-suffix. לכן כל דפי ה-JSP שלנו צריכים להיות בתיקיית /WEB-INF/views/. הרכיב context:component-scan משמש לספק את המיקום של החבילה הבסיסית לסריקת דרכים של כיתות בקרת הבקרה. זכור את ערך החבילה רמת העל שניתן בזמן יצירת הפרוייקט, זהו אותו ערך המשמש כאן.
מחלקת בקרת Spring MVC
HomeController נוצר אוטומטית עם השיטה home(), אף שהרחבתי אותו קצת על ידי הוספת שתי שיטות נוספות – loginPage() ו-login().
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";
}
}
@Controller הוא אינדיקטור שמציין שזו כיתת בקרת רשת. @RequestMapping נמצא בשימוש עם מחלקות ושיטות כדי להפנות את בקשת הלקוח לשיטת הטיפול המסוימת. שימו לב ששיטות הטיפול מחזירות מחרוזת, שזו צריכה להיות שם העמוד התצוגה המשמש כתגובה. כפי שניתן לראות, יש לנו שלוש שיטות המחזירות מחרוזות שונות, ולכן יש צורך ליצור עמודי JSP עם אותו שם. שימו לב ששיטת login() תתבצע עם HTTP method כ-POST, ולכן אנו מצפים לקבל נתוני טופס כאן. לכן יש לנו מחלקת מודל User והיא מסומנת לאימות באמצעות @Validated. כל שיטה כוללת את Model כארגומנט, וניתן להגדיר תכונות שיש להשתמש בהן מאוחר יותר בדפי התגובה של JSP.
מחלקות המודל של Spring MVC
מחלקות המודל משמשות להחזיק במשתנים של טופס, דוגמת המחלקת User שלנו נראית כך.
package com.journaldev.spring;
public class User {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
A simple java bean with the variable name and its getter and setter methods.
מדריך Spring MVC – דפי תצוגה
יש לנו שלוש דפי JSP כמו שמוצג למטה. קוד של 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>
שים לב לשימוש ב־שפת הביטויים של JSP כדי לקבל את ערכי המאפיינים. קוד של 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>
A simple JSP page for the user to provide the userName as input. Notice that form variable name is same as User class variable name. Also, form action is “home” and method is “post”. It’s clear that HomeController login() method will handle this request. user.jsp code:
<%@ 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>
דף בית פשוט למשתמש שבו מוצג שם המשתמש, שים לב שאנו מגדירים את המאפיין הזה בשיטת ההתחברות.
דוגמה ליישום של Spring MVC – בדיקות
היישום שלנו מוכן להרצה, פשוט הפעל אותו על VMware tc Server או בחר בתיק אחר של כל מקור אחר, תקבלו דפים כתגובה.
זהו למדריך Spring MVC, ניתן לראות כמה זה קל ליצור אפליקציית Spring MVC באמצעות תוספות STS. גודל הקוד קטן מאוד ורוב התצורה טופלת על ידי Spring MVC כך שנוכל להתמקד בלוגיקת העסקים. הורד את דוגמת פרויקט Spring MVC מהקישור למטה ושחק איתה.
Source:
https://www.digitalocean.com/community/tutorials/spring-mvc-tutorial