🎉 3.1.0.RELEASE 底层架构升级适配

This commit is contained in:
smallchill 2021-06-28 19:21:49 +08:00
parent 514a31a311
commit 08187b2e1f
31 changed files with 64 additions and 296 deletions

View File

@ -1,7 +1,7 @@
<p align="center">
<img src="https://img.shields.io/badge/license-LGPL%20v3-blue.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Spring%20Cloud-2020-blue.svg" alt="Coverage Status">
<img src="https://img.shields.io/badge/Spring%20Boot-2.4.4-blue.svg" alt="Downloads">
<img src="https://img.shields.io/badge/Spring%20Boot-2.5.2-blue.svg" alt="Downloads">
</p>
## SpringBlade微服务开发平台

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.springblade</groupId>
<artifactId>blade-tool</artifactId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -15,7 +15,6 @@
*/
package org.springblade.core.boot.config;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
@ -60,14 +59,6 @@ public class MybatisPlusConfiguration {
return interceptor;
}
/**
* mybatis-plus自3.4.0起采用新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
/**
* sql 日志
*

View File

@ -101,7 +101,7 @@ mybatis-plus:
swagger:
title: SpringBlade 接口文档系统
description: SpringBlade 接口文档系统
version: 3.0.3
version: 3.1.0
license: Powered By SpringBlade
licenseUrl: https://bladex.vip
terms-of-service-url: https://bladex.vip

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -17,9 +17,7 @@ package org.springblade.core.cloud.client;
import org.springblade.core.launch.constant.AppConstant;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
import java.lang.annotation.*;
@ -34,9 +32,8 @@ import java.lang.annotation.*;
@Documented
@Inherited
@EnableDiscoveryClient
@EnableCircuitBreaker
@EnableFeignClients(AppConstant.BASE_PACKAGES)
@SpringBootApplication(exclude = RibbonAutoConfiguration.class)
@SpringBootApplication
public @interface BladeCloudApplication {
}

View File

@ -19,7 +19,6 @@ package org.springblade.core.cloud.feign;
import org.springblade.core.launch.constant.AppConstant;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
import java.lang.annotation.*;
@ -33,7 +32,7 @@ import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@EnableFeignClients(AppConstant.BASE_PACKAGES)
@EnableAutoConfiguration(exclude = RibbonAutoConfiguration.class)
@EnableAutoConfiguration
public @interface EnableBladeFeign {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -26,12 +26,6 @@
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis.plus.generator.version}</version>
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -25,7 +25,7 @@ public interface AppConstant {
/**
* 应用版本
*/
String APPLICATION_VERSION = "3.0.3";
String APPLICATION_VERSION = "3.1.0";
/**
* 基础包

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -20,6 +20,7 @@ import org.springblade.core.log.publisher.ErrorLogPublisher;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.api.ResultCode;
import org.springblade.core.tool.utils.BeanUtil;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.lang.Nullable;
import org.springframework.web.context.request.RequestAttributes;
@ -36,7 +37,7 @@ import java.util.Map;
public class BladeErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
String requestUri = this.getAttr(webRequest, "javax.servlet.error.request_uri");
Integer status = this.getAttr(webRequest, "javax.servlet.error.status_code");
Throwable error = getError(webRequest);

View File

@ -39,7 +39,7 @@ public class LogAbstract implements Serializable {
/**
* 主键id
*/
@TableId(value = "id", type = IdType.ID_WORKER)
@TableId(value = "id", type = IdType.ASSIGN_ID)
protected Long id;
/**

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -17,11 +17,13 @@ package org.springblade.core.mp.support;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import java.util.Map;
@ -40,8 +42,14 @@ public class Condition {
*/
public static <T> IPage<T> getPage(Query query) {
Page<T> page = new Page<>(Func.toInt(query.getCurrent(), 1), Func.toInt(query.getSize(), 10));
page.setAsc(Func.toStrArray(SqlKeyword.filter(query.getAscs())));
page.setDesc(Func.toStrArray(SqlKeyword.filter(query.getDescs())));
String[] ascArr = Func.toStrArray(query.getAscs());
for (String asc : ascArr) {
page.addOrder(OrderItem.asc(StringUtil.cleanIdentifier(asc)));
}
String[] descArr = Func.toStrArray(query.getDescs());
for (String desc : descArr) {
page.addOrder(OrderItem.desc(StringUtil.cleanIdentifier(desc)));
}
return page;
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -55,7 +55,7 @@ public class SwaggerProperties {
/**
* 版本
**/
private String version = "3.0.3";
private String version = "3.1.0";
/**
* 许可证
**/

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.springblade</groupId>
<artifactId>blade-tool</artifactId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.springblade</groupId>
<artifactId>blade-tool</artifactId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -17,6 +17,7 @@ package org.springblade.core.tool.utils;
import org.springblade.core.tool.support.StrFormatter;
import org.springblade.core.tool.support.StrSpliter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.util.HtmlUtils;
@ -299,6 +300,27 @@ public class StringUtil extends org.springframework.util.StringUtils {
return template2;
}
/**
* 获取标识符用于参数清理
*
* @param param 参数
* @return 清理后的标识符
*/
@Nullable
public static String cleanIdentifier(@Nullable String param) {
if (param == null) {
return null;
}
StringBuilder paramBuilder = new StringBuilder();
for (int i = 0; i < param.length(); i++) {
char c = param.charAt(i);
if (Character.isJavaIdentifierPart(c)) {
paramBuilder.append(c);
}
}
return paramBuilder.toString();
}
/**
* 切分字符串不去除切分后每个元素两边的空白符不去除空白项
*

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>blade-tool</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,33 +0,0 @@
package com.alibaba.cloud.seata.feign;
import feign.Client;
import feign.Request;
import feign.Response;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
import java.io.IOException;
/**
* 重写SeataFeignBlockingLoadBalancerClient以适配最新API
*
* @author Chill
*/
public class SeataFeignBlockingLoadBalancerClient extends FeignBlockingLoadBalancerClient {
public SeataFeignBlockingLoadBalancerClient(Client delegate,
BlockingLoadBalancerClient loadBalancerClient,
SeataFeignObjectWrapper seataFeignObjectWrapper,
LoadBalancerProperties properties,
LoadBalancerClientFactory loadBalancerClientFactory) {
super((Client) seataFeignObjectWrapper.wrap(delegate), loadBalancerClient, properties, loadBalancerClientFactory);
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
return super.execute(request, options);
}
}

View File

@ -1,85 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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
*
* https://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.
*/
package com.alibaba.cloud.seata.feign;
import feign.Client;
import feign.Feign;
import feign.Retryer;
import lombok.RequiredArgsConstructor;
import org.springblade.core.cloud.feign.BladeFeignSentinel;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
* 重写SeataFeignClientAutoConfiguration以适配最新API
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Client.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class SeataFeignClientAutoConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnClass(name = "com.alibaba.csp.sentinel.SphU")
@ConditionalOnProperty(name = "feign.sentinel.enabled", havingValue = "true")
Feign.Builder feignSentinelBuilder(BeanFactory beanFactory) {
return BladeFeignSentinel.builder().retryer(Retryer.NEVER_RETRY)
.client(new SeataFeignClient(beanFactory));
}
@Bean
@ConditionalOnMissingBean
@Scope("prototype")
Feign.Builder feignBuilder(BeanFactory beanFactory) {
return SeataFeignBuilder.builder(beanFactory);
}
@Configuration(proxyBeanMethods = false)
@RequiredArgsConstructor
protected static class FeignBeanPostProcessorConfiguration {
private final LoadBalancedRetryFactory loadBalancedRetryFactory;
private final LoadBalancerProperties properties;
private final LoadBalancerClientFactory loadBalancerClientFactory;
@Bean
SeataBeanPostProcessor seataBeanPostProcessor(SeataFeignObjectWrapper seataFeignObjectWrapper) {
return new SeataBeanPostProcessor(seataFeignObjectWrapper);
}
@Bean
SeataContextBeanPostProcessor seataContextBeanPostProcessor(BeanFactory beanFactory) {
return new SeataContextBeanPostProcessor(beanFactory);
}
@Bean
SeataFeignObjectWrapper seataFeignObjectWrapper(BeanFactory beanFactory) {
return new SeataFeignObjectWrapper(beanFactory, loadBalancedRetryFactory, properties, loadBalancerClientFactory);
}
}
}

View File

@ -1,74 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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
*
* https://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.
*/
package com.alibaba.cloud.seata.feign;
import feign.Client;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
import org.springframework.cloud.openfeign.loadbalancer.RetryableFeignBlockingLoadBalancerClient;
/**
* 重写SeataFeignObjectWrapper以适配最新API
*
* @author Chill
*/
public class SeataFeignObjectWrapper {
private final BeanFactory beanFactory;
private final LoadBalancedRetryFactory loadBalancedRetryFactory;
private final LoadBalancerProperties properties;
private final LoadBalancerClientFactory loadBalancerClientFactory;
private SpringClientFactory springClientFactory;
SeataFeignObjectWrapper(BeanFactory beanFactory, LoadBalancedRetryFactory loadBalancedRetryFactory, LoadBalancerProperties properties, LoadBalancerClientFactory loadBalancerClientFactory) {
this.beanFactory = beanFactory;
this.loadBalancedRetryFactory = loadBalancedRetryFactory;
this.properties = properties;
this.loadBalancerClientFactory = loadBalancerClientFactory;
}
Object wrap(Object bean) {
if (bean instanceof Client && !(bean instanceof SeataFeignClient)) {
if (bean instanceof FeignBlockingLoadBalancerClient) {
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) bean;
return new SeataFeignBlockingLoadBalancerClient(client.getDelegate(),
beanFactory.getBean(BlockingLoadBalancerClient.class), this, properties, loadBalancerClientFactory);
}
if (bean instanceof RetryableFeignBlockingLoadBalancerClient) {
RetryableFeignBlockingLoadBalancerClient client = (RetryableFeignBlockingLoadBalancerClient) bean;
return new SeataRetryableFeignBlockingLoadBalancerClient(client.getDelegate(),
beanFactory.getBean(BlockingLoadBalancerClient.class), this, loadBalancedRetryFactory, properties, loadBalancerClientFactory);
}
return new SeataFeignClient(this.beanFactory, (Client) bean);
}
return bean;
}
SpringClientFactory clientFactory() {
if (this.springClientFactory == null) {
this.springClientFactory = this.beanFactory
.getBean(SpringClientFactory.class);
}
return this.springClientFactory;
}
}

View File

@ -1,49 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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
*
* https://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.
*/
package com.alibaba.cloud.seata.feign;
import feign.Client;
import feign.Request;
import feign.Response;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.RetryableFeignBlockingLoadBalancerClient;
import java.io.IOException;
/**
* 拓展SeataRetryableFeignBlockingLoadBalancerClient以适配最新API
*
* @author Chill
*/
public class SeataRetryableFeignBlockingLoadBalancerClient extends RetryableFeignBlockingLoadBalancerClient {
public SeataRetryableFeignBlockingLoadBalancerClient(Client delegate,
BlockingLoadBalancerClient loadBalancerClient,
SeataFeignObjectWrapper seataFeignObjectWrapper,
LoadBalancedRetryFactory loadBalancedRetryFactory,
LoadBalancerProperties properties,
LoadBalancerClientFactory loadBalancerClientFactory) {
super((Client) seataFeignObjectWrapper.wrap(delegate), loadBalancerClient, loadBalancedRetryFactory, properties, loadBalancerClientFactory);
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
return super.execute(request, options);
}
}

View File

@ -17,9 +17,7 @@ package org.springblade.core.transaction.annotation;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import java.lang.annotation.*;
@ -33,8 +31,7 @@ import java.lang.annotation.*;
@Documented
@Inherited
@EnableDiscoveryClient
@EnableCircuitBreaker
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, RibbonAutoConfiguration.class})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public @interface SeataCloudApplication {
}

16
pom.xml
View File

@ -5,7 +5,7 @@
<groupId>org.springblade</groupId>
<artifactId>blade-tool</artifactId>
<version>3.0.3</version>
<version>3.1.0</version>
<packaging>pom</packaging>
<name>blade-tool</name>
<description>
@ -36,26 +36,26 @@
</scm>
<properties>
<blade.tool.version>3.0.3</blade.tool.version>
<blade.tool.version>3.1.0</blade.tool.version>
<java.version>1.8</java.version>
<maven.plugin.version>3.8.0</maven.plugin.version>
<swagger.version>2.10.5</swagger.version>
<swagger.models.version>1.6.2</swagger.models.version>
<knife4j.version>2.0.8</knife4j.version>
<mybatis.plus.version>3.4.2</mybatis.plus.version>
<mybatis.plus.version>3.4.3.1</mybatis.plus.version>
<mybatis.plus.generator.version>3.4.1</mybatis.plus.generator.version>
<protostuff.version>1.6.0</protostuff.version>
<disruptor.version>3.4.2</disruptor.version>
<spring.boot.admin.version>2.3.1</spring.boot.admin.version>
<mica.auto.version>1.2.5</mica.auto.version>
<alibaba.cloud.version>2.2.5.RELEASE</alibaba.cloud.version>
<alibaba.nacos.version>2.0.0</alibaba.nacos.version>
<alibaba.seata.version>1.4.1</alibaba.seata.version>
<alibaba.cloud.version>2021.1</alibaba.cloud.version>
<alibaba.nacos.version>2.0.2</alibaba.nacos.version>
<alibaba.seata.version>1.4.2</alibaba.seata.version>
<spring.plugin.version>2.0.0.RELEASE</spring.plugin.version>
<spring.boot.version>2.4.4</spring.boot.version>
<spring.cloud.version>2020.0.2</spring.cloud.version>
<spring.boot.version>2.5.2</spring.boot.version>
<spring.cloud.version>2020.0.3</spring.cloud.version>
<spring.platform.version>Cairo-SR8</spring.platform.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>