Okhttp+Tomcat+struts(上传图片)+Servlet(下载图片)
前言
在Android项目开发中,少不了需要将用户上传的图片保存,比如用户上传更新头像。如果不把图片保存到服务器,而是保存到本地,那么用户删除本地数据(如卸载应用,再下载回),用户的图片数据就会丢失,并且用户也无法访问到其他用户的图片数据,因为数据保存在本地是无法实现网络共享。
我曾将图片转为base64的String类型,上传服务器,存储在数据库,后来,由于数据库查询效率实在是低,并且还存不了高清大图,就放弃了这个方式。现在想想,当时真的笨,
作者做的这个只是个Demo,服务器没有用云服务器,而是基于TomCat搭建的本地服务器,要是有任何不合理的地方,欢迎指出。
服务器端
项目目录:
03.jsp表单信息
<body>
<h2> 文件上传 </h2>
<form action="upload.action" method="post" enctype="multipart/form-data">
上传文件:<input type="file" name="upload"><br>
<input type="submit" value="提交">${result}
</form>
</body>
error.jsp上传图片错误跳转的界面
<body>
<h2>上传失败!</h2>
<s:fielderror></s:fielderror>
</body>
web.xml配置
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>DownloadServlet</servlet-name>
<servlet-class>com.ilikexy.DownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadServlet</servlet-name>
<url-pattern>/downloadServlet.do</url-pattern>
</servlet-mapping>
struts.xml配置
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<constant name="struts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-default">
<action name="upload" class="com.ilikexy.FileUploadAction">
<result>/jsp/03.jsp</result>
<result name="input">/jsp/error.jsp</result>
<!-- 配置拦截器限制上传文件类型及大小 -->
<interceptor-ref name="fileUpload">
<param name="allowedTypes">image/*</param>
<param name="maximumSize">2M</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
</package>
</struts>
上传图片的Action处理类FileUploadAction.java
public class FileUploadAction extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 1L;
//图片
private List<File> upload;
private List<String> uploadContentType;
private List<String> uploadFileName;
//
private String result;
@Override
public String execute() throws Exception {
System.out.println("已经触发了上传函数");
String path = ServletActionContext.getServletContext().getRealPath("/images");
File file = new File(path);
if(!file.exists()){//要是文件夹不存在就创建文件夹
file.mkdir();
}
//循环将批量上传的文件保存到本地
for(int i=0;i<upload.size();i++){
File fileer = new File(file,uploadFileName.get(i));//文件 = 文件夹 + 文件名
FileUtils.copyFile(upload.get(i),fileer);//用FileUtils复制并写入文件,两个参数,一个是文件, 一个是空文件
System.out.println(""+fileer.getAbsolutePath());
}
result="上传成功!";
return SUCCESS;
}
public List<File> getUpload() {
return upload;
}
public void setUpload(List<File> upload) {
this.upload = upload;
}
public List<String> getUploadContentType() {
return uploadContentType;
}
public void setUploadContentType(List<String> uploadContentType) {
this.uploadContentType = uploadContentType;
}
public List<String> getUploadFileName() {
return uploadFileName;
}
public void setUploadFileName(List<String> uploadFileName) {
this.uploadFileName = uploadFileName;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
下载文件的Servlet类 DownloadServlet.java
public class DownloadServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取文件下载路径
String path = getServletContext().getRealPath("/") + "images/";
String filename = req.getParameter("filename");
File file = new File(path + filename);
if(file.exists()){
//设置相应类型application/octet-stream
resp.setContentType("application/x-msdownload");
//设置头信息
resp.setHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
InputStream inputStream = new FileInputStream(file);
ServletOutputStream ouputStream = resp.getOutputStream();
byte b[] = new byte[1024];
int n ;
while((n = inputStream.read(b)) != -1){
ouputStream.write(b,0,n);//以字符的形式传输
}
//关闭流、释放资源
ouputStream.close();
inputStream.close();
}else{
System.out.println("文件不存在下载失败!");
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.write("文件不存在下载失败!");
writer.close();
}
}
测试一下效果
然后我们就可以在输出的路径里找到这个张图片:
既然服务器端的功能已经实现了,那么就看一下Android客户端,Okhttp如何post上传图片,如何get请求获取图片:
上传图片关键代码:
//网络请求,将图片数据发给服务器
public void sendToServer(){
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient client = new OkHttpClient();
//所有图片类型
MediaType mediaType=MediaType.Companion.parse("image/*; charset=utf-8");
//第一层,说明数据为文件,以及文件类型
RequestBody fileBody=RequestBody.Companion.create(fileer,mediaType);
//第二层,指明服务表单的键名,文件名,文件体
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("upload",fileer.getName(),fileBody)
.build();
Request request = new Request.Builder()
.url("http://192.168.3.6:8888/DemoStrut/upload.action")
.post(requestBody)
.build();
//发送请求
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure( Call call, IOException e) {
//网络故障
Looper.prepare();
Toast.makeText(MainActivity.this,"网络故障!",Toast.LENGTH_SHORT).show();
Looper.loop();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.body()!=null){
Looper.prepare();
//Toast.makeText(MainActivity.this,response.body().string(),Toast.LENGTH_SHORT).show();
Log.d("theresult",response.body().string());
Looper.loop();
}
}
});
}
}).start();
}
下载图片关键代码:
//网络请求,下载图片
public void downloadFromServer(){
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://192.168.3.6:8888/DemoStrut/downloadServlet.do?filename=wenzhang6.png")
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure( Call call, IOException e) {
//网络故障
Looper.prepare();
Toast.makeText(MainActivity.this,"网络故障!",Toast.LENGTH_SHORT).show();
Looper.loop();
}
@Override
public void onResponse( Call call, Response response) throws IOException {
//把接收到的流转化为bitmap
InputStream in = response.body().byteStream();
Bitmap bitmap = BitmapFactory.decodeStream(in);
runOnUiThread(new Runnable() {//子线程更新ui
@Override
public void run() {
//这个是图片控件
picturehere.setImageBitmap(bitmap);
}
});
}
});
}
}).start();
}
效果
有任何问题欢迎评论区讨论,一起加油,谢谢了。