最近写的app项目涉及到用户更换头像,就涉及到文件上传,在网上找了很多教程,最后选了一个看起来比较接地气的,伪造post文件上传
原博客地址:https://blog.csdn.net/anan890624/article/details/52510299
博客好像并没有给出服务器端的代码吗,因为是post提交文件上传,正好和我之前做的基于表单的文件上传吻合,服务器端参考的是http://www.360doc.com/content/14/0506/15/7532272_375213559.shtml这篇文章的代码。
自己写的服务器端代码:
package com.servlet;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.RequestContext;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
import com.bean.Organize;
import com.service.OrganizeService;
import com.service.UserService;
import com.utils.Tool;
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
DiskFileItemFactory factory = new DiskFileItemFactory();
String path = null;
path = this.getServletContext().getRealPath("/upload");
System.out.println(path);
ServletFileUpload servletFileUpload = new ServletFileUpload();
servletFileUpload.setFileItemFactory(factory);
servletFileUpload.setFileSizeMax(1000*1000);
servletFileUpload.setHeaderEncoding("UTF-8");
String id = request.getHeader("id");
System.out.println("id="+id);
if(!ServletFileUpload.isMultipartContent(request)){
return;
}
try {
List<FileItem> fileItems = servletFileUpload.parseRequest(new ServletRequestContext(request));
FileItem fileItem = null;
Iterator<FileItem> it = fileItems.iterator();
while(it.hasNext()) {
FileItem item = it.next();
if(item.isFormField()) {
String fieldName = item.getFieldName();
String value = item.getString("UTF-8");
System.out.println("name="+fieldName+",value="+value);
}else {
fileItem = item;
File uploadDir = new File(path);
if(!uploadDir.exists()) {
uploadDir.mkdirs();
}
path = path + "/" +(int)(Math.random()*10000);
File file = new File(path+".jpg");
path = file.getAbsolutePath();
InputStream in = fileItem.getInputStream();
OutputStream out = new FileOutputStream(file);
byte buffer[] = new byte[1024];
int len=0;
while((len=in.read(buffer))>0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
}
}
//更改地址为网络地址
int begin=path.indexOf("ClubServer");
int last=path.length();
path = Tool.ip+path.substring(begin,last);
System.out.println(path);
//保存上传的图片地址
if(id.startsWith("user:")) {
id = id.substring(5);
System.out.println(id);
UserService us = new UserService();
boolean flag = us.updateHeadImg(id,path);
response.getWriter().write(flag?path:"0");
}
if(id.startsWith("org:")) {
id = id.substring(4);
id = new String(id.getBytes(Tool.getEncoding(id)),"UTF-8");
System.out.println(id+":"+Tool.getEncoding(id));
OrganizeService os = new OrganizeService();
boolean flag = os.updateOrganizeImg(id,path);
response.getWriter().write(flag?path:"0");
}
} catch (Exception e) {
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
里面除了文件上传外,加了一些将图片地址和其他信息(user_id等)存入数据库的代码。存的时候地址记得转换成网络地址。
然后就是android端上传代码:
package com.example.mypplication;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import bean.User;
import utils.Tool;
import utils.UserDataOp;
public class ChangeHeadImgActivity extends Activity {
private final int OPEN_ALBUM_FLAG = 1023; //打开相册
private final int OPEN_CAMERA_FLAG = 1024; //打开相机
private ImageView mShowIV;
private String mSaveDir;// 拍照存放的文件夹名字
private String mFileName;// 拍照存放的文件的名字
private String user_id;
private TextView tv_info;
private String url;
private HttpClient httpClient;
private UserDataOp ud;
private String img_path;
private Bitmap bitmap;
// 要上传的本地文件路径
private String uploadFile;
// 上传到服务器的指定位置
private String actionUrl = Tool.ip+Tool.webName+"UploadServlet";
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.changeheadimg);
mShowIV = (ImageView) findViewById(R.id.iv_head);
tv_info = (TextView) findViewById(R.id.tv_info);
}
public void changeimg(View v) {
uploadFile = this.getFilesDir().getAbsolutePath();
Intent intent;
intent = new Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(intent, OPEN_ALBUM_FLAG);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
File file;
Bitmap bitmap;
OutputStream outputStream;
if (resultCode == RESULT_OK) {
Uri originUri = data.getData();
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(originUri, proj, null, null, null);
int columnIndex = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(columnIndex);
uploadFile = path;
mShowIV.setImageURI(originUri);
bitmap = getCompressBitmap(path);
//android6.0需动态获取外部存储访问权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && this.checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 1);
}
// mShowIV.setImageBitmap(bitmap);//将选中的图片展示出来
/* 创建一个新的文件,存放压缩过的bitmap,用于发送给服务器 */
String saveDir = uploadFile;
File dir = new File(saveDir);
if (!dir.exists()) {
dir.mkdir();
}
// 创建一个临时文件用来存放图片
String fileName = "tmp.jpg";
file = new File(this.getFilesDir().getAbsolutePath(), fileName);
if (file.exists()) {
file.delete();
}
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
file.createNewFile();
outputStream = new FileOutputStream(file);
// //将bitmap写入file
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
/* 到这里已经成功将bitmap写入file了,此时可以将file或者流发送给服务器了 */
} catch (Exception e) {
e.printStackTrace();
}
uploadFile = file.getAbsolutePath();
// tv_info.setText(path);
new Thread(new UploadThread()).start();
}
}
public class UploadThread implements Runnable {
@Override
public void run() {
upload();
}
}
public void upload() {
String path="";
String end = "\r\n";
String twoHyphens = "--";
String boundary = "******";
URL url;
try {
url = new URL(actionUrl);
HttpURLConnection httpURLConnection = (HttpURLConnection) url
.openConnection();
httpURLConnection.setChunkedStreamingMode(128 * 1024);// 128K
// 允许输入输出流
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
httpURLConnection.setUseCaches(false);
// 使用POST方法
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
httpURLConnection.setRequestProperty("Charset", "UTF-8");
httpURLConnection.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
//将id(用户id格式 user:+id 社团id格式 org:+id)传到服务器
httpURLConnection.setRequestProperty("id", user_id);
DataOutputStream dos = new DataOutputStream(
httpURLConnection.getOutputStream());
dos.writeBytes(twoHyphens + boundary + end);
dos.writeBytes("Content-Disposition: form-data; name=\"uploadfile\"; filename=\""
+ uploadFile.substring(uploadFile.lastIndexOf("/") + 1)
+ "\"" + end);
dos.writeBytes(end);
FileInputStream fis = new FileInputStream(uploadFile);
byte[] buffer = new byte[8192]; // 8k
int count = 0;
// 读取文件
while ((count = fis.read(buffer)) != -1) {
dos.write(buffer, 0, count);
}
fis.close();
dos.writeBytes(end);
dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
dos.flush();
InputStream is = httpURLConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "utf-8");
BufferedReader br = new BufferedReader(isr);
String result = br.readLine();
Log.i("tag", result);
dos.close();
is.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Bitmap getCompressBitmap(String path) {
int BASE_SIZE = 400;// 需要压缩到的最小宽高
Bitmap bitmap;
BitmapFactory.Options options = new BitmapFactory.Options();
// 只计算几何尺寸不返回bitmap,这样不会占用内存
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
int width = options.outWidth;
int height = options.outHeight;
int min = width < height ? width : height;
int rate = min / BASE_SIZE;// 压缩倍率
if (rate < 1)
rate = 1;
options.inSampleSize = rate;
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(path, options);
return bitmap;
}
}
直接全粘过来,最初只写了upload()方法,在模拟器上创建一个文件顺利传到了服务器,写完发现,真机没法直接创建文件...完成图片上传还得调用相册程序,这里参考了https://blog.csdn.net/nnmmbb/article/details/16949349,调用相机程序代码我就删了,觉得太麻烦,只做了调用相册程序。同时它还提供了getCompressBitmap()方法压缩图片,可以自己修改要压缩的尺寸,怎么突然就自动换字体了。。。然后androidmanifest.xml一定要记得添加网络权限和外部存储读写权限,我刚开始就忘了加,还在那一直测,奇怪他没反应。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
好不容易做好这一切,用eclipse API19完美传送图片到服务器,但当我把代码转到android studio使用的API28时,又传不了了(摊手),弄了好久,网上查发现,api>23要手动获取读写外部存储权限,wtf,于是网上找了代码,加进去(上边已经加进去了),才算是终于完成了,心好累。。。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && this.checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 1);
}
最后还有,要将用户信息连带图片一起传到服务器,才能在数据库将图片与用户匹配
httpURLConnection.setRequestProperty("id", user_id);
因为http协议api什么的还不太熟,我是直接给他加到请求头里了。。。
最后就是不知道为什么Tomcat服务器老是自动删除我创建的uolpad文件夹,哎~