从app上传图片到php,再上传到java后端服务器的方法一览
在现在的网络开发中,上传图片类的需求实在是太普通不过了,但是对于怎么样做到上传图片,对于刚开始建立项目的时候,还是有点不知所措的。也许有幸,我们做的项目是之前已经有人写过类似的用例了,那么我们只需要依葫芦画瓢就行了。
好好了解下图片上传(文件上传)的方式,对于认知的提升还是有好处的。而且说不定哪天你就有个这样的需求呢,这里是一条龙上传。
本文就一个从app到php层,再到java层的流程,演译下整个上传图片的流程吧。
一、app端获取用户选择的图片,转化为输入流,上传至php前端接口:
package com.dia.ration; import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID; /**
* 上传文件到服务器类
*/
public class UploadUtil {
private static final String TAG = "uploadFile";
private static final int TIME_OUT = 10 * 1000; // 超时时间
private static final String CHARSET = "utf-8"; // 设置编码
/**
* Android上传文件到服务端
*
* @param file 需要上传的文件
* @param RequestURL 请求的rul
* @return 返回响应的内容
*/
public static String uploadFile(File file, String RequestURL) {
String result = null;
String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成
String PREFIX = "--", LINE_END = "\r\n";
String CONTENT_TYPE = "multipart/form-data"; // 内容类型
try {
URL url = new URL(RequestURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(TIME_OUT);
conn.setConnectTimeout(TIME_OUT);
conn.setDoInput(true); // 允许输入流
conn.setDoOutput(true); // 允许输出流
conn.setUseCaches(false); // 不允许使用缓存
conn.setRequestMethod("POST"); // 请求方式
conn.setRequestProperty("Charset", CHARSET); // 设置编码
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
if (file != null) {
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
StringBuffer sb = new StringBuffer();
sb.append(PREFIX);
sb.append(BOUNDARY);
sb.append(LINE_END);
/**
* 这里重点注意: name里面的值为服务端需要key 只有这个key 才可以得到对应的文件
* filename是文件的名字,包含后缀名的 比如:abc.png
*/
sb.append("Content-Disposition: form-data; name=\"uploadfile\"; filename=\""
+ file.getName() + "\"" + LINE_END);
sb.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINE_END);
sb.append(LINE_END);
dos.write(sb.toString().getBytes());
InputStream is = new FileInputStream(file);
byte[] bytes = new byte[1024];
int len = 0;
while ((len = is.read(bytes)) != -1) {
dos.write(bytes, 0, len);
}
is.close();
dos.write(LINE_END.getBytes());
byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
dos.write(end_data);
dos.flush();
InputStream input = conn.getInputStream();
StringBuffer sb1 = new StringBuffer();
int ss;
while ((ss = input.read()) != -1) {
sb1.append((char) ss);
}
result = sb1.toString();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* 通过拼接的方式构造请求内容,实现参数传输以及文件传输
*
* @param url Service net address
* @param params text content
* @param files pictures
* @return String result of Service response
* @throws IOException
*/
public static String post(String url, Map<String, String> params, Map<String, File> files)
throws IOException {
String BOUNDARY = UUID.randomUUID().toString();
String PREFIX = "--", LINEND = "\r\n";
String MULTIPART_FROM_DATA = "multipart/form-data";
String CHARSET = "UTF-8";
URL uri = new URL(url);
HttpURLConnection conn = (HttpURLConnection) uri.openConnection();
conn.setReadTimeout(10 * 1000); // 缓存的最长时间
conn.setDoInput(true); // 允许输入
conn.setDoOutput(true); // 允许输出
conn.setUseCaches(false); // 不允许使用缓存
conn.setRequestMethod("POST");
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("Charsert", "UTF-8");
conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY);
// 首先组拼文本类型的参数
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
sb.append(PREFIX);
sb.append(BOUNDARY);
sb.append(LINEND);
sb.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINEND);
sb.append("Content-Type: text/plain; charset=" + CHARSET + LINEND);
sb.append("Content-Transfer-Encoding: 8bit" + LINEND);
sb.append(LINEND);
sb.append(entry.getValue());
sb.append(LINEND);
}
DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
outStream.write(sb.toString().getBytes());
// 发送文件数据
if (files != null)
for (Map.Entry<String, File> file : files.entrySet()) {
StringBuilder sb1 = new StringBuilder();
sb1.append(PREFIX);
sb1.append(BOUNDARY);
sb1.append(LINEND);
sb1.append("Content-Disposition: form-data; name=\"uploadfile\"; filename=\""
+ file.getValue().getName() + "\"" + LINEND);
sb1.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINEND);
sb1.append(LINEND);
outStream.write(sb1.toString().getBytes());
InputStream is = new FileInputStream(file.getValue());
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
is.close();
outStream.write(LINEND.getBytes());
}
byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes();
outStream.write(end_data);
outStream.flush();
int res = conn.getResponseCode();
InputStream in = conn.getInputStream();
StringBuilder sb2 = new StringBuilder();
if (res == 200) {
int ch;
while ((ch = in.read()) != -1) {
sb2.append((char) ch);
}
}
outStream.close();
conn.disconnect();
return sb2.toString();
}
// 测试
public static void main(String[] args) throws IOException {
String requestURL = "sss";
final Map<String, String> params = new HashMap<String, String>();
params.put("send_userId", String.valueOf(1));
params.put("send_email", "ss@ss.com");
final Map<String, File> files = new HashMap<String, File>();
files.put("uploadfile", new File("/var/data/de.jpg"));
final String result = UploadUtil.post(requestURL, params, files);
System.out.println("result is: " + result);
}
}
二、php服务端接收文件,临时保存并继续上传至java后端:
1. 接收文件类
<?php
namespace App\Controller; use Action\RestAction;
use Api\UploadApi; class UserController extends RestAction
{
/**
* 用户头像上传
*/
public function set_avatar_post($code)
{
$uploadApi = new UploadApi();
$res = $uploadApi->uploads('avatar');
$filename = $res['data']; $result = $uploadApi->uploadAvatar($code, $filename);
@unlink($filename); //删除图片
if (!$result['status']) {
$this->response($result);
}
$avatar = A("Personal", "Api")->getAvatar($code);
$this->response($avatar);
}
}
2. 上传类
<?php
namespace Api\Action; class UploadApi
{
public function __construct()
{
//...
} public function curlGet($url, $param = array(), $timeout = 30, $ajaxResponseImmediately = true)
{
$opts = array(
CURLOPT_TIMEOUT => $timeout,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_HTTPHEADER => $header
);
switch (strtoupper($method)) {
// case 'POST':
// $opts[CURLOPT_URL] = $url;
// $opts[CURLOPT_POST] = 1;
// $opts[CURLOPT_POSTFIELDS] = $param;
// break;
default:
$opts[CURLOPT_URL] = $url . '?' . http_build_query($param);
break;
} $ch = curl_init();
curl_setopt_array($ch, $opts);
$result = curl_exec($ch); //记录请求日志
curl_close($ch);
return $result;
} public function curlPost($url, $param = array(), $timeout = 30, $ajaxResponseImmediately = true)
{
$opts = array(
CURLOPT_TIMEOUT => $timeout,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_HTTPHEADER => $header
);
switch (strtoupper($method)) {
case 'POST':
default:
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_POST] = 1;
$opts[CURLOPT_POSTFIELDS] = $param;
break;
// $opts[CURLOPT_URL] = $url . '?' . http_build_query($param);
// break;
} $ch = curl_init();
curl_setopt_array($ch, $opts);
$result = curl_exec($ch); $log_data['result'] = $result;
if (!empty($param)) $log_data['param'] = $param;
curl_close($ch);
return $result;
} public function uploads($param = '')
{
if ($param == '') {
$param = 'imgFile';
}
// 文件保存目录路径
$save_url = dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . "Uploads" . DIRECTORY_SEPARATOR;
// 定义允许上传的文件扩展名
$ext_arr = array(
'image' => array('gif', 'jpg', 'jpeg', 'png', 'bmp'),
);
// 最大文件大小
$max_size = 20 * 1024;
// PHP上传失败
if (!empty ($_FILES [$param] ['error'])) {
switch ($_FILES [$param] ['error']) {
case '1' :
$error = '超过php.ini允许的大小。';
break;
case '2' :
$error = '超过表单允许的大小。';
break;
case '3' :
$error = '图片只有部分被上传。';
break;
case '4' :
$error = '请选择图片。';
break;
case '6' :
$error = '找不到临时目录。';
break;
case '7' :
$error = '写文件到硬盘出错。';
break;
case '8' :
$error = 'File upload stopped by extension。';
break;
case '999' :
default :
$error = '未知错误。';
}
$result = array('status' => '0', 'error' => '111111', 'msg' => $error); }
// 有上传文件时
if (empty ($_FILES) === false) {
$file_name = $_FILES [$param] ['name'];// 原文件名
$tmp_name = $_FILES [$param] ['tmp_name'];// 服务器上临时文件名
$file_size = $_FILES [$param] ['size'];// 文件大小
// 检查文件名
if (!$file_name) {
$result = array('status' => '0', 'error' => '111111', 'msg' => '请选择文件');
}
// 检查是否已上传
if (@is_uploaded_file($tmp_name) === false) {
$result = array('status' => '0', 'error' => '111111', 'msg' => '上传失败');
}
// 检查文件大小
if ($file_size > $max_size) {
$result = array('status' => '0', 'error' => '111111', 'msg' => '');
}
// 检查目录名
$dir_name = empty ($_GET ['dir']) ? 'image' : trim($_GET ['dir']);
if (empty ($ext_arr [$dir_name])) {
$result = array('status' => '0', 'error' => '111111', 'msg' => '目录名不正确');
}
// 获得文件扩展名
$temp_arr = explode('.', $file_name);
$file_ext = array_pop($temp_arr);
$file_ext = trim($file_ext);
$file_ext = strtolower($file_ext);
// 检查扩展名
if (in_array($file_ext, $ext_arr [$dir_name]) === false) {
$result = array('status' => '0', 'error' => '111111', 'msg' => '上传文件扩展名是不允许的扩展名');
}
// 创建文件夹
if ($dir_name !== '') {
if (!file_exists($save_url)) {
mkdir($save_url);
}
}
$new_file_name = date('YmdHis') . '_' . rand(10000, 99999) . '.' . $file_ext;
$file_path = $save_url . $new_file_name;
if (move_uploaded_file($tmp_name, $file_path) === false) {
$result['msg'] = '上传文件失败';
$result = array('status' => '0', 'error' => '111111', 'msg' => '上传文件失败');
} else {
$result = array('status' => '1', 'error' => '000000', 'data' => $file_path);
}
@chmod($file_path, 0644);
return $result;
}
} public function uploadAvatar($code, $avatarImageName) {
$url = $this->getApiUrl(__METHOD__);
$data = array(
"code" => $code,
"ip" => $this->params['ip'],
"avatar" => !empty($avatarImageName) ? '@' . $avatarImageName : '',
);
$result = $this->curlPost($url, $data);
return $result;
}
}
这样,php就已经接收到了来自客户端的 图片上传了,并且已经上传到java后端服务器。
注意:这里有个坑,即php版本大于5.6以后,直接使用 @ 符号无法上传文件了,需要 加上一个安全选项:CURLOPT_SAFE_UPLOAD => false 才可以,或者使用5.6以的高级上传类上传文件:
curl_setopt(ch, CURLOPT_POSTFIELDS, [
'file' => new CURLFile(realpath('image.png')),
]);
三、java后端接收php上传的图片
package com.xx.c.action; import com.xx.core.pojo.Constants;
import com.xx.core.pojo.MicroException;
import com.xx.core.pojo.ResponseEntity;
import com.xx.core.web.spring.bind.annotation.ClientIP;
import com.xx.core.web.spring.bind.annotation.SessionUserId;
import com.xx.c.pojo.user.UpFileUrlBean;
import com.xx.c.service.user.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Iterator; @Controller
@RequestMapping(value = "upload")
public class UploadAction { @Resource(name = "userService")
private UserService userService; @RequestMapping(value = "/uploadAvatar", method = RequestMethod.POST, produces = "application/json")
@ResponseBody
public Object uploadAvatar(@RequestParam String code, @ClientIP String addIp, @SessionUserId Long userId,
@ModelAttribute UpFileUrlBean bean, HttpServletRequest request) throws MicroException {
bean.setAddIp(addIp);
bean.setUserId(userId); try {
// 转型为MultipartHttpRequest:
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
// 从其中取出一个文件 后续可使用spring 上传文件方法:file.transferTo(destFile);
MultipartFile file = null;
for (Iterator<String> it = multipartRequest.getFileNames(); it.hasNext();) {
file = multipartRequest.getFile((String) it.next());
}
userService.uploadAvatar(file, bean);
} catch (Exception e) {
throw new MicroException(Constants.ErrCode.UPLOAD_AVATAR_TO_SERVER_FAILED, Constants.ErrMsg.UPLOAD_AVATAR_TO_SERVER_FAILED, e);
} ResponseEntity ret = new ResponseEntity(Constants.System.OK);
return ret;
} }
至此,上传流程已经完成了。(当然,后续还可能使用其他上传,比如dubbo调用文件系统上传文件,调用第三方sdk上传到文件服务器。。。, 原理大抵一样,使用字节流进行传输,然后读取出来存储到文件)
一般为app写的接口中,都会涉及到加解密问题,此时,文件不应该算作加密的范畴,而应单独给一个字段。
从app上传图片到php,再上传到java后端服务器的方法一览的更多相关文章
- 从app上传图片到php,再上传到java后端服务器的方法一条龙服务
在现在的网络开发中,上传图片类的需求实在是太普通不过了,但是对于怎么样做到上传图片,对于刚开始建立项目的时候,还是有点不知所措的.也许有幸,我们做的项目是之前已经有人写过类似的用例了,那么我们只需要依 ...
- 将本地文件上传到指定的服务器(HttpWebRequest方法)
将本地文件上传到指定的服务器(HttpWebRequest方法),通过文件流,带文件名,同文件一同上传的表单文本域及值. ///<summary> /// 将本地文件上传到指定的服务器(H ...
- ASP.NET简单实现APP中用户个人头像上传和裁剪
最近有个微信项目的用户个人中心模块中,客户要求用户头像不仅仅只是上传图片,还需要能对图片进行裁剪.考虑到flash在IOS和Android上的兼容性问题,于是想着能从js这块入手,在网上发现了devo ...
- ueditor1.3.6jsp版在struts2应用中上传图片报"未找到上传文件"解决方案
摘要: ueditor1.3.6jsp版在struts2应用中上传图片报"未找到上传文件"解决方案 在struts2应用中使用ueditor富文本编辑器上传图片或者附件时,即使配置 ...
- asp.net core 通过ajax上传图片及wangEditor图片上传
asp.net core 通过ajax上传图片 .net core前端代码,因为是通过ajax调用,首先要保证ajax能调用后台代码,具体参见上一篇.net core 使用ajax调用后台代码. 前端 ...
- 图片上传oss--先拿server端签名再上传oss,返回id值
目前项目oss阿里云存储图片,图片上传主要步骤是:前端从服务端拿到签名signature,再上传到oss上busket里,上传成功返回图片id (imgId),最后再给server端: 注:官网上有个 ...
- 微信多媒体上传图片,创建卡券上传 LOGO
//*****************************************多媒体上传图片 begin******************************************** ...
- [Swift通天遁地]四、网络和线程-(9)上传图片并实时显示上传进度
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- Day12-微信小程序实战-交友小程序-搭建服务器与上传文件到后端
要搞一个小型的cms内容发布系统 因为小程序上线之后,直接对数据库进行操作的话,慧出问题的,所以一般都会做一个管理系统,让工作人员通过这个管理系统来对这个数据库进行增删改查 微信小程序其实给我们提供了 ...
随机推荐
- vector作为参数的三种传参方式
c++中常用的vector容器作为参数时,有三种传参方式,分别如下(为说明问题,用二维vector): function1(std::vector<std::vector<int> ...
- HAProxy的三种不同类型配置方案
haproxy是一款功能强大.灵活好用反向代理软件,提供了高可用.负载均衡.后端服务器代理的功能,它在7层负载均衡方面的功能很强大(支持 cookie track, header rewrite等等) ...
- [大数据]-Elasticsearch5.3.1 IK分词,同义词/联想搜索设置
--题外话:最近发现了一些问题,一些高搜索量的东西相当一部分没有价值.发现大部分是一些问题的错误日志.而我是个比较爱贴图的.搜索引擎的检索会将我们的博文文本分词.所以图片内容一般是检索不到的,也就是说 ...
- 18、面向对象基本原则及UML类图简介
18.1.面向对象基本原则 18.1.1.面向抽象原则 抽象类特点: a.抽象类中可以有abstract方法,也可以有非abstract方法. b.抽象类不能用new运算符创建对象. c.如果一个非抽 ...
- Java Date Classes
References: [1] http://tutorials.jenkov.com/java-date-time/index.html [2] https://docs.oracle.com/ja ...
- (入门篇 NettyNIO开发指南)第四章-TIP黏包/拆包问题解决之道
熟悉TCP编程的读者可能都知道,无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制.木章开始我们先简单介绍TCP粘包/拆包的基础知识,然后模拟一个没有考虑TCP ...
- hexo摸爬滚打之进阶教程
本文首发在我的个人博客:http://muyunyun.cn/ 写博客有三个层次,第一层次是借鉴居多的博文,第二层次是借鉴后经过消化后有一定量产出的博文,第三层次是原创好文居多的博文.在参考了大量前辈 ...
- docker - 关于network的一些理解
docker 提供给我们多种(4种)网络模式,我们可以根据自己的需求来使用.例如我们在一台主机(host)或者同一个docker engine上面运行continer的时候,我们就可以选择bridge ...
- OpenGL判断一个点是否可见
关于OpenGL中判断一个点是否可见,可以分成两种情况讨论:点在2D空间中和3D空间中的时候.并且"在2D空间中"可以看作"在3D空间中"的特殊情况. 温馨提示 ...
- Java 9 揭秘(2. 模块化系统)
文 by / 林本托 Tips 做一个终身学习的人. 在此章节中,主要介绍以下内容: 在JDK 9之前Java源代码用于编写,打包和部署的方式以及该方法的潜在问题 JDK 9中有哪些模块 如何声明模块 ...