xie.bx 3 лет назад
Родитель
Сommit
1449145b52

+ 1 - 1
commom/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>lx-im</artifactId>
         <groupId>com.lx</groupId>
-        <version>${im.version}</version>
+        <version>1.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>commom</artifactId>

+ 39 - 0
commom/src/main/java/com/lx/common/enums/FileTypeEnum.java

@@ -0,0 +1,39 @@
+package com.lx.common.enums;
+
+public enum FileTypeEnum {
+
+    FILE(0,"文件"),
+    IMAGE(1,"图片"),
+    VIDEO(2,"视频");
+
+
+    private Integer code;
+
+    private String desc;
+
+    FileTypeEnum(Integer index, String desc) {
+        this.code =index;
+        this.desc=desc;
+    }
+
+    public static FileTypeEnum fromCode(Integer code){
+        for (FileTypeEnum typeEnum:values()) {
+            if (typeEnum.code.equals(code)) {
+                return typeEnum;
+            }
+        }
+        return null;
+    }
+
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public Integer getCode(){
+        return this.code;
+    }
+
+
+}
+

+ 34 - 2
im-platform/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>lx-im</artifactId>
         <groupId>com.lx</groupId>
-        <version>${im.version}</version>
+        <version>1.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -16,7 +16,7 @@
         <dependency>
             <groupId>com.lx</groupId>
             <artifactId>commom</artifactId>
-            <version>${im.version}</version>
+            <version>1.0.0</version>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -66,6 +66,38 @@
             <groupId>org.springframework.session</groupId>
             <artifactId>spring-session-data-redis</artifactId>
         </dependency>
+        <!--minio-->
+        <dependency>
+            <groupId>io.minio</groupId>
+            <artifactId>minio</artifactId>
+            <version>8.4.3</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.squareup.okhttp3</groupId>
+                    <artifactId>okhttp</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.jetbrains.kotlin</groupId>
+                    <artifactId>kotlin-stdlib</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>4.9.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jetbrains.kotlin</groupId>
+            <artifactId>kotlin-stdlib</artifactId>
+            <version>1.3.70</version>
+        </dependency>
+        <!--thumbnailator图片处理-->
+        <dependency>
+            <groupId>net.coobird</groupId>
+            <artifactId>thumbnailator</artifactId>
+            <version>0.4.8</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 31 - 0
im-platform/src/main/java/com/lx/implatform/config/MinIoClientConfig.java

@@ -0,0 +1,31 @@
+package com.lx.implatform.config;
+
+import io.minio.MinioClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+@Configuration
+public class MinIoClientConfig {
+    @Value("${minio.endpoint}")
+    private String endpoint;
+    @Value("${minio.accessKey}")
+    private String accessKey;
+    @Value("${minio.secretKey}")
+    private String secretKey;
+
+    /**
+     * 注入minio 客户端
+     * @return
+     */
+    @Bean
+    public MinioClient minioClient(){
+
+        MinioClient client =  MinioClient.builder()
+                .endpoint(endpoint)
+                .credentials(accessKey, secretKey)
+                .build();
+        return  client;
+    }
+}

+ 3 - 3
im-platform/src/main/java/com/lx/implatform/config/SwaggerConfig.java

@@ -32,9 +32,9 @@ public class SwaggerConfig {
 
     private ApiInfo apiInfo() {
         return new ApiInfoBuilder()
-                .title("uaa service Doc")
-                .description("用户授权服务Api文档")
-                .termsOfServiceUrl("http://www.baidu.com/")
+                .title("IM Platform doc")
+                .description("蓝星IM API文档")
+                .termsOfServiceUrl("http://XXX/")
                 .version("1.0")
                 .build();
     }

+ 1 - 1
im-platform/src/main/java/com/lx/implatform/config/WebSecurityConfg.java

@@ -55,7 +55,7 @@ public class WebSecurityConfg extends WebSecurityConfigurerAdapter {
     @Override
     protected void configure(HttpSecurity http) throws Exception {
         http.authorizeRequests()
-            .antMatchers("/login","/logout","/register","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**")
+            .antMatchers("/image/upload","/login","/logout","/register","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**")
             .permitAll()
             .anyRequest() //任何其它请求
             .authenticated() //都需要身份认证

+ 42 - 0
im-platform/src/main/java/com/lx/implatform/controller/FileController.java

@@ -0,0 +1,42 @@
+package com.lx.implatform.controller;
+
+import com.lx.common.result.Result;
+import com.lx.common.result.ResultUtils;
+import com.lx.implatform.service.thirdparty.FileService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+/*
+ * 文件上传
+ * @Author Blue
+ * @Date 2022/10/28
+ */
+@Slf4j
+@RestController
+@Api(tags = "文件上传")
+public class FileController {
+
+
+    @Autowired
+    private FileService fileService;
+
+    @ApiOperation(value = "上传图片",notes="上传图片")
+    @PostMapping("/image/upload")
+    public Result upload(MultipartFile file) {
+        return ResultUtils.success(fileService.uploadImage(file));
+    }
+
+
+    @GetMapping("/online")
+    @ApiOperation(value = "查找用户",notes="根据昵称查找用户")
+    public Result checkOnline(){
+
+        return ResultUtils.success("");
+    }
+}

+ 1 - 1
im-platform/src/main/java/com/lx/implatform/controller/FriendsController.java

@@ -17,7 +17,7 @@ import javax.validation.constraints.NotEmpty;
 import java.util.List;
 import java.util.stream.Collectors;
 
-@Api(tags = "好友相关API")
+@Api(tags = "好友")
 @RestController
 @RequestMapping("/friends")
 public class FriendsController {

+ 1 - 1
im-platform/src/main/java/com/lx/implatform/controller/SingleMessageController.java

@@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
 
-@Api(tags = "单发消息相关api")
+@Api(tags = "私聊消息")
 @RestController
 @RequestMapping("/message/single")
 public class SingleMessageController {

+ 6 - 3
im-platform/src/main/java/com/lx/implatform/controller/UserController.java

@@ -18,7 +18,7 @@ import javax.validation.constraints.NotEmpty;
 import java.util.List;
 
 
-@Api(tags = "用户相关API")
+@Api(tags = "用户")
 @RestController
 @RequestMapping("/user")
 public class UserController {
@@ -28,12 +28,14 @@ public class UserController {
 
 
     @GetMapping("/online")
+    @ApiOperation(value = "判断用户是否在线",notes="返回在线的用户id集合")
     public Result checkOnline(@NotEmpty @RequestParam("userIds") String userIds){
         List<Long> onlineIds = userService.checkOnline(userIds);
         return ResultUtils.success(onlineIds);
     }
 
     @GetMapping("/self")
+    @ApiOperation(value = "获取当前用户信息",notes="获取当前用户信息")
     public Result findSelfInfo(){
         UserSession session = SessionContext.getSession();
         User user = userService.getById(session.getId());
@@ -43,6 +45,7 @@ public class UserController {
 
 
     @GetMapping("/find/{id}")
+    @ApiOperation(value = "查找用户",notes="根据id查找用户")
     public Result findByIde(@NotEmpty @PathVariable("id") long id){
         User user = userService.getById(id);
         UserVO userVO = BeanUtils.copyProperties(user,UserVO.class);
@@ -51,8 +54,8 @@ public class UserController {
 
 
     @GetMapping("/findByNickName")
-    @ApiOperation(value = "查找非好友用户",notes="查找非好友用户")
-    public Result findUnfriendsUser(@NotEmpty(message = "用户昵称不可为空") @RequestParam("nickName") String nickName){
+    @ApiOperation(value = "查找用户",notes="根据昵称查找用户")
+    public Result findByNickName(@NotEmpty(message = "用户昵称不可为空") @RequestParam("nickName") String nickName){
            return ResultUtils.success( userService.findUserByNickName(nickName));
     }
 }

+ 83 - 0
im-platform/src/main/java/com/lx/implatform/service/thirdparty/FileService.java

@@ -0,0 +1,83 @@
+package com.lx.implatform.service.thirdparty;
+
+import com.lx.common.enums.FileTypeEnum;
+import com.lx.common.enums.ResultCode;
+import com.lx.implatform.exception.GlobalException;
+import com.lx.implatform.util.ImageUtil;
+import com.lx.implatform.util.MinioUtil;
+import com.lx.implatform.vo.UploadImageVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.PostConstruct;
+import java.io.IOException;
+
+/*
+ * 文件上传服务
+ * @Author Blue
+ * @Date 2022/10/28
+ */
+@Slf4j
+@Service
+public class FileService {
+
+    @Autowired
+    private MinioUtil  minioUtil;
+
+    @Value("${minio.public}")
+    private String  minIOServer;
+    @Value("${minio.bucketName}")
+    private String bucketName;
+
+    @Value("${minio.imagePath}")
+    private String imagePath;
+
+    @Value("${minio.filePath}")
+    private String filePath;
+
+    @PostConstruct
+    public void init(){
+        if(!minioUtil.bucketExists(bucketName)){
+            minioUtil.makeBucket(bucketName);
+        }
+    }
+
+    public UploadImageVO uploadImage(MultipartFile file){
+        try {
+            UploadImageVO vo = new UploadImageVO();
+
+            String fileName = minioUtil.upload(bucketName,imagePath,file);
+            vo.setOriginUrl(generUrl(FileTypeEnum.IMAGE,fileName));
+            // 上传缩略图
+            byte[] imageByte = ImageUtil.compressForScale(file.getBytes(),100);
+            fileName = minioUtil.upload(bucketName,imagePath,file.getOriginalFilename(),imageByte,file.getContentType());
+            vo.setCompressUrl(generUrl(FileTypeEnum.IMAGE,fileName));
+            return vo;
+        } catch (IOException e) {
+            log.error("上传图片失败,{}",e.getMessage(),e);
+            throw new GlobalException(ResultCode.PROGRAM_ERROR,"图片上传失败");
+        }
+    }
+
+
+    public String generUrl(FileTypeEnum fileTypeEnum, String fileName){
+        String url = minIOServer+"/"+bucketName;
+        switch (fileTypeEnum){
+            case FILE:
+                url += "/file/";
+                break;
+            case IMAGE:
+                url += "/image/";
+                break;
+            case VIDEO:
+                url += "/video/";
+                break;
+        }
+        url += fileName;
+        return url;
+    }
+
+}

+ 78 - 0
im-platform/src/main/java/com/lx/implatform/util/ImageUtil.java

@@ -0,0 +1,78 @@
+package com.lx.implatform.util;
+
+
+import lombok.extern.slf4j.Slf4j;
+import net.coobird.thumbnailator.Thumbnails;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+@Slf4j
+public class ImageUtil {
+
+    //以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值
+    private static final Integer ZERO = 0;
+    private static final Integer ONE_ZERO_TWO_FOUR = 1024;
+    private static final Integer NINE_ZERO_ZERO = 900;
+    private static final Integer THREE_TWO_SEVEN_FIVE = 3275;
+    private static final Integer TWO_ZERO_FOUR_SEVEN = 2047;
+    private static final Double ZERO_EIGHT_FIVE = 0.85;
+    private static final Double ZERO_SIX = 0.6;
+    private static final Double ZERO_FOUR_FOUR = 0.44;
+    private static final Double ZERO_FOUR = 0.4;
+
+    /**
+     * 根据指定大小压缩图片
+     *
+     * @param imageBytes  源图片字节数组
+     * @param desFileSize 指定图片大小,单位kb
+     * @return 压缩质量后的图片字节数组
+     */
+    public static byte[] compressForScale(byte[] imageBytes, long desFileSize) {
+        if (imageBytes == null || imageBytes.length <= ZERO || imageBytes.length < desFileSize * ONE_ZERO_TWO_FOUR) {
+            return imageBytes;
+        }
+        long srcSize = imageBytes.length;
+        double accuracy = getAccuracy(srcSize / ONE_ZERO_TWO_FOUR);
+        try {
+            while (imageBytes.length > desFileSize * ONE_ZERO_TWO_FOUR) {
+                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
+                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
+                Thumbnails.of(inputStream)
+                        .scale(accuracy)
+                        .outputQuality(accuracy)
+                        .toOutputStream(outputStream);
+                imageBytes = outputStream.toByteArray();
+            }
+            log.info("图片原大小={}kb | 压缩后大小={}kb",
+                    srcSize / ONE_ZERO_TWO_FOUR, imageBytes.length / ONE_ZERO_TWO_FOUR);
+        } catch (Exception e) {
+            log.error("【图片压缩】msg=图片压缩失败!", e);
+        }
+        return imageBytes;
+    }
+
+    /**
+     * 自动调节精度(经验数值)
+     *
+     * @param size 源图片大小
+     * @return 图片压缩质量比
+     */
+    private static double getAccuracy(long size) {
+        double accuracy;
+        if (size < NINE_ZERO_ZERO) {
+            accuracy = ZERO_EIGHT_FIVE;
+        } else if (size < TWO_ZERO_FOUR_SEVEN) {
+            accuracy = ZERO_SIX;
+        } else if (size < THREE_TWO_SEVEN_FIVE) {
+            accuracy = ZERO_FOUR_FOUR;
+        } else {
+            accuracy = ZERO_FOUR;
+        }
+        return accuracy;
+    }
+
+}
+
+
+

+ 139 - 0
im-platform/src/main/java/com/lx/implatform/util/MinioUtil.java

@@ -0,0 +1,139 @@
+package com.lx.implatform.util;
+
+
+import com.lx.common.util.DateTimeUtils;
+import io.minio.*;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Date;
+
+@Component
+public class MinioUtil {
+
+
+    @Autowired
+    private MinioClient minioClient;
+
+    /**
+     * 查看存储bucket是否存在
+     * @return boolean
+     */
+    public Boolean bucketExists(String bucketName) {
+        Boolean found;
+        try {
+            found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+        return found;
+    }
+
+    /**
+     * 创建存储bucket
+     * @return Boolean
+     */
+    public Boolean makeBucket(String bucketName) {
+        try {
+            minioClient.makeBucket(MakeBucketArgs.builder()
+                    .bucket(bucketName)
+                    .build());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 删除存储bucket
+     * @return Boolean
+     */
+    public Boolean removeBucket(String bucketName) {
+        try {
+            minioClient.removeBucket(RemoveBucketArgs.builder()
+                    .bucket(bucketName)
+                    .build());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * 文件上传
+     * @bucketName bucket名称
+     * @path 路径
+     * @param file 文件
+     * @return Boolean
+     */
+    public String upload(String bucketName,String path,MultipartFile file) {
+        String originalFilename = file.getOriginalFilename();
+        if (StringUtils.isBlank(originalFilename)){
+            throw new RuntimeException();
+        }
+        String fileName = System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf("."));
+        String objectName = DateTimeUtils.getFormatDate(new Date(),DateTimeUtils.PARTDATEFORMAT)+ "/" + fileName;
+        try {
+            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(path+"/" +objectName)
+                    .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
+            //文件名称相同会覆盖
+            minioClient.putObject(objectArgs);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+        return objectName;
+    }
+
+    /**
+     * 文件上传
+     * @param bucketName bucket名称
+     * @param path 路径
+     * @param name 文件名
+     * @param fileByte 文件内容
+     * @param contentType
+     * @return Boolean
+     */
+    public String upload(String bucketName,String path,String name,byte[] fileByte,String contentType) {
+
+        String fileName = System.currentTimeMillis() + name.substring(name.lastIndexOf("."));
+        String objectName = DateTimeUtils.getFormatDate(new Date(),DateTimeUtils.PARTDATEFORMAT)+ "/" + fileName;
+        try {
+            InputStream stream = new ByteArrayInputStream(fileByte);
+            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(path+"/" +objectName)
+                    .stream(stream, fileByte.length, -1).contentType(contentType).build();
+            //文件名称相同会覆盖
+            minioClient.putObject(objectArgs);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+        return objectName;
+    }
+
+
+    /**
+     * 删除
+     * @param bucketName bucket名称
+     * @path path
+     * @param fileName
+     * @return
+     * @throws Exception
+     */
+    public boolean remove(String bucketName,String path,String fileName){
+        try {
+            minioClient.removeObject( RemoveObjectArgs.builder().bucket(bucketName).object(path+fileName).build());
+        }catch (Exception e){
+            return false;
+        }
+        return true;
+    }
+}

+ 16 - 0
im-platform/src/main/java/com/lx/implatform/vo/UploadImageVO.java

@@ -0,0 +1,16 @@
+package com.lx.implatform.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel("图片上传VO")
+public class UploadImageVO {
+
+    @ApiModelProperty(value = "原图")
+    private String originUrl;
+
+    @ApiModelProperty(value = "缩略图")
+    private String compressUrl;
+}

+ 8 - 0
im-platform/src/main/resources/application.yml

@@ -23,6 +23,14 @@ mybatis-plus:
   mapper-locations:
     # *.xml的具体路径
     - classpath*:mapper/*.xml
+minio:
+  endpoint: http://127.0.0.1:9001
+  public: http://127.0.0.1:9001
+  accessKey: admin
+  secretKey: 12345678
+  bucketName: lx-im
+  imagePath: image
+  filePath: file
 
 web-ui:
   login-page: http://localhost:8080

+ 2 - 2
im-server/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>lx-im</artifactId>
         <groupId>com.lx</groupId>
-        <version>${im.version}</version>
+        <version>1.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -16,7 +16,7 @@
         <dependency>
             <groupId>com.lx</groupId>
             <artifactId>commom</artifactId>
-            <version>${im.version}</version>
+            <version>1.0.0</version>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 14 - 13
im-ui/src/components/AddFriends.vue

@@ -1,22 +1,22 @@
 <template>
-	<el-dialog title="添加好友" :visible.sync="dialogVisible" width="500px" :before-close="onClose">
+	<el-dialog title="添加好友" :visible.sync="dialogVisible" width="350px" :before-close="onClose">
 		<el-input width="200px" placeholder="搜索好友" class="input-with-select" v-model="searchText" @keyup.enter.native="onSearch()">
 			<el-button slot="append" icon="el-icon-search" @click="onSearch()"></el-button>
 		</el-input>
-		<el-scrollbar style="height:600px">
-		<div v-for="(userInfo) in users" :key="userInfo.id">
-			<div class="item">
-				<div class="avatar">
-					<head-image :url="userInfo.headImage"></head-image>
+		<el-scrollbar style="height:400px">
+			<div v-for="(userInfo) in users" :key="userInfo.id">
+				<div class="item">
+					<div class="avatar">
+						<head-image :url="userInfo.headImage"></head-image>
+					</div>
+					<div class="add-friend-text">
+						<div>{{userInfo.nickName}}</div>
+						<div :class="userInfo.online ? 'online-status  online':'online-status'">{{ userInfo.online?"[在线]":"[离线]"}}</div>
+					</div>
+					 <el-button type="success" v-show="!isFriend(userInfo.id)" plain @click="onAddFriends(userInfo)">添加</el-button>
+					 <el-button type="info" v-show="isFriend(userInfo.id)" plain disabled>已添加</el-button>
 				</div>
-				<div class="add-friend-text">
-					<div>{{userInfo.nickName}}</div>
-					<div :class="userInfo.online ? 'online-status  online':'online-status'">{{ userInfo.online?"[在线]":"[离线]"}}</div>
-				</div>
-				 <el-button type="success" v-show="!isFriend(userInfo.id)" plain @click="onAddFriends(userInfo)">添加</el-button>
-				 <el-button type="info" v-show="isFriend(userInfo.id)" plain disabled>已添加</el-button>
 			</div>
-		</div>
 		</el-scrollbar>
 	</el-dialog>
 </template>
@@ -88,6 +88,7 @@
 </script>
 
 <style scoped lang="scss">
+
 	.item {
 		height: 80px;
 		display: flex;

+ 3 - 0
im-ui/src/store/friendsStore.js

@@ -41,6 +41,9 @@ export default {
 		},
 		refreshOnlineStatus(state){
 			let userIds = [];
+			if(state.friendsList.length ==0){
+				return; 
+			}
 			state.friendsList.forEach((f)=>{userIds.push(f.friendId)});
 			httpRequest({
 				url: '/api/user/online',

+ 4 - 0
minio/minio.bat

@@ -0,0 +1,4 @@
+
+set MINIO_ACCESS_KEY=admin
+set MINIO_SECRET_KEY=12345678
+.\minio.exe  server C:\data\minio --address ":9001" --console-address ":9002"

+ 1 - 2
pom.xml

@@ -7,7 +7,7 @@
     <artifactId>lx-im</artifactId>
     <groupId>com.lx</groupId>
     <packaging>pom</packaging>
-    <version>${im.version}</version>
+    <version>1.0.0</version>
 
     <modules>
         <module>im-platform</module>
@@ -37,7 +37,6 @@
      </dependencies>
 
     <properties>
-        <im.version>1.0.0</im.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>1.8</java.version>