千家信息网

android+spring boot 选择,上传,下载文件

发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,1 概述前端android,上传与下载文件,使用OkHttp处理请求,后端使用spring boot+MVC,处理android发送来的上传与下载请求.这个其实不难,就是特别多奇奇怪怪的坑,因此,希望
千家信息网最后更新 2025年12月02日android+spring boot 选择,上传,下载文件

1 概述

前端android,上传与下载文件,使用OkHttp处理请求,后端使用spring boot+MVC,处理android发送来的上传与下载请求.这个其实不难,就是特别多奇奇怪怪的坑,因此,希望看到的,不要像笔者这样踩的那么痛苦了...

2 环境

  • win10
  • Spring Boot 2.2.2 RELEASE
  • IDEA 2019.3.1
  • Android Studio 3.6RC1
  • Tomcat 9.0.30

3 android

3.1 准备工作

3.1.1 新建工程

这次用一个全新的例子写博客,因此从新建工程开始:

3.1.2 AndroidManifest.xml

加入

网络权限,读写SD卡权限,当然还有允许http请求的权限.

3.1.3 build.gradle

加入

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'

3.1.4 上传文件

手动上传一些文件到AVD设备,为下一步选择与上传文件做准备,先把这个窗口工具栏打开:

打开后,打开在右侧栏中的Device File Explorer:

然后选择sdcard文件夹上传文件即可,其他文件夹一般没有权限.

3.1.5 布局

添加三个button(上传/下载/选择文件),一个EditText(上传文件名与下载文件名),一个ImageView(显示下载的图片).

直接拖放改一下id.

3.2 选择文件

3.2.1 申请权限

首先申请动态读写文件权限(其实选择文件只需要读权限,因为后面的下载需要写权限所以这里就一起申请了):

使用checkSelfPermission检查权限,参数为一个Context与String,String表示相应的权限,如果有了这个权限就会返回

PackageManager.PERMISSION_GRANTED

没有就会返回

PackageManager.PERMISSION_DENIED

没有就利用requestPermissions()申请,参数为Content,String[],int,String[]表示要申请的所有权限,int是一个requestCode.

3.2.2 Intent选择文件

新建一个Intent后,设置选择类型,然后就重写onActivityResult:

这是简化了的处理,因为选择的是图片,选择其他文件的话可以参照这里.

其中path是选择的文件的路径,可能你会问:

String path = dir.toString().substring(0,dir.toString().indexOf("0")+2) +    DocumentsContract.getDocumentId(uri).split(":")[1];

这个是怎么来的,其实是拼凑过来的,因为这是图片,是这个的简化版:

(博客在这里)

3.3 上传文件

参数为文件路径与文件名,然后使用OkHttpClient,因为是文件,用的body是MultipartBody,增加一个叫file的FormDataPart与一个叫filename的FormDataPart.然后使用execute()发送请求,body()获取响应内容,这里假设了后端响应一个布尔,表示上传成功或失败,url的话使用了本地的路径,注意不能是localhost,使用内网ip,然后还要与后端对应.

3.4 下载文件

参数为一个文件名,根据这个文件名返回对应的文件,返回一个File,这里请求体可以选择FormBody或MultipartBody,因为这是一个文件名参数,这里笔者为了统一就选择了MultipartBody,使用FormBody的话,只需要将RequestBody的那一行改为:

RequestBody body = new FormBody.Builder().add("filename",filename).build();

有了请求体后发送请求获取响应体,进而获取输入流,然后首先需要判断是否为空,但不能直接这样判断:

inputStream == null

因为后端是这样的:

从响应体获取的inputStream肯定不为null,需要先进行一次读取(也就是判断里面的文件是否为null),若为null的话删除这个文件,不为null的话继续读取并写入文件.

4 Spring Boot

4.1 准备工作

用的是IDEA,其他IDE请自行搜索如何新建一个SpringBoot工程.

4.1.1 新建工程

打包的话可以jar或war,不用部署的话jar即可,要部署的话后期也可以改成war.

两个,一个Spring Web,用于MVC等,一个模板引擎,用于显示视图,如果不需要显示可以不选.

4.1.2 application.properties

作为一个示例demo,属性就直接在application.properties中配置了,实际情况请在相应的配置文件中配置相应属性.

需要配置上传文件的大小限制与上传文件夹的路径.

4.1.3 pom.xml

这里其实不需要干什么,只是如果下载依赖慢的话,可以这样设置settings.xml文件,在中加上:

    alimaven    aliyun maven    http://maven.aliyun.com/nexus/content/groups/public/    central    uk    central    Human Readable Name for this Mirror.    http://uk.maven.org/maven2/    CN    OSChina Central    http://maven.oschina.net/content/groups/public/    central    nexus    internal nexus repository        http://repo.maven.apache.org/maven2    central

windows用户的话这个文件在

C:\Users\{username}\.m2\settings.xml

linux的话在

~/.m2/settings.xml

4.2 处理上传文件

首先对应的post映射路径为/upload,与android端的路径对应,然后需要一个表示文件的MultipartFile与一个表示文件名的String,判断这两个是否为空后,如果上传的文件夹不存在则先创建,存在的话直接进行复制,然后根据复制成功或失败返回布尔值.复制使用了Files.copy(),第一个InputStream为上传文件的输入流,第二个Path为存储文件的路径,resolve(filename)相当于在上传目录下的filename文件.输出的话建议使用日志代替.

4.3 处理下载文件

下载的话可以选择使用get或post请求,这里选择了post请求,因为android端是post请求,需要对应.get请求的话可以从浏览器发起.

首先根据文件名获取对应文件,判断文件是否存在后返回一个ResponseEntity,需要设定content-type与body,content-type根据需要设置即可,这里是图片,默认.jpg或.png,body的话使用FileSystemResource,直接new一个放进body即可.

如果不存在相应的文件则返回null,这里需要注意一下前端的判断,不能直接判断ResponseBody是否为null.

5 测试

5.1 postman测试

postman只能测试与后端的连接,上传等是否有问题,可以用来定位后端的问题.

5.1.1 上传测试

再Headers中设置了Content-Type为multipart/form-data后:

在body添加一个叫file的文件与一个叫filename的字符串表示文件名:

发送,返回true.

服务器端有输出提示:

查看文件夹:

5.1.2 下载测试

把file参数关掉,保留filename,修改路径.

然后发送,postman可以直接显示图片:

5.2 android端测试

5.2.1 上传测试

后端提示:

查看文件夹:

5.2.2 下载测试

输入文件名后直接下载:

默认的话是放在这里,按需要更改位置即可,注意加上写权限:

若看不到文件选择synchronize即可.

6 部署到服务器

服务器用的是tomcat,需要修改一些Spring Boot的部分.

6.1 部署

6.1.1 改变打包方式

pom.xml中jar改成war.

6.1.2 去除tomcat依赖

pom.xml加入:

    org.springframework.boot    spring-boot-starter-tomcat    provided

6.1.3 修改Main

修改Main类,让其继承SpringBootServletInitializer,重载configure(),同时main()保持不变.

修改前:

修改后:

6.1.4 修改路径

这个按需要修改即可,在这里不需要,注意就是@PostMapping,@GetMapping等都是相对于

tomcat/webapps/项目/

目录下的.

6.1.5 设置打包名字

build加上.

6.1.6 打包

6.1.7 上传到服务器

打包后的文件放在target下,使用scp上传即可,这里是本地的tomcat,就这接移动war了.

6.1.8 运行

开启tomcat,双击startup.bat即可.

linux的话:

cd xxxx/tomcat/bin./startup.sh

6.2 测试

在测试前需要确保没有占用相应端口,默认8080,也就是说,如果不改端口的话,需要关闭IDEA运行中的SpringBoot应用.

6.2.1 postman测试

上传测试,注意需要改路径,加上打包项目名,ip的话可以使用localhost或者内网ip.

服务器这边收到了,因为上传路径只是直接写名字,因此会与startup.bat同一路径.

下载测试:

服务器的输出:

6.2.2 android端测试

android端需要修改路径即可,加上war打包的名字.

这里打包的名字是kr,直接加上即可.

上传那里也是要加上,然后:

服务器的输出:

查看文件:

7 最最最喜欢的

7.1 权限

android需要读权限才能读取文件并上传,需要写权限才能保存从服务器返回的文件,在AndroidManifest.xml中加入:

......

这是外部设备的读写权限.当然,加入这个还不能访问,因为,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);}

7.2 路径

需要保证下面几个路径正确,还有可读,可写等:

  • url路径不能错.
  • 前端上传文件的路径.
  • 后端接收前端上传文件的路径.
  • 后端发送前端需要下载的文件的路径.
  • 前端接收下载文件的路径.

7.3 有关http的问题

7.3.1 okhttp的stream关闭

若前端是这样写的,在工具类中返回了之后Response已经关闭,因此需要读取输入流之类的需要先读取再返回,而不是返回一个ResponseBody或InputStream进行读取,否则会提示"closed".

7.3.2 http

Android P开始默认禁用http,因此可以使用https或者在AndroidManifest.xml中允许http连接:

7.3.3 线程

网络请求不能在主线程中,新开一个线程即可.

7.3.4 AVD

若检查过了服务器与android端没问题,那么有可能是AVD的问题,解决方法很简单,卸载,重启AVD,注意一定要卸载再重启.

7.4 ip

在本地测试的话后端可以直接localhost,在android端不能直接localhost,可以使用ipconfig或ifconfig查看内网ip,输入内网ip即可.

若在服务器上测试直接使用服务器ip.

7.5 判空处理

对于前端,应该判断存储路径是否为空,是否为null等,再传给后端,对于后端,要判断文件是否存在等,不存在就返回null,这时又需要前端进行判断返回的null,在下载文件时,虽然对不存在的文件后端返回null,但是,前端收到的是一个InputStream,不能直接判断是否为null,需要先读取一次,再进行剩下的读取:

8 源码

github

码云

文件 路径 权限 测试 选择 服务 前端 文件名 服务器 参数 文件夹 处理 图片 问题 输入 名字 工程 这是 输出 配置 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 田言是什么公司的啊软件开发 网络安全对用户应急的预案 博雅数据库河北高校 多种软件开发 pspice怎么添加数据库 h3c服务器管理口装系统 网络安全教育的对策 数据库技术与云计算的关系 服务器的安全需求分析报告 电脑服务器已满怎么办 公安网络安全大检查方案 国内数据库技术历史 因服务器发送了无效应答 app和网页能共用一个服务器吗 汽车电子总线网络技术线束 高质量的软件开发之道 杭州绿盟网络安全工程师人员名单 串口通信的网络安全 h5创建本地数据库 通友财务管理软件连接不到服务器 泰安联想服务器代理 ssm 添加对象数据库 互程网络技术有限公司招聘 合发网络技术青岛即墨分公司 平安银行网络安全视频 国家实行网络安全高效制度 网络安全法的突出亮点 软件开发自己能学吗 衢州java软件开发计划 服务器存储数据用关系型数据库
0