В этом уроке мы покажем вам, как использовать Maven для управления многомодульным проектом, содержащим четыре модуля:
- Модуль паролей – только интерфейс.
- Модуль пароля md5 – Реализация модуля пароля, хэширование пароля MD5.
- Модуль sha паролей – Реализация модуля паролей, хэширование паролей SHA.
- Веб–модуль – Простое веб-приложение MVC для хэширования входных данных с помощью алгоритма MD5 или SHA.
Зависимость от модуля.
$ password $ password <-- password-md5 $ password <-- password-sha $ web <-- (password-md5 | password-sha) <-- password
Некоторые команды для построения многомодульного проекта, например:
$ mvn -pl password compile # compile password module only $ mvn -pl password-sha compile # compile password-sha module, also dependency - password $ mvn -pl web compile # compile web module only $ mvn -am -pl web compile # compile web module, also dependency - password-sha or password-md5, password $ mvn -pl web jetty:run # run web module with Jetty $ mvn compile # compile everything
Используемые технологии:
- Мавен 3.5.3
- JDK 8
- Весна 5.1.0.ВЫПУСК
- thymeleaf 3.0.10.ВЫПУСК
1. Структура каталогов
В макете многомодульного проекта родительский проект содержит родительский pom.xml
и каждый подмодуль (подпроект) также содержит собственный и каждый подмодуль (подпроект) также содержит собственный
2. Мавен ПОМ
Давайте рассмотрим многомодульные POM-файлы Maven.
2.1 Родительский файл POM, упаковка – pom
.
4.0.0 com.mkyong.multi java-multi-modules pom 1.0 web password password-sha password-md5
2.2 В модуле пароля.
java-multi-modules com.mkyong.multi 1.0 4.0.0 com.mkyong.password password 1.0 jar
2.3 В модуле пароль-md5.
java-multi-modules com.mkyong.multi 1.0 4.0.0 com.mkyong.password password-md5 1.0 jar com.mkyong.password password 1.0
2.4 В модуле password-sha.
java-multi-modules com.mkyong.multi 1.0 4.0.0 com.mkyong.password password-sha 1.0 jar com.mkyong.password password 1.0
2.4 В веб-модуле.
com.mkyong.multi java-multi-modules 1.0 4.0.0 com.mkyong web 1.0 war com.mkyong.password password-sha 1.0
3. Родительский проект
3.1 Родительский pom, эти свойства и зависимости (JDK 8, блок 5, Весна 5) являются общими для всех подмодулей.
4.0.0 com.mkyong.multi java-multi-modules pom 1.0 UTF-8 1.8 1.8 5.3.1 5.1.0.RELEASE web password password-sha password-md5 org.springframework spring-context ${spring.version} org.junit.jupiter junit-jupiter-engine ${junit.version} test org.junit.jupiter junit-jupiter-params ${junit.version} test org.apache.maven.plugins maven-surefire-plugin 2.22.0 org.apache.maven.plugins maven-dependency-plugin 3.1.1
4. Модуль Паролей
4.1 Модуль, содержащий только один интерфейс.
4.2 Файл POM.
java-multi-modules com.mkyong.multi 1.0 4.0.0 com.mkyong.password password 1.0 jar
4.3 Интерфейс.
package com.mkyong.password; public interface PasswordService { String hash(String input); String algorithm(); }
5. Пароль-Модуль md5
5.1 Реализация модуля паролей.
5.2 Файл POM.
java-multi-modules com.mkyong.multi 1.0 4.0.0 com.mkyong.password password-md5 1.0 jar com.mkyong.password password 1.0
5.3 Хеширование MD5.
package com.mkyong.password; import org.springframework.stereotype.Service; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @Service public class PasswordServiceImpl implements PasswordService { @Override public String hash(String input) { return md5(input); } @Override public String algorithm() { return "md5"; } private String md5(String input) { StringBuilder result = new StringBuilder(); MessageDigest md; try { md = MessageDigest.getInstance("MD5"); byte[] hashInBytes = md.digest(input.getBytes(StandardCharsets.UTF_8)); for (byte b : hashInBytes) { result.append(String.format("%02x", b)); } } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException(e); } return result.toString(); } }
5.4 Модульный тест.
package com.mkyong.password; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import static org.junit.jupiter.api.Assertions.assertEquals; public class TestPasswordService { PasswordService passwordService; @BeforeEach void init() { passwordService = new PasswordServiceImpl(); } @DisplayName("md5 -> hex") @ParameterizedTest @CsvSource({ "123456, e10adc3949ba59abbe56e057f20f883e", "hello world, 5eb63bbbe01eeed093cb22bb8f5acdc3" }) void testMd5hex(String input, String expected) { assertEquals(expected, passwordService.hash(input)); } }
6. Модуль ввода пароля-sha
6.1 Реализация модуля паролей.
6.2 Файл POM.
java-multi-modules com.mkyong.multi 1.0 4.0.0 com.mkyong.password password-sha 1.0 jar 1.11 commons-codec commons-codec ${commos.codec.version} com.mkyong.password password 1.0
6.3 Хеширование SHA с помощью общей библиотеки кодеков Apache
package com.mkyong.password; import org.apache.commons.codec.digest.DigestUtils; import org.springframework.stereotype.Service; @Service public class PasswordServiceImpl implements PasswordService { @Override public String hash(String input) { return DigestUtils.sha256Hex(input); } @Override public String algorithm() { return "sha256"; } }
6.4 Модульный тест.
package com.mkyong.password; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import static org.junit.jupiter.api.Assertions.assertEquals; public class TestPasswordService { PasswordService passwordService; @BeforeEach void init() { passwordService = new PasswordServiceImpl(); } @DisplayName("sha256 -> hex") @ParameterizedTest @CsvSource({ "123456, 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92", "hello world, b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" }) void testSha256hex(String input, String expected) { assertEquals(expected, passwordService.hash(input)); } }
7. Веб-Модуль
7.1 Веб-приложение Spring MCV + thymeleaf, хэширует входные данные с помощью алгоритма md5 или sha.
7.2 Файл POM.
com.mkyong.multi java-multi-modules 1.0 4.0.0 com.mkyong web 1.0 war 3.0.10.RELEASE com.mkyong.password password-sha 1.0 org.springframework spring-webmvc ${spring.version} org.springframework spring-test ${spring.version} ch.qos.logback logback-classic 1.2.3 org.hamcrest hamcrest-library 1.3 test javax.servlet javax.servlet-api 3.1.0 provided org.thymeleaf thymeleaf ${thymeleaf.version} org.thymeleaf thymeleaf-spring5 ${thymeleaf.version} java-web-project org.eclipse.jetty jetty-maven-plugin 9.4.12.v20180830 org.apache.maven.plugins maven-war-plugin 3.2.2
7.3 Зависимость от веб-модуля
$ mvn -pl web dependency:tree [INFO] com.mkyong:web:war:1.0 [INFO] +- com.mkyong.password:password-sha:jar:1.0:compile [INFO] | +- commons-codec:commons-codec:jar:1.11:compile [INFO] | \- com.mkyong.password:password:jar:1.0:compile [INFO] +- org.springframework:spring-webmvc:jar:5.1.0.RELEASE:compile [INFO] | +- org.springframework:spring-aop:jar:5.1.0.RELEASE:compile [INFO] | +- org.springframework:spring-beans:jar:5.1.0.RELEASE:compile [INFO] | +- org.springframework:spring-core:jar:5.1.0.RELEASE:compile [INFO] | | \- org.springframework:spring-jcl:jar:5.1.0.RELEASE:compile [INFO] | +- org.springframework:spring-expression:jar:5.1.0.RELEASE:compile [INFO] | \- org.springframework:spring-web:jar:5.1.0.RELEASE:compile [INFO] +- org.springframework:spring-test:jar:5.1.0.RELEASE:compile [INFO] +- ch.qos.logback:logback-classic:jar:1.2.3:compile [INFO] | +- ch.qos.logback:logback-core:jar:1.2.3:compile [INFO] | \- org.slf4j:slf4j-api:jar:1.7.25:compile [INFO] +- org.hamcrest:hamcrest-library:jar:1.3:test [INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test [INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided [INFO] +- org.thymeleaf:thymeleaf:jar:3.0.10.RELEASE:compile [INFO] | +- ognl:ognl:jar:3.1.12:compile [INFO] | | \- org.javassist:javassist:jar:3.20.0-GA:compile [INFO] | +- org.attoparser:attoparser:jar:2.0.5.RELEASE:compile [INFO] | \- org.unbescape:unbescape:jar:1.1.6.RELEASE:compile [INFO] +- org.thymeleaf:thymeleaf-spring5:jar:3.0.10.RELEASE:compile [INFO] +- org.springframework:spring-context:jar:5.1.0.RELEASE:compile [INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.3.1:test [INFO] | +- org.apiguardian:apiguardian-api:jar:1.0.0:test [INFO] | +- org.junit.platform:junit-platform-engine:jar:1.3.1:test [INFO] | | +- org.junit.platform:junit-platform-commons:jar:1.3.1:test [INFO] | | \- org.opentest4j:opentest4j:jar:1.1.1:test [INFO] | \- org.junit.jupiter:junit-jupiter-api:jar:5.3.1:test [INFO] \- org.junit.jupiter:junit-jupiter-params:jar:5.3.1:test [INFO] ------------------------------------------------------------------------
7.4 Пружинный материал, интегрируйте thymeleaf и конфигурацию.
package com.mkyong.web.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.thymeleaf.spring5.SpringTemplateEngine; import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; import org.thymeleaf.spring5.view.ThymeleafViewResolver; import org.thymeleaf.templatemode.TemplateMode; @EnableWebMvc @Configuration @ComponentScan({"com.mkyong"}) public class SpringConfig implements WebMvcConfigurer { @Autowired private ApplicationContext applicationContext; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**") .addResourceLocations("/resources/"); } @Bean public SpringResourceTemplateResolver templateResolver() { SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(this.applicationContext); templateResolver.setPrefix("/WEB-INF/views/"); templateResolver.setSuffix(".html"); templateResolver.setTemplateMode(TemplateMode.HTML); templateResolver.setCacheable(true); return templateResolver; } @Bean public SpringTemplateEngine templateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); templateEngine.setEnableSpringELCompiler(true); return templateEngine; } @Bean public ThymeleafViewResolver viewResolver() { ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine()); return viewResolver; } }
package com.mkyong.web; import com.mkyong.web.config.SpringConfig; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class>[] getRootConfigClasses() { return null; } @Override protected Class>[] getServletConfigClasses() { return new Class[]{SpringConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
package com.mkyong.web.controller; import com.mkyong.password.PasswordService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class WelcomeController { private final Logger logger = LoggerFactory.getLogger(WelcomeController.class); @Autowired private PasswordService passwordService; @GetMapping("/") public String welcome(@RequestParam(name = "query", required = false, defaultValue = "123456") String query, Model model) { logger.debug("Welcome to mkyong.com... Query : {}", query); model.addAttribute("query", query); model.addAttribute("hash", passwordService.hash(query)); model.addAttribute("algorithm", passwordService.algorithm()); return "index"; } }
7.5 Модульный тест для Spring MVC.
package com.mkyong.web; import com.mkyong.web.config.SpringConfig; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @SpringJUnitWebConfig(SpringConfig.class) @DisplayName("Test Spring MVC default view") public class TestWelcome { private MockMvc mockMvc; @Autowired private WebApplicationContext webAppContext; @BeforeEach public void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext).build(); } @Test public void testDefault() throws Exception { this.mockMvc.perform( get("/")) .andExpect(status().isOk()) .andExpect(view().name("index")) .andExpect(model().attribute("query", "123456")); //.andExpect(model().attribute("sha256", "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92")) //.andExpect(model().attribute("md5", "e10adc3949ba59abbe56e057f20f883e")); } }
7.6 Вид на лист Тимьяна.
Сделано.
8. Демонстрация
8.1 В родительском проекте используется стандартная компиляция mvn
для компиляции всех модулей, Maven определит порядок сборки.
$ mvn compile [INFO] Reactor Summary: [INFO] [INFO] java-multi-modules 1.0 ............................. SUCCESS [ 0.007 s] [INFO] password ........................................... SUCCESS [ 0.539 s] [INFO] password-sha ....................................... SUCCESS [ 0.038 s] [INFO] web ................................................ SUCCESS [ 0.080 s] [INFO] password-md5 1.0 ................................... SUCCESS [ 0.035 s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.822 s [INFO] Finished at: 2018-10-23T15:32:21+08:00 [INFO] ------------------------------------------------------------------------
8.2 Установите все модули в локальное хранилище.
$ mvn install
8.3 Компилирует только веб-модуль (Maven найдет зависимость модуля паролей от локального репозитория, поэтому нам нужно установка mvn
$ mvn -pl web compile
8.4 В качестве альтернативы добавьте -am
для компиляции веб-модуля, а также его модулей зависимостей (пароль-sha и пароль).
$ mvn -am -pl web compile [INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------ [INFO] Reactor Build Order: [INFO] [INFO] java-multi-modules [pom] [INFO] password [jar] [INFO] password-sha [jar] [INFO] web [war] ...... [INFO] Reactor Summary: [INFO] [INFO] java-multi-modules 1.0 ............................. SUCCESS [ 0.009 s] [INFO] password ........................................... SUCCESS [ 0.534 s] [INFO] password-sha ....................................... SUCCESS [ 0.036 s] [INFO] web 1.0 ............................................ SUCCESS [ 0.077 s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.780 s [INFO] Finished at: 2018-10-23T15:36:16+08:00 [INFO] ------------------------------------------------------------------------
8.5 Протестируйте веб-модуль с помощью веб-причала mvn-pl: выполните команду
.
$ mvn install $ mvn -pl web jetty:run //... [INFO] 1 Spring WebApplicationInitializers detected on classpath [INFO] DefaultSessionIdManager workerName=node0 [INFO] No SessionScavenger set, using defaults [INFO] node0 Scavenging every 600000ms [INFO] Started ServerConnector@40a8a26f{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} [INFO] Started @6398ms [INFO] Started Jetty Server
8.6 http://localhost:8080
8.7 http://localhost:8080/?query = мкенг
8.8 Обновление алгоритма md5. Перезапустите сервер причала.
com.mkyong.password password-md5 1.0
8.9 http://localhost:8080/?query = мкенг
Скачать Исходный Код
Рекомендации
- Учебное пособие: Лист Тимьяна + Весна
- Обслуживание веб-контента с помощью Spring MVC
- Многомодульный Проект
- Spring IO – Создание многомодульного проекта
- Многомодульные сборки проектов с использованием Maven и Gradle
- Maven – Как создать проект Java
- Maven – Как создать проект веб-приложения Java
Оригинал: “https://mkyong.com/maven/maven-how-to-create-a-multi-module-project/”