您好,登錄后才能下訂單哦!
前端android,上傳與下載文件,使用OkHttp處理請求,后端使用spring boot+MVC,處理android發送來的上傳與下載請求.這個其實不難,就是特別多奇奇怪怪的坑,因此,希望看到的,不要像筆者這樣踩的那么痛苦了...
這次用一個全新的例子寫博客,因此從新建工程開始:
加入
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:usesCleartextTraffic="true">
網絡權限,讀寫SD卡權限,當然還有允許http請求的權限.
加入
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
這個是支持JDK8的.
還有這兩個okhttp與conscrypt,最新版本okhttp可以在這里查看,最新版本conscrypt在這里:
implementation 'com.squareup.okhttp3:okhttp:4.3.1'
implementation 'org.conscrypt:conscrypt-android:2.2.1'
手動上傳一些文件到AVD設備,為下一步選擇與上傳文件做準備,先把這個窗口工具欄打開:
打開后,打開在右側欄中的Device File Explorer:
然后選擇sdcard文件夾上傳文件即可,其他文件夾一般沒有權限.
添加三個button(上傳/下載/選擇文件),一個EditText(上傳文件名與下載文件名),一個ImageView(顯示下載的圖片).
直接拖放改一下id.
首先申請動態讀寫文件權限(其實選擇文件只需要讀權限,因為后面的下載需要寫權限所以這里就一起申請了):
使用checkSelfPermission檢查權限,參數為一個Context與String,String表示相應的權限,如果有了這個權限就會返回
PackageManager.PERMISSION_GRANTED
沒有就會返回
PackageManager.PERMISSION_DENIED
沒有就利用requestPermissions()申請,參數為Content,String[],int,String[]表示要申請的所有權限,int是一個requestCode.
新建一個Intent后,設置選擇類型,然后就重寫onActivityResult:
這是簡化了的處理,因為選擇的是圖片,選擇其他文件的話可以參照這里.
其中path是選擇的文件的路徑,可能你會問:
String path = dir.toString().substring(0,dir.toString().indexOf("0")+2) +
DocumentsContract.getDocumentId(uri).split(":")[1];
這個是怎么來的,其實是拼湊過來的,因為這是圖片,是這個的簡化版:
(博客在這里)
參數為文件路徑與文件名,然后使用OkHttpClient,因為是文件,用的body是MultipartBody,增加一個叫file的FormDataPart與一個叫filename的FormDataPart.然后使用execute()發送請求,body()獲取響應內容,這里假設了后端響應一個布爾,表示上傳成功或失敗,url的話使用了本地的路徑,注意不能是localhost,使用內網ip,然后還要與后端對應.
參數為一個文件名,根據這個文件名返回對應的文件,返回一個File,這里請求體可以選擇FormBody或MultipartBody,因為這是一個文件名參數,這里筆者為了統一就選擇了MultipartBody,使用FormBody的話,只需要將RequestBody的那一行改為:
RequestBody body = new FormBody.Builder().add("filename",filename).build();
有了請求體后發送請求獲取響應體,進而獲取輸入流,然后首先需要判斷是否為空,但不能直接這樣判斷:
inputStream == null
因為后端是這樣的:
從響應體獲取的inputStream肯定不為null,需要先進行一次讀取(也就是判斷里面的文件是否為null),若為null的話刪除這個文件,不為null的話繼續讀取并寫入文件.
用的是IDEA,其他IDE請自行搜索如何新建一個SpringBoot工程.
打包的話可以jar或war,不用部署的話jar即可,要部署的話后期也可以改成war.
兩個,一個Spring Web,用于MVC等,一個模板引擎,用于顯示視圖,如果不需要顯示可以不選.
作為一個示例demo,屬性就直接在application.properties中配置了,實際情況請在相應的配置文件中配置相應屬性.
需要配置上傳文件的大小限制與上傳文件夾的路徑.
這里其實不需要干什么,只是如果下載依賴慢的話,可以這樣設置settings.xml文件,在<mirrors>中加上:
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
<mirror>
<id>uk</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://uk.maven.org/maven2/</url>
</mirror>
<mirror>
<id>CN</id>
<name>OSChina Central</name>
<url>http://maven.oschina.net/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
<mirror>
<id>nexus</id>
<name>internal nexus repository</name>
<!-- <url>http://192.168.1.100:8081/nexus/content/groups/public/</url>-->
<url>http://repo.maven.apache.org/maven2</url>
<mirrorOf>central</mirrorOf>
</mirror>
windows用戶的話這個文件在
C:\Users\{username}\.m2\settings.xml
linux的話在
~/.m2/settings.xml
首先對應的post映射路徑為/upload,與android端的路徑對應,然后需要一個表示文件的MultipartFile與一個表示文件名的String,判斷這兩個是否為空后,如果上傳的文件夾不存在則先創建,存在的話直接進行復制,然后根據復制成功或失敗返回布爾值.復制使用了Files.copy(),第一個InputStream為上傳文件的輸入流,第二個Path為存儲文件的路徑,resolve(filename)相當于在上傳目錄下的filename文件.輸出的話建議使用日志代替.
下載的話可以選擇使用get或post請求,這里選擇了post請求,因為android端是post請求,需要對應.get請求的話可以從瀏覽器發起.
首先根據文件名獲取對應文件,判斷文件是否存在后返回一個ResponseEntity,需要設定content-type與body,content-type根據需要設置即可,這里是圖片,默認.jpg或.png,body的話使用FileSystemResource,直接new一個放進body即可.
如果不存在相應的文件則返回null,這里需要注意一下前端的判斷,不能直接判斷ResponseBody是否為null.
postman只能測試與后端的連接,上傳等是否有問題,可以用來定位后端的問題.
再Headers中設置了Content-Type為multipart/form-data后:
在body添加一個叫file的文件與一個叫filename的字符串表示文件名:
發送,返回true.
服務器端有輸出提示:
查看文件夾:
把file參數關掉,保留filename,修改路徑.
然后發送,postman可以直接顯示圖片:
后端提示:
查看文件夾:
輸入文件名后直接下載:
默認的話是放在這里,按需要更改位置即可,注意加上寫權限:
若看不到文件選擇synchronize即可.
服務器用的是tomcat,需要修改一些Spring Boot的部分.
pom.xml中jar改成war.
pom.xml加入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
修改Main類,讓其繼承SpringBootServletInitializer,重載configure(),同時main()保持不變.
修改前:
修改后:
這個按需要修改即可,在這里不需要,注意就是@PostMapping,@GetMapping等都是相對于
tomcat/webapps/項目/
目錄下的.
build加上<finalName>.
打包后的文件放在target下,使用scp上傳即可,這里是本地的tomcat,就這接移動war了.
開啟tomcat,雙擊startup.bat即可.
linux的話:
cd xxxx/tomcat/bin
./startup.sh
在測試前需要確保沒有占用相應端口,默認8080,也就是說,如果不改端口的話,需要關閉IDEA運行中的SpringBoot應用.
上傳測試,注意需要改路徑,加上打包項目名,ip的話可以使用localhost或者內網ip.
服務器這邊收到了,因為上傳路徑只是直接寫名字,因此會與startup.bat同一路徑.
下載測試:
服務器的輸出:
android端需要修改路徑即可,加上war打包的名字.
這里打包的名字是kr,直接加上即可.
上傳那里也是要加上,然后:
服務器的輸出:
查看文件:
android需要讀權限才能讀取文件并上傳,需要寫權限才能保存從服務器返回的文件,在AndroidManifest.xml中加入:
<manifest>...
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>...</application>
這是外部設備的讀寫權限.當然,加入這個還不能訪問,因為,android6.0以后還需要動態申請權限,所以:
String [] permission = new String[]{
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"
};
if(
ActivityCompat.checkSelfPermission(this,permission[0]) != PackageManager.PERMISSION_GRANTED
||
ActivityCompat.checkSelfPermission(this,permission[1]) != PackageManager.PERMISSION_DENIED
)
{
ActivityCompat.requestPermissions(this,permission,1);
}
需要保證下面幾個路徑正確,還有可讀,可寫等:
若前端是這樣寫的,在工具類中返回了之后Response已經關閉,因此需要讀取輸入流之類的需要先讀取再返回,而不是返回一個ResponseBody或InputStream進行讀取,否則會提示"closed".
Android P開始默認禁用http,因此可以使用https或者在AndroidManifest.xml中允許http連接:
<application android:usesCleartextTraffic="true">
網絡請求不能在主線程中,新開一個線程即可.
若檢查過了服務器與android端沒問題,那么有可能是AVD的問題,解決方法很簡單,卸載,重啟AVD,注意一定要卸載再重啟.
在本地測試的話后端可以直接localhost,在android端不能直接localhost,可以使用ipconfig或ifconfig查看內網ip,輸入內網ip即可.
若在服務器上測試直接使用服務器ip.
對于前端,應該判斷存儲路徑是否為空,是否為null等,再傳給后端,對于后端,要判斷文件是否存在等,不存在就返回null,這時又需要前端進行判斷返回的null,在下載文件時,雖然對不存在的文件后端返回null,但是,前端收到的是一個InputStream,不能直接判斷是否為null,需要先讀取一次,再進行剩下的讀取:
github
碼云
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。