diff --git a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminRegionController.java b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminRegionController.java
index 9992dc80..9961b6e4 100644
--- a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminRegionController.java
+++ b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminRegionController.java
@@ -44,7 +44,7 @@ public class AdminRegionController {
String name, Integer code,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer limit,
- @Sort @RequestParam(defaultValue = "add_time") String sort,
+ @Sort (accepts={"id"}) @RequestParam(defaultValue = "id") String sort,
@Order @RequestParam(defaultValue = "desc") String order){
if(adminId == null){
return ResponseUtil.unlogin();
diff --git a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminStorageController.java b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminStorageController.java
index 50d4fca2..d2223003 100644
--- a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminStorageController.java
+++ b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminStorageController.java
@@ -68,7 +68,7 @@ public class AdminStorageController {
}
@PostMapping("/create")
- public Object create(@LoginAdmin Integer adminId, @RequestParam("file") MultipartFile file) {
+ public Object create(@LoginAdmin Integer adminId, @RequestParam("file") MultipartFile file) throws IOException {
if(adminId == null){
return ResponseUtil.unlogin();
}
@@ -81,7 +81,7 @@ public class AdminStorageController {
return ResponseUtil.badArgumentValue();
}
String key = generateKey(originalFilename);
- storageService.store(file, key);
+ storageService.store(file.getInputStream(), file.getSize(), file.getContentType(), key);
String url = storageService.generateUrl(key);
LitemallStorage storageInfo = new LitemallStorage();
diff --git a/litemall-all/src/main/java/org/linlinjava/litemall/Application.java b/litemall-all/src/main/java/org/linlinjava/litemall/Application.java
index f4988f23..7241a35f 100644
--- a/litemall-all/src/main/java/org/linlinjava/litemall/Application.java
+++ b/litemall-all/src/main/java/org/linlinjava/litemall/Application.java
@@ -3,8 +3,6 @@ package org.linlinjava.litemall;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.builder.SpringApplicationBuilder;
-import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication(scanBasePackages = {
"org.linlinjava.litemall",
@@ -13,12 +11,7 @@ import org.springframework.boot.web.support.SpringBootServletInitializer;
"org.linlinjava.litemall.wx",
"org.linlinjava.litemall.admin"})
@MapperScan("org.linlinjava.litemall.db.dao")
-public class Application extends SpringBootServletInitializer {
-
- @Override
- protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
- return application.sources(Application.class);
- }
+public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
diff --git a/litemall-core/pom.xml b/litemall-core/pom.xml
index b3d010cc..cb4ab9b0 100644
--- a/litemall-core/pom.xml
+++ b/litemall-core/pom.xml
@@ -18,31 +18,23 @@
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
+ org.springframework.boot
+ spring-boot-starter-mail
- org.springframework
- spring-context-support
- RELEASE
- compile
-
-
- com.sun.mail
- javax.mail
+ org.springframework.boot
+ spring-boot-starter-json
com.github.qcloudsms
qcloudsms
- 1.0.5
com.qcloud
cos_api
- 5.4.4
slf4j-log4j12
@@ -54,7 +46,6 @@
com.aliyun.oss
aliyun-sdk-oss
- 2.5.0
commons-lang
@@ -68,25 +59,13 @@
weixin-java-miniapp
- org.springframework.boot
- spring-boot-configuration-processor
- true
+ com.github.binarywang
+ weixin-java-pay
org.linlinjava
litemall-db
-
- com.github.binarywang
- weixin-java-pay
- 3.0.0
-
-
- org.springframework
- spring-test
- 5.0.7.RELEASE
- compile
-
\ No newline at end of file
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/qcode/QCodeService.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/qcode/QCodeService.java
index 7d637160..818e3b88 100644
--- a/litemall-core/src/main/java/org/linlinjava/litemall/core/qcode/QCodeService.java
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/qcode/QCodeService.java
@@ -7,9 +7,7 @@ import org.linlinjava.litemall.core.system.SystemConfig;
import org.linlinjava.litemall.db.domain.LitemallGroupon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
-import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
@@ -65,9 +63,9 @@ public class QCodeService {
FileInputStream inputStream = new FileInputStream(file);
//将商品图片,商品名字,商城名字画到模版图中
byte[] imageData = drawPicture(inputStream, goodPicUrl, goodName, SystemConfig.getMallName());
- MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(), "image/jpeg", imageData);
+ ByteArrayInputStream inputStream2 = new ByteArrayInputStream(imageData);
//存储分享图
- storageService.store(multipartFile, getKeyName(goodId));
+ storageService.store(inputStream2, imageData.length, "image/jpeg", getKeyName(goodId));
} catch (WxErrorException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/AliyunStorage.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/AliyunStorage.java
index 84c8c175..432b7f46 100644
--- a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/AliyunStorage.java
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/AliyunStorage.java
@@ -6,8 +6,8 @@ import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
-import org.springframework.web.multipart.MultipartFile;
+import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
@@ -74,14 +74,14 @@ public class AliyunStorage implements Storage {
* 阿里云OSS对象存储简单上传实现
*/
@Override
- public void store(MultipartFile file, String keyName) {
+ public void store(InputStream inputStream, long contentLength, String contentType, String keyName) {
try {
// 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20M以下的文件使用该接口
ObjectMetadata objectMetadata = new ObjectMetadata();
- objectMetadata.setContentLength(file.getSize());
- objectMetadata.setContentType(file.getContentType());
+ objectMetadata.setContentLength(contentLength);
+ objectMetadata.setContentType(contentType);
// 对象键(Key)是对象在存储桶中的唯一标识。
- PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, file.getInputStream(), objectMetadata);
+ PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, inputStream, objectMetadata);
PutObjectResult putObjectResult = getOSSClient().putObject(putObjectRequest);
} catch (Exception ex) {
ex.printStackTrace();
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/LocalStorage.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/LocalStorage.java
index 305ee71b..a4fc7f69 100644
--- a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/LocalStorage.java
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/LocalStorage.java
@@ -3,9 +3,9 @@ package org.linlinjava.litemall.core.storage;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
-import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
+import java.io.InputStream;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -47,9 +47,9 @@ public class LocalStorage implements Storage {
}
@Override
- public void store(MultipartFile file, String keyName) {
+ public void store(InputStream inputStream, long contentLength, String contentType, String keyName) {
try {
- Files.copy(file.getInputStream(), rootLocation.resolve(keyName), StandardCopyOption.REPLACE_EXISTING);
+ Files.copy(inputStream, rootLocation.resolve(keyName), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new RuntimeException("Failed to store file " + keyName, e);
}
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/Storage.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/Storage.java
index 58a769ef..598ca109 100644
--- a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/Storage.java
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/Storage.java
@@ -1,8 +1,8 @@
package org.linlinjava.litemall.core.storage;
import org.springframework.core.io.Resource;
-import org.springframework.web.multipart.MultipartFile;
+import java.io.InputStream;
import java.nio.file.Path;
import java.util.stream.Stream;
@@ -13,10 +13,12 @@ public interface Storage {
/**
* 存储一个文件对象
- * @param file SpringBoot MultipartFile文件对象
+ * @param inputStream 文件输入流
+ * @param contentLength 文件长度
+ * @param contentType 文件类型
* @param keyName 文件索引名
*/
- void store(MultipartFile file, String keyName);
+ void store(InputStream inputStream, long contentLength, String contentType, String keyName);
Stream loadAll();
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/StorageService.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/StorageService.java
index 29ca050c..26fa0c9d 100644
--- a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/StorageService.java
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/StorageService.java
@@ -3,6 +3,7 @@ package org.linlinjava.litemall.core.storage;
import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
+import java.io.InputStream;
import java.nio.file.Path;
import java.util.stream.Stream;
@@ -31,12 +32,13 @@ public class StorageService {
/**
* 存储一个文件对象
- *
- * @param file SpringBoot MultipartFile文件对象
- * @param keyName 文件索引名
+ * @param inputStream 文件输入流
+ * @param contentLength 文件长度
+ * @param contentType 文件类型
+ * @param keyName 文件索引名
*/
- public void store(MultipartFile file, String keyName) {
- storage.store(file, keyName);
+ public void store(InputStream inputStream, long contentLength, String contentType, String keyName) {
+ storage.store(inputStream, contentLength, contentType, keyName);
}
public Stream loadAll() {
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/TencentStorage.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/TencentStorage.java
index 505e270a..625aa554 100644
--- a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/TencentStorage.java
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/TencentStorage.java
@@ -8,13 +8,10 @@ import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
-import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
+import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
@@ -81,14 +78,14 @@ public class TencentStorage implements Storage {
}
@Override
- public void store(MultipartFile file, String keyName) {
+ public void store(InputStream inputStream, long contentLength, String contentType, String keyName) {
try {
// 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20M以下的文件使用该接口
ObjectMetadata objectMetadata = new ObjectMetadata();
- objectMetadata.setContentLength(file.getSize());
- objectMetadata.setContentType(file.getContentType());
+ objectMetadata.setContentLength(contentLength);
+ objectMetadata.setContentType(contentType);
// 对象键(Key)是对象在存储桶中的唯一标识。例如,在对象的访问域名 `bucket1-1250000000.cos.ap-guangzhou.myqcloud.com/doc1/pic1.jpg` 中,对象键为 doc1/pic1.jpg, 详情参考 [对象键](https://cloud.tencent.com/document/product/436/13324)
- PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, file.getInputStream(), objectMetadata);
+ PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, inputStream, objectMetadata);
PutObjectResult putObjectResult = getCOSClient().putObject(putObjectRequest);
} catch (Exception ex) {
ex.printStackTrace();
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/util/YmlPropertyFactory.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/util/YmlPropertyFactory.java
deleted file mode 100644
index 95cc5887..00000000
--- a/litemall-core/src/main/java/org/linlinjava/litemall/core/util/YmlPropertyFactory.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.linlinjava.litemall.core.util;
-
-import org.springframework.boot.env.PropertySourcesLoader;
-import org.springframework.core.env.PropertySource;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.support.EncodedResource;
-import org.springframework.core.io.support.PropertySourceFactory;
-
-import java.io.IOException;
-
-/**
- * 某些情况下外部依赖导致 yaml 配置未能正确注入时,@PropertySource(value = {"classpath:application-wx.yaml"}, factory = YmlPropertyFactory.class) 手动注入配置文件
- */
-public class YmlPropertyFactory implements PropertySourceFactory {
- @Override
- public PropertySource> createPropertySource(String name, EncodedResource resource) throws IOException {
- return name != null ? new PropertySourcesLoader().load(resource.getResource(), name, null) : new PropertySourcesLoader().load(
- resource.getResource(), getNameForResource(resource.getResource()), null);
- }
-
- private static String getNameForResource(Resource resource) {
- String name = resource.getDescription();
- if (!org.springframework.util.StringUtils.hasText(name)) {
- name = resource.getClass().getSimpleName() + "@" + System.identityHashCode(resource);
- }
- return name;
- }
-}
diff --git a/litemall-core/src/main/resources/application.yml b/litemall-core/src/main/resources/application.yml
index 3e899539..bf97b49a 100644
--- a/litemall-core/src/main/resources/application.yml
+++ b/litemall-core/src/main/resources/application.yml
@@ -1,6 +1,6 @@
spring:
profiles:
- active: core
+ active: core, db
message:
encoding: UTF-8
diff --git a/litemall-core/src/test/java/org/linlinjava/litemall/core/AliyunStorageTest.java b/litemall-core/src/test/java/org/linlinjava/litemall/core/AliyunStorageTest.java
index e5a949eb..51ec0507 100644
--- a/litemall-core/src/test/java/org/linlinjava/litemall/core/AliyunStorageTest.java
+++ b/litemall-core/src/test/java/org/linlinjava/litemall/core/AliyunStorageTest.java
@@ -11,6 +11,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.FileCopyUtils;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -24,9 +25,8 @@ public class AliyunStorageTest {
@Test
public void test() throws IOException {
String test = getClass().getClassLoader().getResource("litemall.png").getFile();
- byte[] content = (byte[])FileCopyUtils.copyToByteArray(new FileInputStream(test));
- MockMultipartFile mockMultipartFile = new MockMultipartFile("litemall.png", "litemall.png", "image/png", content);
- aliyunStorage.store(mockMultipartFile, "litemall.png");
+ File testFile = new File(test);
+ aliyunStorage.store(new FileInputStream(test), testFile.length(), "image/png", "litemall.png");
Resource resource = aliyunStorage.loadAsResource("litemall.png");
String url = aliyunStorage.generateUrl("litemall.png");
System.out.println("test file " + test);
diff --git a/litemall-core/src/test/java/org/linlinjava/litemall/core/LocalStorageTest.java b/litemall-core/src/test/java/org/linlinjava/litemall/core/LocalStorageTest.java
index aca78d04..8e39629f 100644
--- a/litemall-core/src/test/java/org/linlinjava/litemall/core/LocalStorageTest.java
+++ b/litemall-core/src/test/java/org/linlinjava/litemall/core/LocalStorageTest.java
@@ -6,11 +6,9 @@ import org.linlinjava.litemall.core.storage.LocalStorage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.Resource;
-import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
-import org.springframework.util.FileCopyUtils;
-
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -24,9 +22,8 @@ public class LocalStorageTest {
@Test
public void test() throws IOException {
String test = getClass().getClassLoader().getResource("litemall.png").getFile();
- byte[] content = (byte[])FileCopyUtils.copyToByteArray(new FileInputStream(test));
- MockMultipartFile mockMultipartFile = new MockMultipartFile("litemall.png", "litemall.png", "image/jpeg", content);
- localStorage.store(mockMultipartFile, "litemall.png");
+ File testFile = new File(test);
+ localStorage.store(new FileInputStream(test), testFile.length(), "image/png", "litemall.png");
Resource resource = localStorage.loadAsResource("litemall.png");
String url = localStorage.generateUrl("litemall.png");
System.out.println("test file " + test);
diff --git a/litemall-core/src/test/java/org/linlinjava/litemall/core/TencentStorageTest.java b/litemall-core/src/test/java/org/linlinjava/litemall/core/TencentStorageTest.java
index fae0a9a9..28b67b13 100644
--- a/litemall-core/src/test/java/org/linlinjava/litemall/core/TencentStorageTest.java
+++ b/litemall-core/src/test/java/org/linlinjava/litemall/core/TencentStorageTest.java
@@ -6,11 +6,10 @@ import org.linlinjava.litemall.core.storage.TencentStorage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.Resource;
-import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
-import org.springframework.util.FileCopyUtils;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -24,9 +23,8 @@ public class TencentStorageTest {
@Test
public void test() throws IOException {
String test = getClass().getClassLoader().getResource("litemall.png").getFile();
- byte[] content = (byte[])FileCopyUtils.copyToByteArray(new FileInputStream(test));
- MockMultipartFile mockMultipartFile = new MockMultipartFile("litemall.png", "litemall.png", "image/png", content);
- tencentStorage.store(mockMultipartFile, "litemall.png");
+ File testFile = new File(test);
+ tencentStorage.store(new FileInputStream(test), testFile.length(), "image/png", "litemall.png");
Resource resource = tencentStorage.loadAsResource("litemall.png");
String url = tencentStorage.generateUrl("litemall.png");
System.out.println("test file " + test);
diff --git a/litemall-db/pom.xml b/litemall-db/pom.xml
index b9b215aa..5792eaaa 100644
--- a/litemall-db/pom.xml
+++ b/litemall-db/pom.xml
@@ -12,6 +12,11 @@
+
+ org.springframework.boot
+ spring-boot-starter-json
+
+
org.mybatis.spring.boot
mybatis-spring-boot-starter
@@ -32,11 +37,6 @@
druid-spring-boot-starter
-
- com.fasterxml.jackson.core
- jackson-databind
-
-
diff --git a/litemall-db/src/main/resources/application-db.yml b/litemall-db/src/main/resources/application-db.yml
index efe31994..583a0c64 100644
--- a/litemall-db/src/main/resources/application-db.yml
+++ b/litemall-db/src/main/resources/application-db.yml
@@ -22,5 +22,5 @@ spring:
test-on-return: false
test-while-idle: true
time-between-eviction-runs-millis: 60000
- filters: stat,wall,log4j
+ filters: stat,wall
diff --git a/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxStorageController.java b/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxStorageController.java
index 1b2fda14..b5f40c2f 100644
--- a/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxStorageController.java
+++ b/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxStorageController.java
@@ -48,7 +48,7 @@ public class WxStorageController {
}
@PostMapping("/upload")
- public Object upload(@RequestParam("file") MultipartFile file) {
+ public Object upload(@RequestParam("file") MultipartFile file) throws IOException {
String originalFilename = file.getOriginalFilename();
InputStream inputStream = null;
try {
@@ -58,7 +58,7 @@ public class WxStorageController {
return ResponseUtil.badArgumentValue();
}
String key = generateKey(originalFilename);
- storageService.store(file, key);
+ storageService.store(file.getInputStream(), file.getSize(), file.getContentType(), key);
String url = storageService.generateUrl(key);
LitemallStorage storageInfo = new LitemallStorage();
diff --git a/pom.xml b/pom.xml
index 2eb2fc5c..cfcef2a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
org.springframework.boot
spring-boot-starter-parent
- 1.5.12.RELEASE
+ 2.0.4.RELEASE
@@ -55,12 +55,6 @@
${project.version}
-
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
- 2.9.5
-
-
org.mybatis.spring.boot
@@ -85,7 +79,7 @@
com.alibaba
druid-spring-boot-starter
- 1.1.9
+ 1.1.10
@@ -99,6 +93,36 @@
weixin-java-miniapp
3.1.0
+
+
+ com.github.qcloudsms
+ qcloudsms
+ 1.0.5
+
+
+
+ com.qcloud
+ cos_api
+ 5.4.4
+
+
+
+ com.aliyun.oss
+ aliyun-sdk-oss
+ 2.5.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-json
+ 2.0.4.RELEASE
+
+
+
+ org.springframework.boot
+ spring-boot-starter-mail
+ 2.0.4.RELEASE
+