Відмінності war та jar-файлів

Фактично jar-бібліотека – це просто zip архів, що зрозуміло з його імені: Java Archive. Найчастіше він має чотири складові:

  • скомпільовані класи;
  • ресурси: properties-файли тощо;
  • маніфест MANIFEST.MF;
  • інші jar-бібліотеки (рідко).

Вигляд типової структури такого архіву:

  META-INF/
  	MANIFEST.MF
  com/
  	javarush/
	      MyApplication.class
  application.properties

Тепер давай розглянемо типовий war-файл. До речі, war – не від слова війна, а від Web Archive. Структура war-файлу зазвичай складніша. Найчастіше він складається з двох частин:

  • Java складова
    • скомпільовані класи
    • ресурси для java-класів: properties-файли тощо
    • інші jar-бібліотеки (часто)
    • маніфест MANIFEST.MF
  • Web складова
    • web-xml – дескриптор розгортання вебсервісу
    • jsp-сервелети
    • статичні веб-ресурси: HTML, CSS, JS-файли

Приклад типового war-файлу:

META-INF/
    MANIFEST.MF
WEB-INF/
    web.xml
    jsp/
    	helloWorld.jsp
    classes/
    	static/
    	templates/
    	application.properties
    lib/
    	// *.jar files as libs

Важливо! jar-файл може запустити просто java-машину, а для запуску war-файлу його потрібно завантажити на вебсервер. Самостійно він не запускається.

Плагін створення war-файлу за допомогою maven-war-plugin

Уявімо, що у нас є простий вебпроєкт. Нехай проєкт визначається такою структурою файлів. Як його зібрати?

|-- pom.xml
 `-- src
 	`-- main
     	|-- java
     	|   `-- com
     	|   	`-- example
     	|       	`-- projects
     	|           	`-- SampleAction.java
     	|-- resources
     	|   `-- images
     	|   	`-- sampleimage.jpg
     	`-- webapp
         	|-- WEB-INF
         	|   `-- web.xml
         	|-- index.jsp
         	`-- jsp
             	`-- websource.jsp

По-перше, нам потрібно вказати Maven, зібрати все це у вигляді war-файлу. Для цього є тег <package>, ось приклад:

	<project>
  	...
      <groupId>com.example.projects</groupId>
      <artifactId>simple-war</artifactId>
  	<packaging>war</packaging>
      <version>1.0-SNAPSHOT</version>
  	<name>Simple War Project</name>
      <url>http://javarush.com</url>
  	...
    </project>

По-друге, нам потрібно підключити плагін maven-war-plugin. Приклад:

  <build>
	<plugins>
  	<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
    	<version>3.3.2</version>
    	<configuration>
          <webappDirectory>/sample/servlet/container/deploy/directory</webappDirectory>
    	</configuration>
      </plugin>
    </plugins>
  </build>

Тут ми просто вказуємо плагін, який у майбутньому можна конфігурувати. Також за допомогою тега webappDirectory перевизначаємо директорію, до якої буде розгорнено проєкт. Давай розглянемо детальніше, про що йдеться.

Плагіну можна встановити два режими складання (два види goal):

  • war:war
  • war:exploded

У першому випадку підсумковий war-файл просто кладеться до папки target і має ім'я <artifactId>-<version>.war.

Але можна "попросити" плагін, щоб у підсумкову папку вміст war-файлу було розміщено в тому стані, в якому він буде розпакований вебсервером у себе всередині. Для цього використовується goal war:exploded.

Другий підхід використовується часто, якщо ти запускаєш або дебажиш проєкт прямо з Intellij IDEA.

До речі, тег webappDirectory у прикладі вище дозволяє перевизначити директорію, куди буде розпаковано твій war-файл при складанні в режимі war:exploded.

Про інші налаштування плагіна можна дізнатися з його офіційної сторінки.

Складання вебзастосунків на основі SpringBoot

Давай розберемо якийсь реальний приклад складання проєкту. Подивимося на програму на основі SpringBoot.

Крок перший. Створи порожній Maven web-проект за допомогою IDEA.

Крок другий. Додай до його pom.xml залежно від Spring.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>

Крок третій. Створи клас com.javarush.spring.MainController. Його потрібно розмістити в папці src/main/java:


@Controller
public class MainController {

	@GetMapping("/")
    public String viewIndexPage(Model model) {
        model.addAttribute("header", "Maven Generate War");
    	return "index";
	}
}

Тут описано 3 речі. По-перше, анотація @Controller показує фреймворку SpringBoot, що цей клас буде використовуватися для обслуговування вхідних веб-запитів.

По-друге, анотація @GetMapping вказує, що наш метод буде викликатися для обслуговування GET-запиту на кореневий URI - /

По-третє, метод повертає рядок "index". Це говорить фреймворку SpringBoot, що як відповідь потрібно віддати вміст файлу index.html.

Крок четвертий. Потрібно додати до проєкту файл index.html з таким вмістом:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Index</title>
    <!-- Bootstrap core CSS -->
    <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-light bg-light">
    	<div class="container-fluid">
        	<a class="navbar-brand" href="#">
            	JavaRush Tutorial
        	</a>
    	</div>
    </nav>
    <div class="container">
    	<h1>[[${header}]]</h1>
    </div>
</body>
</html>

Це не просто HTML. Перед тим, як його вміст віддадуть клієнту, його буде модифіковано на сервері фреймворком Thymeleaf. У цей файл вбудовані спеціальні теги, які дозволяють бібліотеці Thymeleaf обробляти та модифікувати вміст сторінки.

Червоним відображені теги, які будуть оброблені бібліотекою Thymeleaf, зеленим – стилі CSS-бібліотеки Bootstrap.

Крок п'ятий. Вказуємо плагін у pom.xml:

<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>3.3.1</version>
</plugin>

Трохи переоцінив власні сили. Щоб повністю розібрати простий приклад, потрібно багато часу. Але ти можеш завантажити повний код проєкту з GitHub та спробувати розібратися у ньому самостійно. До речі, відсотків 80% свого робочого часу ти робитимеш саме це :)

Повний код ти можеш завантажити за цим посиланням у GitHub.