瀏覽代碼

@task: file upload

bai 3 年之前
父節點
當前提交
80c812d211

+ 4 - 2
demo/build.gradle

@@ -27,8 +27,6 @@ apply plugin: 'kotlin-android-extensions'*/
 plugins {
     id 'com.android.application'
     id 'kotlin-android'
-   /// id 'kotlin-android-extensions'
-    // kotlin("kapt")
     id 'org.jetbrains.kotlin.kapt'
     id 'kotlin-parcelize'
 }
@@ -272,4 +270,8 @@ dependencies {
     //屏幕适配
 //    implementation 'me.jessyan:autosize:1.2.1'
     implementation 'com.rm:rmswitch:1.2.2'
+
+    androidTestImplementation("androidx.test.ext:junit:1.1.3")
+    androidTestImplementation("androidx.test.ext:junit-ktx:1.1.3")
+    testImplementation("junit:junit:4.13.2")
 }

+ 1 - 1
demo/src/main/java/com/framework/app/Constants.kt

@@ -10,7 +10,7 @@ const val test2IP = "http://192.168.0.11:8876/"
 
 const val tencentIP = "http://82.157.28.170:8876/"
 
-const val IP = tencentIP
+const val IP = test2IP
 
 const val pathDownloadMap = "adm/downloadMap?key="
 

+ 19 - 3
demo/src/main/java/com/framework/app/api/Api.kt

@@ -1,11 +1,12 @@
 package com.framework.app.api
 
+import com.framework.app.http.FileInfo
+import com.framework.app.http.FileUploadInfo
 import com.framework.app.test2IP
 import com.framework.mvvm.model.data.Model
 import com.framework.mvvm.model.vo.*
-import retrofit2.http.Body
-import retrofit2.http.Headers
-import retrofit2.http.POST
+import okhttp3.RequestBody
+import retrofit2.http.*
 
 interface Api {
     /**
@@ -14,6 +15,9 @@ interface Api {
     @POST("adm/dict")
     suspend fun getDict(@Body request: AdmRequest): Model<Dict>
 
+    /**
+     * 获取配置信息
+     */
     @POST("adm/config")
     suspend fun getConfig(@Body request: AdmRequest): Model<Config>
 
@@ -35,5 +39,17 @@ interface Api {
     @Headers("Content-Encoding: gzip")
     @POST("adm/upload")
     suspend fun uploadBuilding(@Body building: UploadBuilding): Model<UploadResult>
+
+    /**
+     * 获取文件上传接口
+     */
+    @POST("http://develop.persagy.com/dmp-file/file/initSingleUpload?groupCode=BR&userId=bdtp&appId=adm&projectId=Pj000222011")
+    suspend fun getFileUploadInfo(@Body file: FileInfo): Model<FileUploadInfo>
+
+    /**
+     * 上传文件
+     */
+    @PUT("")
+    suspend fun uploadFile(@Url url: String, @Body file: RequestBody): String
 }
 

+ 27 - 0
demo/src/main/java/com/framework/app/converter/NullOrEmptyConverter.kt

@@ -0,0 +1,27 @@
+package com.framework.app.converter
+
+import okhttp3.ResponseBody
+import retrofit2.Converter
+import retrofit2.Retrofit
+import java.lang.reflect.Type
+
+/**
+ * 空字符串转换器
+ */
+class NullOrEmptyConverter : Converter.Factory() {
+    override fun responseBodyConverter(
+        type: Type,
+        annotations: Array<out Annotation>,
+        retrofit: Retrofit
+    ): Converter<ResponseBody, *> {
+        val delegate: Converter<ResponseBody, Any> =
+            retrofit.nextResponseBodyConverter(this, type, annotations)
+        return Converter<ResponseBody, Any?> { value ->
+            val length = value.contentLength().toInt()
+            if (length == 0) {
+                return@Converter ""
+            }
+            delegate.convert(value)
+        }
+    }
+}

+ 28 - 0
demo/src/main/java/com/framework/app/http/FileUpload.kt

@@ -0,0 +1,28 @@
+package com.framework.app.http
+
+/**
+ * 文件基本信息
+ */
+data class FileInfo(
+    val fileMd5: String,            // 文件MD5
+    val fileName: String,           // 文件名
+    val fileBucket: String = "adm", // 目前固定"adm"
+    val fileSize: Int               // 文件大小
+)
+
+/**
+ * 文件上传信息
+ */
+data class FileUploadInfo(
+    val id: String,
+    val uploadCode: Int,
+    val content: List<FilePartInfo>? = null
+)
+
+/**
+ * 文件上传分段信息和上传Url
+ */
+data class FilePartInfo(
+    val partNumber: Int,
+    val uploadUrl: String
+)

+ 26 - 0
demo/src/main/java/com/framework/app/tools/FileTools.kt

@@ -0,0 +1,26 @@
+package com.framework.app.tools
+
+import android.content.Context
+import com.framework.app.http.FileInfo
+import com.framework.mvvm.model.data.SuccessResponse
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.RequestBody
+import okhttp3.RequestBody.Companion.toRequestBody
+import java.io.File
+import java.io.FileInputStream
+
+/**
+ * 读取文件,返回字节数组
+ */
+fun File.toBytes(): ByteArray {
+
+    val fis = FileInputStream(this)
+    return fis.readBytes()
+}
+
+fun File.toRequestBody(
+    mediaType: String = "application/json;charset=utf-8"
+): RequestBody {
+    val bytes = this.toBytes()
+    return bytes.toRequestBody(mediaType.toMediaType())
+}

+ 43 - 0
demo/src/main/java/com/framework/app/tools/Md5.kt

@@ -0,0 +1,43 @@
+package com.framework.app.tools
+
+import java.io.File
+import java.io.InputStream
+import java.security.MessageDigest
+
+/**
+ * MD5
+ */
+fun md5(byteArray: ByteArray): String {
+    val digest = MessageDigest.getInstance("md5")
+    val bytes = digest.digest(byteArray)
+    var md5 = ""
+    for (b in bytes) {
+        val hex = Integer.toHexString(0xFF and b.toInt())
+        if (hex.length == 1) {
+            md5 += "0"
+        }
+        md5 += hex
+    }
+    return md5
+}
+
+/**
+ * 文件 md5
+ */
+fun fileMD5(file: File): String {
+    return md5(file.toBytes())
+}
+
+/**
+ * 字符串 md5
+ */
+fun strMD5(string: String): String {
+    return md5(string.toByteArray())
+}
+
+fun streamMD5(stream: InputStream): String {
+    return md5(stream.readBytes())
+}
+
+
+

+ 2 - 0
demo/src/main/java/com/framework/di/Di.kt

@@ -3,6 +3,7 @@ package com.framework.di
 import android.content.Context
 import com.framework.app.IP
 import com.framework.app.api.Api
+import com.framework.app.converter.NullOrEmptyConverter
 import com.framework.app.http.GzipRequestInterceptor
 import com.framework.mvvm.model.db.AdmDatabase
 import com.framework.mvvm.model.repository.AdmRepository
@@ -25,6 +26,7 @@ val httpModule = DI.Module("netModule") {
             Retrofit.Builder()
                 .baseUrl(IP)
                 .client(instance())
+                .addConverterFactory(NullOrEmptyConverter())
                 .addConverterFactory(GsonConverterFactory.create())
                 .build()
         }

+ 1 - 1
demo/src/main/java/com/framework/mvvm/model/data/Http.kt

@@ -36,7 +36,7 @@ suspend fun <T> request(block: suspend () -> Model<T>): Response<T> {
         block()
     }.onSuccess {
         // "00000" 代表数据请求成功
-        result = if (it.code == "00000") {
+        result = if (it.code == "00000" || it.message == "success") {
             Response.create(it.data)
         } else {
             Response.create(it.message ?: "http request Ok, but don't have data")

+ 3 - 0
demo/src/main/java/com/framework/mvvm/model/data/Model.kt

@@ -1,10 +1,13 @@
 package com.framework.mvvm.model.data
 
+import com.google.gson.annotations.SerializedName
+
 /**
  * ① Api 返回数据容器
  */
 data class Model<T>(
     val code: String,
+    @SerializedName(value = "message", alternate = ["result"])
     val message: String? = null,
     val data: T
 )

+ 19 - 31
demo/src/main/java/com/framework/mvvm/model/repository/AdmRepository.kt

@@ -3,17 +3,20 @@ package com.framework.mvvm.model.repository
 import android.content.SharedPreferences
 import android.util.Log
 import androidx.lifecycle.LiveData
+import com.framework.app.DEVICE_ID
 import com.framework.app.api.Api
 import com.framework.app.base.IRepository
-import com.framework.app.DEVICE_ID
+import com.framework.app.http.FileInfo
+import com.framework.app.http.FileUploadInfo
 import com.framework.mvvm.model.data.*
 import com.framework.mvvm.model.db.AdmDatabase
-import com.framework.mvvm.model.db.entity.*
+import com.framework.mvvm.model.db.entity.ProjectEntity
 import com.framework.mvvm.model.db.entity.dict.*
 import com.framework.mvvm.model.db.entity.task.*
 import com.framework.mvvm.model.vo.AdmRequest
 import com.framework.mvvm.model.vo.Building
 import com.framework.mvvm.model.vo.UploadBuilding
+import okhttp3.RequestBody
 
 class AdmRepository(
     private val api: Api,
@@ -21,35 +24,6 @@ class AdmRepository(
     private val sp: SharedPreferences
 ) : IRepository {
 
-    fun getProjects(request: AdmRequest): LiveData<Data<List<ProjectEntity>>> {
-        return dataSource(
-            fromDb = { db.projectDao().getProjects() },
-            fromNt = { request { api.getFrame(request) } },
-            isFromNt = { true },
-            onSuccess = { frame ->
-                val projects = frame.projects
-                val bafs = frame.buildingsAndFloors
-                try {
-                    db.projectDao().insProject(projects)
-                    db.objectDao().insObjects(bafs)
-                } catch (e: Exception) {
-                    Log.d("IRepository:${AdmRepository::class.simpleName}", e.message!!)
-                }
-            },
-            onFailure = {
-                println("onFailure: ${it.msg}")
-            }
-        )
-    }
-
-    fun getProjects(): LiveData<List<ProjectEntity>> {
-        return db.projectDao().getProjects()
-    }
-
-    suspend fun insProject(projects: List<ProjectEntity>) {
-        return db.projectDao().insProject(projects)
-    }
-
     suspend fun insProblem(problem: ProblemArchEntity) {
         return db.problemArchDao().insProblem(problem)
     }
@@ -507,4 +481,18 @@ class AdmRepository(
             println("uploadBuilding Exception: $e")
         }
     }
+
+    /**
+     *  获取文件信息
+     */
+    suspend fun getFileUploadInfo(file: FileInfo): Model<FileUploadInfo> {
+        return api.getFileUploadInfo(file)
+    }
+
+    /**
+     * 上传文件
+     */
+    suspend fun uploadFile(url: String, file: RequestBody): String {
+        return api.uploadFile(url, file)
+    }
 }

+ 54 - 2
demo/src/main/java/com/framework/mvvm/mv/AdmViewModel.kt

@@ -1,19 +1,23 @@
 package com.framework.mvvm.mv
 
 import android.content.SharedPreferences
+import android.util.Log
 import androidx.core.content.edit
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import cn.sagacloud.cadengine.OkhttpUtil
 import com.framework.app.DEVICE_ID
 import com.framework.app.IP
+import com.framework.app.http.FileInfo
+import com.framework.app.http.FileUploadInfo
 import com.framework.app.pathDownloadMap
 import com.framework.app.timestamp
+import com.framework.app.tools.md5
+import com.framework.app.tools.toBytes
+import com.framework.mvvm.model.data.*
 import com.framework.mvvm.model.db.entity.task.ObjectEntity
 import com.framework.mvvm.model.repository.AdmRepository
 import com.framework.mvvm.model.vo.AdmRequest
-import com.framework.mvvm.model.vo.FloorInfo
-import com.google.gson.Gson
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
 import kotlinx.coroutines.flow.StateFlow
@@ -21,6 +25,9 @@ import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import okhttp3.RequestBody
+import okhttp3.RequestBody.Companion.toRequestBody
+import java.io.File
 
 
 class AdmViewModel(private val repository: AdmRepository) : ViewModel() {
@@ -128,4 +135,49 @@ class AdmViewModel(private val repository: AdmRepository) : ViewModel() {
     suspend fun getBuildings(): List<ObjectEntity> {
         return repository.getBuildings()
     }
+
+    /**
+     * 获取文件上传信息
+     */
+    private suspend fun getFileUploadInfo(basic: FileInfo): Response<FileUploadInfo> {
+        return request { repository.getFileUploadInfo(basic) }
+    }
+
+    /**
+     * 上传文件
+     */
+    private suspend fun uploadFile(url: String, file: RequestBody): String {
+        return repository.uploadFile(url, file)
+    }
+
+    /**
+     * 上传文件
+     */
+    fun fileUpload(file: File) {
+        val bytes = file.toBytes()
+
+        val md5 = md5(bytes)
+
+        val info = FileInfo(
+            fileMd5 = md5,
+            fileName = file.name,
+            fileSize = bytes.size
+        )
+
+        viewModelScope.launch(Dispatchers.IO) {
+            val response = getFileUploadInfo(info)
+            if (response is SuccessResponse) {
+                val data = response.data
+                val url = data.content?.get(0)?.uploadUrl ?: ""
+                if (url.isNotEmpty()) {
+                    val body = bytes.toRequestBody()
+                    val result = uploadFile(url, body)
+
+                    Log.d("fileUpload", "success: $result")
+                }
+            } else {
+                Log.d("fileUpload", "upload file has something error:$response")
+            }
+        }
+    }
 }