删除minio自定义实现模块,根据模块规划调整模块名称。

This commit is contained in:
刘小平 2024-07-31 11:14:57 +08:00
parent c09c9c3fa8
commit 4de6b0679d
25 changed files with 31 additions and 554 deletions

View File

@ -12,6 +12,12 @@
<artifactId>minio-plus-core</artifactId> <artifactId>minio-plus-core</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -27,7 +33,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
<artifactId>minio-s3-api-definition</artifactId> <artifactId>s3-api-definition</artifactId>
</dependency> </dependency>
<!-- google图片压缩 --> <!-- google图片压缩 -->
<dependency> <dependency>

View File

@ -13,9 +13,8 @@
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>minio-s3-api-definition</module> <module>s3-api-definition</module>
<module>minio-s3-api-custom</module> <module>s3-api-minio</module>
<module>minio-s3-api-official</module>
</modules> </modules>
</project> </project>

View File

@ -9,7 +9,7 @@
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>minio-s3-api-definition</artifactId> <artifactId>s3-api-definition</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>

View File

@ -9,7 +9,7 @@
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>minio-s3-api-official</artifactId> <artifactId>s3-api-minio</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
@ -31,7 +31,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
<artifactId>minio-s3-api-definition</artifactId> <artifactId>s3-api-definition</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>

View File

@ -12,6 +12,12 @@
<artifactId>minio-plus-all-spring-boot-starter</artifactId> <artifactId>minio-plus-all-spring-boot-starter</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
@ -19,7 +25,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
<artifactId>minio-s3-api-official</artifactId> <artifactId>s3-api-minio</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -12,6 +12,12 @@
<artifactId>minio-plus-core-spring-boot-starter</artifactId> <artifactId>minio-plus-core-spring-boot-starter</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
@ -19,7 +25,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
<artifactId>minio-s3-api-official</artifactId> <artifactId>s3-api-minio</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>minio-s3-api</artifactId>
<groupId>me.liuxp</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>minio-s3-api-custom</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>me.liuxp</groupId>
<artifactId>minio-s3-api-definition</artifactId>
</dependency>
<dependency>
<groupId>me.liuxp</groupId>
<artifactId>minio-plus-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,88 +0,0 @@
package org.liuxp.minioplus.s3.custom;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.liuxp.minioplus.common.config.MinioPlusProperties;
import org.liuxp.minioplus.s3.def.ListParts;
import org.liuxp.minioplus.s3.def.MinioS3Client;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.io.InputStream;
import java.time.ZonedDateTime;
import java.util.List;
@Slf4j
@Repository
public class MinioS3ClientImpl implements MinioS3Client {
@Resource
private MinioPlusProperties properties;
@Override
public Boolean bucketExists(String bucketName) {
// 取得当前时间
ZonedDateTime date = ZonedDateTime.now();
// HTTP请求
HttpResponse httpResponse = S3Request.request(properties.getKey(),properties.getSecret(),properties.getBackend()
,properties.getBackend()+"/"+bucketName,"","/"+bucketName, Method.HEAD.name(),date,0);
return httpResponse.isOk();
}
@Override
public void makeBucket(String bucketName) {
}
@Override
public String createMultipartUpload(String bucketName, String objectName) {
return null;
}
@Override
public Boolean completeMultipartUpload(String bucketName, String objectName, String uploadId, List<ListParts.Part> parts) {
return null;
}
@Override
public ListParts listParts(String bucketName, String objectName, Integer maxParts, String uploadId) {
// 获取失败时拼一个空的返回值
return null;
}
@Override
public String getUploadObjectUrl(String bucketName, String objectName, String uploadId, String partNumber) {
return null;
}
@Override
public String getDownloadUrl(String fileName, String contentType, String bucketName, String objectName) {
return null;
}
@Override
public String getPreviewUrl(String contentType, String bucketName, String objectName) {
return null;
}
@Override
public Boolean putObject(String bucketName, String objectName, InputStream stream, long size, String contentType) {
return null;
}
@Override
public byte[] getObject(String bucketName, String objectName) {
return new byte[0];
}
@Override
public void removeObject(String bucketName, String objectName) {
}
}

View File

@ -1,39 +0,0 @@
package org.liuxp.minioplus.s3.custom;
/**
* S3 API 接口定义
* @author contact@liuxp.me
* @since 2024/06/07
*/
public enum S3APIEnums {
BUCKET_EXISTS("检查桶是否存在", "http://localhost:9000/document","/document","HEAD");
private final String name;
private final String url;
private final String path;
private final String method;
S3APIEnums(String name,String url,String path,String method) {
this.name = name;
this.url = url;
this.path = path;
this.method = method;
}
public String getName() {
return name;
}
public String getUrl() {
return url;
}
public String getPath() {
return path;
}
public String getMethod() {
return method;
}
}

View File

@ -1,52 +0,0 @@
package org.liuxp.minioplus.s3.custom;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class S3Request {
static String ZERO_MD5_HASH = "1B2M2Y8AsgTpgAmY7PhCfg==";
static String ZERO_SHA256_HASH = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
public static HttpResponse request(String accessKey,String secretKey,String backend,String url, Object body, String path, String method, ZonedDateTime date,int length){
String md5Hash = ZERO_MD5_HASH;
if (body instanceof byte[]) {
md5Hash = S3Signer.md5Hash((byte[]) body, length);
}
// 创建除Authorization外所有header
Map<String, List<String>> headers = new HashMap<>();
headers.put("Host", CollUtil.newArrayList(backend.replace("http://","").replace("https://","")));
headers.put("Accept-Encoding", CollUtil.newArrayList("identity"));
headers.put("User-Agent", CollUtil.newArrayList("MinIO (Windows 10; amd64) minio-java/8.3.3"));
headers.put("Content-MD5", CollUtil.newArrayList(md5Hash));
headers.put("x-amz-content-sha256", CollUtil.newArrayList(ZERO_SHA256_HASH));
headers.put("x-amz-date", CollUtil.newArrayList(date.format(Time.AMZ_DATE_FORMAT)));
// 计算authorization
String authorization = S3Signer.build(accessKey,secretKey,date,headers,"",method,path,ZERO_SHA256_HASH);
HttpRequest httpRequest = HttpUtil.createRequest(Method.HEAD, url);
httpRequest.header(headers,true);
httpRequest.header("Authorization", authorization);
return httpRequest.execute();
}
}

View File

@ -1,228 +0,0 @@
package org.liuxp.minioplus.s3.custom;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.HexUtil;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
public class S3Signer {
private static final String serviceName = "s3";
private static final String US_EAST_1 = "us-east-1";
private static final Set<String> IGNORED_HEADERS = CollUtil.set(true,"accept-encoding", "authorization", "content-type", "content-length", "user-agent");
public static String build(String accessKey,String secretKey,ZonedDateTime date,Map<String, List<String>> headers,String params,String method,String path,String zeroSha256Hash){
try {
// 计算scope
String scope = buildScope(date);
// 计算signedHeaders
Map<String, String> canonicalHeaders = buildCanonicalHeaders(headers);
// 计算signedHeaders
String signedHeaders = buildSignedHeaders(canonicalHeaders);
// 计算canonicalQueryString
String canonicalQueryString = buildCanonicalQueryString(params);
// 计算buildCanonicalRequest
String canonicalRequestHash = buildCanonicalRequest(canonicalHeaders,signedHeaders,canonicalQueryString,method,path,zeroSha256Hash);
// 计算stringToSign
String stringToSign = buildStringToSign(date,scope,canonicalRequestHash);
// 计算signingKey
byte[] signingKey = buildSigningKey(date,secretKey);
// 计算signature
String signature = buildSignature(signingKey,stringToSign);
// 计算authorization
String authorization = buildAuthorization(accessKey,scope,signedHeaders,signature);
log.debug("httpRequest.headers()="+headers);
log.debug("scope="+scope);
log.debug("canonicalHeaders="+canonicalHeaders);
log.debug("signedHeaders="+signedHeaders);
log.debug("canonicalQueryString="+canonicalQueryString);
log.debug("canonicalRequestHash="+canonicalRequestHash);
log.debug("stringToSign="+stringToSign);
log.debug("signature="+signature);
log.debug("authorization="+authorization);
return authorization;
}catch (Exception e){
throw new RuntimeException("S3签名失败", e);
}
}
// 计算scope
private static String buildScope(ZonedDateTime date){
return date.format(Time.SIGNER_DATE_FORMAT) + "/" + US_EAST_1 + "/" + serviceName + "/aws4_request";
}
private static Map<String, String> buildCanonicalHeaders(Map<String, List<String>> headers){
Map<String, String> canonicalHeaders = new TreeMap<>();
for (String name : headers.keySet()) {
String signedHeader = name.toLowerCase(Locale.US);
if (!IGNORED_HEADERS.contains(signedHeader)) {
// Convert and add header values as per
// https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
// * Header having multiple values should be converted to comma separated values.
// * Multi-spaced value of header should be trimmed to single spaced value.
canonicalHeaders.put(
signedHeader,
headers.get(name).stream()
.map(
value -> {
return value.replaceAll("( +)", " ");
})
.collect(Collectors.joining(",")));
}
}
return canonicalHeaders;
}
/**
* 计算signedHeaders
* @return
*/
private static String buildSignedHeaders(Map<String, String> canonicalHeaders) {
return CharSequenceUtil.join(";", canonicalHeaders.keySet());
}
private static String buildCanonicalQueryString(String params){
if(CharSequenceUtil.isBlank(params)){
return "";
}
return params;
//TODO
// MapUtil
// Building a multimap which only order keys, ordering values is not performed
// until MinIO server supports it.
// Multimap<String, String> signedQueryParams =
// MultimapBuilder.treeKeys().arrayListValues().build();
//
// for (String queryParam : params.split("&")) {
// String[] tokens = queryParam.split("=");
// if (tokens.length > 1) {
// signedQueryParams.put(tokens[0], tokens[1]);
// } else {
// signedQueryParams.put(tokens[0], "");
// }
// }
//
// return Joiner.on("&").withKeyValueSeparator("=").join(signedQueryParams.entries());
}
private static String buildCanonicalRequest(Map<String, String> canonicalHeaders,String signedHeaders
,String canonicalQueryString,String method,String path,String zeroSha256Hash) throws NoSuchAlgorithmException {
StringBuilder headers = new StringBuilder();
for (String key : canonicalHeaders.keySet()) {
headers.append(key);
headers.append(":");
headers.append(canonicalHeaders.get(key));
headers.append("\n");
}
String canonicalRequest = method + "\n" + path + "\n" + canonicalQueryString + "\n"
+ headers + "\n" + signedHeaders + "\n" + zeroSha256Hash;
log.debug("canonicalRequest="+canonicalRequest);
byte[] data = canonicalRequest.getBytes(StandardCharsets.UTF_8);
MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");
sha256Digest.update(data, 0, data.length);
return HexUtil.encodeHexStr(sha256Digest.digest());
}
/**
* 计算stringToSign
* @param date
* @param scope
* @param canonicalRequestHash
* @return
*/
private static String buildStringToSign(ZonedDateTime date,String scope,String canonicalRequestHash){
return "AWS4-HMAC-SHA256" + "\n" + date.format(Time.AMZ_DATE_FORMAT) + "\n" + scope + "\n" + canonicalRequestHash;
}
/**
* 计算signingKey
* @param date
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
private static byte[] buildSigningKey(ZonedDateTime date,String secretKey) throws NoSuchAlgorithmException, InvalidKeyException {
String aws4SecretKey = "AWS4" + secretKey;
byte[] dateKey = sumHmac(aws4SecretKey.getBytes(StandardCharsets.UTF_8), date.format(Time.SIGNER_DATE_FORMAT).getBytes(StandardCharsets.UTF_8));
byte[] dateRegionKey = sumHmac(dateKey, US_EAST_1.getBytes(StandardCharsets.UTF_8));
byte[] dateRegionServiceKey = sumHmac(dateRegionKey, serviceName.getBytes(StandardCharsets.UTF_8));
return sumHmac(dateRegionServiceKey, "aws4_request".getBytes(StandardCharsets.UTF_8));
}
/**
* 计算signature
* @param signingKey
* @param stringToSign
* @return
*/
private static String buildSignature(byte[] signingKey,String stringToSign) throws NoSuchAlgorithmException, InvalidKeyException {
byte[] digest = sumHmac(signingKey, stringToSign.getBytes(StandardCharsets.UTF_8));
return HexUtil.encodeHexStr(digest);
}
/**
* 计算authorization
* @param accessKey
* @param scope
* @param signedHeaders
* @param signature
* @return
*/
private static String buildAuthorization(String accessKey,String scope,String signedHeaders,String signature){
return "AWS4-HMAC-SHA256 Credential=" + accessKey + "/" + scope + ", SignedHeaders=" + signedHeaders + ", Signature=" + signature;
}
private static byte[] sumHmac(byte[] key, byte[] data) throws NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
mac.update(data);
return mac.doFinal();
}
public static String md5Hash(byte[] data, int length) {
try {
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
md5Digest.update(data, 0, length);
return Base64.getEncoder().encodeToString(md5Digest.digest());
}catch (Exception e){
throw new RuntimeException("md5Hash失败", e);
}
}
}

View File

@ -1,44 +0,0 @@
package org.liuxp.minioplus.s3.custom;/*
* MinIO Java SDK for Amazon S3 Compatible Cloud Storage,
* (C) 2020 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
/** Time formatters for S3 APIs. */
public class Time {
public static final ZoneId UTC = ZoneId.of("Z");
public static final DateTimeFormatter AMZ_DATE_FORMAT =
DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'", Locale.US).withZone(UTC);
public static final DateTimeFormatter RESPONSE_DATE_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH':'mm':'ss'.'SSS'Z'", Locale.US).withZone(UTC);
// Formatted string is convertible to LocalDate only, not to LocalDateTime or ZonedDateTime.
// Below example shows how to use this to get ZonedDateTime.
// LocalDate.parse("20200225", SIGNER_DATE_FORMAT).atStartOfDay(UTC);
public static final DateTimeFormatter SIGNER_DATE_FORMAT =
DateTimeFormatter.ofPattern("yyyyMMdd", Locale.US).withZone(UTC);
public static final DateTimeFormatter HTTP_HEADER_DATE_FORMAT =
DateTimeFormatter.ofPattern("EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'", Locale.US).withZone(UTC);
public static final DateTimeFormatter EXPIRATION_DATE_FORMAT = RESPONSE_DATE_FORMAT;
private Time() {}
}

View File

@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.liuxp.minioplus.s3.custom.MinioS3ClientImpl

View File

@ -1,54 +0,0 @@
import cn.hutool.http.HttpResponse;
import org.liuxp.minioplus.s3.custom.S3Request;
import java.time.ZonedDateTime;
public class S3RequestTest {
// public static void main(String[] args){
//
// String accessKey = "minioadmin";
// String secretKey = "minioadmin";
// String backend = "http://localhost:9000";
// String bucket = "document";
//// String url = "http://localhost:9000/document1";
//
//// ZonedDateTime date = ZonedDateTime.parse("2024-05-31T16:31:54Z");
// // 取得当前时间
// ZonedDateTime date = ZonedDateTime.now();
//
// HttpResponse httpResponse = S3Request.request(accessKey,secretKey,backend,backend+"/"+bucket,"","/"+bucket,"HEAD",date);
//
// System.out.println("httpResponse.isOk()="+httpResponse.isOk());
// System.out.println("httpResponse.getStatus()="+httpResponse.getStatus());
// System.out.println("httpResponse.headers()="+httpResponse.headers());
// System.out.println("httpResponse.body()="+httpResponse.body());
//
// }
public static void main(String[] args){
String accessKey = "minioadmin";
String secretKey = "minioadmin";
String backend = "http://localhost:9000";
String bucket = "document223";
// String url = "http://localhost:9000/document1";
// ZonedDateTime date = ZonedDateTime.parse("2024-05-31T16:31:54Z");
// 取得当前时间
ZonedDateTime date = ZonedDateTime.now();
byte[] EMPTY_BODY = new byte[] {};
HttpResponse httpResponse = S3Request.request(accessKey,secretKey,backend,backend+"/"+bucket,EMPTY_BODY,"/"+bucket,"PUT",date,0);
System.out.println("httpResponse.isOk()="+httpResponse.isOk());
System.out.println("httpResponse.getStatus()="+httpResponse.getStatus());
System.out.println("httpResponse.headers()="+httpResponse.headers());
System.out.println("httpResponse.body()="+httpResponse.body());
}
}

13
pom.xml
View File

@ -40,8 +40,8 @@
<module>minio-plus-common</module> <module>minio-plus-common</module>
<module>minio-plus-core</module> <module>minio-plus-core</module>
<module>minio-plus-extension</module> <module>minio-plus-extension</module>
<module>minio-plus-s3-api</module>
<module>minio-plus-spring-boot-starter</module> <module>minio-plus-spring-boot-starter</module>
<module>minio-s3-api</module>
</modules> </modules>
<properties> <properties>
@ -49,7 +49,7 @@
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<maven-source-plugin.version>3.0.1</maven-source-plugin.version> <maven-source-plugin.version>3.0.1</maven-source-plugin.version>
<revision>0.1.4</revision> <revision>0.1.5</revision>
<spring-boot.version>2.7.18</spring-boot.version> <spring-boot.version>2.7.18</spring-boot.version>
<mybatisplus.version>3.5.7</mybatisplus.version> <mybatisplus.version>3.5.7</mybatisplus.version>
<lombok.version>1.18.32</lombok.version> <lombok.version>1.18.32</lombok.version>
@ -154,7 +154,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
<artifactId>minio-s3-api-definition</artifactId> <artifactId>s3-api-definition</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency> <dependency>
@ -164,7 +164,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
<artifactId>minio-s3-api-official</artifactId> <artifactId>s3-api-minio</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -305,10 +305,7 @@
<artifactId>dependency-check-maven</artifactId> <artifactId>dependency-check-maven</artifactId>
<version>10.0.3</version> <version>10.0.3</version>
<configuration> <configuration>
<skipRuntimeScope>true</skipRuntimeScope> <skip>true</skip>
<skipProvidedScope>true</skipProvidedScope>
<skipSystemScope>true</skipSystemScope>
<skipTestScope>true</skipTestScope>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>