Gradle – wprowadzenie
Gradle – wprowadzenie
Gradle to obok Apache Maven jedno z najbardziej popularnych narzędzi które służą do budowania projektu. Narzędzie to pozwala zautomatyzować proces budowania aplikacji z użyciem języka domenowego DSL. Gradle w porównaniu do Mavena daje nam większą elastyczność – o czym w dalszej części artykułu. Poznawanie gradle’a zaczniemy od utworzenia nowego projektu w Intellij Idea:
po zdefiniowaniu parametrów group, name, version zostanie wygenerowana struktura projektu zawierająca pliki (w mavenie odpowiednikiem jest groupId, artifactId, version):
- build.gradle – zawiera opis budowania projektu w języku Groovy,
- gradlew.sh – Gradle Wrapper dla systemu linux, m.in. weryfikuje czy gradle jest poprawnie zainstalowany, pozwala uniezależnić się od wersji gradle’a zainstalowanej na komputerze programisty.
- gradlew.bat – Gradle Wrapper dla MS Windows, m.in. weryfikuje czy gradle jest poprawnie zainstalowany, pozwala uniezależnić się od wersji gradle’a zainstalowanej na komputerze programisty.
- settings.gradle – zawiera konfigurację projektu, po wygenerowaniu projektu plik ten zawiera tylko jego nazwę.
W katalogu projektu wydajemy następujące polecenie:
gradlew build --console=verbose
w wyniku otrzymujemy:
Welcome to Gradle 4.8! Here are the highlights of this release: - Dependency locking - Maven Publish and Ivy Publish plugins improved and marked stable - Incremental annotation processing enhancements - APIs to configure tasks at creation time For more details see https://docs.gradle.org/4.8/release-notes.html Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details > Task :compileJava NO-SOURCE > Task :processResources NO-SOURCE > Task :classes UP-TO-DATE > Task :jar > Task :assemble > Task :compileTestJava NO-SOURCE > Task :processTestResources NO-SOURCE > Task :testClasses UP-TO-DATE > Task :test NO-SOURCE > Task :check UP-TO-DATE > Task :build BUILD SUCCESSFUL in 21s 1 actionable task: 1 executed
parametr -console=verbose pozwala wyświetlić więcej informacji na konsoli. Została wykonana cała seria zadań która składa się na budowania projektu. Zawartość pliku build.gradle – zależności pobierane widać są z centralnego repozytorium mavena. Poniżej dodana jest tylko jedna zależność do biblioteki junit 4.12.
plugins { id 'java' } group 'pl.javaleader' version '1.0-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' }
Gradle działa na zasadzie zadań, zadaniem może być utworzenie pliku JAR czy uruchomienie testów. Dodajmy teraz pierwsze własne zadanie do pliku build.gradle:
task javaLeaderMsgHelloWorld javaLeaderMsgHelloWorld.doFirst( { println "This is done first JavaLeader.pl" } ); javaLeaderMsgHelloWorld.doLast( { println "This is done last JavaLeader.pl" } );
uruchamiamy zadanie:
gradlew javaLeaderMsgHelloWorld
wynik:
> Task :javaLeaderMsgHelloWorld This is done first JavaLeader.pl This is done last JavaLeader.pl
Używając Apache Maven nie byłoby to takie proste ze względu na sztywny proces budowania (lifecycle)…
Projekt wielomodułowy:
Wielomodułowy projekt pozwala lepiej podzielić poszczególne warstwy aplikacji, utwórzmy zatem nowy moduł:
podając nazwę: name = api (grupa oczywiście jest ta sama bo to podprojekt, nie musimy jej ponownie podawać).
Plik settings.gradle głównego projektu przedstawia się następująco:
rootProject.name = 'gradle-intro' include 'api'
dodajmy interfejs do modułu api:
public interface MsgService { String showMsg(); }
oraz jego implementację:
public class MsgServiceImpl implements MsgService { @Override public String showMsg() { return "JavaLeader.pl"; } }
w pliku build.gradle głównego projektu dodajemy zależność do podmodułu – api:
dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' compile project(":api") }
Do głównego projektu dodajemy klasę która wykorzystuje klasy z modułu – api:
public class MessagePrinter { public static void main(String[] args) { MsgService msgService = new MsgServiceImpl(); msgService.showMsg(); System.out.println(); } }
tworzymy nowy moduł – WebPage – który będzie aplikacją webową z pakowaniem war. Niestety w gradle nie ma archetypów a wsparcie do tworzenia projektów według zdefiniowanego szablonu jest ubogie – https://docs.gradle.org/current/userguide/build_init_plugin.html. Należy zatem “ręcznie” utworzyć strukturę projektu aplikacji web.
Plik gradle.build aplikacji webowej:
plugins { id 'java' id 'war' id 'org.gretty' version '2.2.0' }
dodajemy sposób pakowania projektu typowy dla aplikacji webowych – war – oraz plugin który pozwala w łatwy sposób uruchomić aplikację z użyciem serwera Jetty lub serwera Apache Tomcat. Dodajemy również zależność do modułu – api i obsługę servletów – javax.servlet-api:
dependencies { providedCompile 'javax.servlet:javax.servlet-api:3.1.0' testCompile group: 'junit', name: 'junit', version: '4.12' compile project(":api") }
należy również dodać nazwę repozytorium – jcenter() – inaczej nie uda się dodać zależności do pluginu org.gretty:
repositories { mavenCentral() jcenter() }
Tworzymy teraz przykładowy servlet:
@WebServlet(name = "JavaLeaderHomeServlet", urlPatterns = {"home"}, loadOnStartup = 1) public class JavaLeaderHomeServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { MsgService msgService = new MsgServiceImpl(); response.getWriter().print(msgService.showMsg()); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); if (name == null) { name = "noname"; } request.setAttribute("user", name); request.getRequestDispatcher("response.jsp").forward(request, response); } }
Plik webapp/index.html:
<html> <head> <title>Web Demo</title> </head> <body> <form method="post" action="home"> <h2>Name:</h2> <input type="text" id="say-hello-text-input" name="name" /> <input type="submit" id="say-hello-button" value="Say Hello" /> </form> </body> </html>
Plik webapp/response.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Hello Page</title> </head> <body> <h2>Hello, ${user}!</h2> </body> </html>
Uruchomienie aplikacji sprowadza się do wykonania zadania:
gradlew appRun
Pod adresem:
http://localhost:8080/web-app/
widoczny jest formularz z pliku webapp/index.html:
Pod adresem:
http://localhost:8080/web-app/home
widać odpowiedź z servletu dla mapowania adresu /home dla metody get:
JavaLeader.pl
Pod adresem:
http://localhost:8080/web-app/home
widać odpowiedź z servletu dla mapowania adresu /home dla metody post.
Hello, JavaLeader.pl!
Testy jednostkowe z użyciem biblioteki Mockito:
Dodajemy zależność do biblioteki Mockito celem przetestowania Servletu:
dependencies { providedCompile 'javax.servlet:javax.servlet-api:3.1.0' testCompile 'org.mockito:mockito-core:2.7.19' testCompile group: 'junit', name: 'junit', version: '4.12' compile project(":api") }
tworzymy klasę testową w pakiecie ./test/java która pozwoli przetestować Servlet:
public class JavaLeaderTestServlet { @Mock private HttpServletRequest request; @Mock private HttpServletResponse response; @Mock private RequestDispatcher requestDispatcher; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } @Test public void doGet() throws Exception { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); when(response.getWriter()).thenReturn(printWriter); new JavaLeaderHomeServlet().doGet(request, response); assertEquals("JavaLeader.pl", stringWriter.toString()); } @Test public void doPostWithoutName() throws Exception { when(request.getRequestDispatcher("response.jsp")).thenReturn(requestDispatcher); new JavaLeaderHomeServlet().doPost(request, response); verify(request).setAttribute("user", "noname"); verify(requestDispatcher).forward(request,response); } @Test public void doPostWithName() throws Exception { when(request.getParameter("name")).thenReturn("JavaLeader.pl"); when(request.getRequestDispatcher("response.jsp")).thenReturn(requestDispatcher); new JavaLeaderHomeServlet().doPost(request, response); verify(request).setAttribute("user", "JavaLeader.pl"); verify(requestDispatcher).forward(request,response); } }
Servlet przetestowany jest na 3 różne sposoby z użyciem odpowiednio spreparowanych obiektów – Mock. Po uruchomieniu testów poleceniem:
gradlew test
dostępny jest ich wynik w pliku test/index.html:
jak widać wszystkie testy przeszły prawidłowo.
Leave a comment