如何搭建一个WEB服务器项目(六)—— 上传图片至服务器

如何搭建一个WEB服务器项目(六)—— 上传图片至服务器

上传图片(用户头像)至服务器

观前提示:本系列文章有关服务器以及后端程序这些概念,我写的全是自己的理解,并不一定正确,希望不要误人子弟。欢迎各位大佬来评论区提出问题或者是指出错误,分享宝贵经验。先谢谢了( ̄▽ ̄)"!

前两期介绍了如何从服务器获取数据和加载图片,现在我们来看看如何把图片上传到服务器。这是一个很常见的需求,比如说上传用户头像等,本期也将围绕这个内容展开。首先服务器这边我们写一个上传图片的controller:

1 package dolphin.controller;

2

3 import org.springframework.stereotype.Controller;

4 import org.springframework.web.bind.annotation.RequestMapping;

5 import org.springframework.web.bind.annotation.ResponseBody;

6 import org.springframework.web.multipart.MultipartFile;

7

8 import javax.servlet.http.HttpServletRequest;

9 import java.io.File;

10 import java.io.IOException;

11

12 /**

13 * @description :数据更新控制层

14 * @author :郭小柒w

15 * @date :2020/5/16 16:03

16 * @version :1.0

17 */

18 @Controller

19 public class UpdateController {

20 /**

21 *

22 * @param file

23 * @param request

24 * @return String 不同的返回值代表不同上传结果

25 * @throws IllegalStateException

26 * @throws IOException

27 */

28 @RequestMapping( "/Upload")

29 @ResponseBody

30 public String photoUpload(MultipartFile file, HttpServletRequest request) throws IllegalStateException, IOException {

31 if (file != null) {// 判断上传的文件是否为空

32 String path = null;// 文件路径

33 String type = null;// 文件类型

34 String fileName = file.getOriginalFilename();// 文件原名称

35 System.out.println("上传的文件原名称:"+fileName);

36 // 判断文件类型

37 type = fileName.indexOf(".") != -1 ? fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()) : null;

38 if (type != null) {// 判断文件类型是否为空

39 if ("GIF".equals(type.toUpperCase()) || "PNG".equals(type.toUpperCase()) || "JPG".equals(type.toUpperCase())) {

40 // 项目在容器中实际发布运行的根路径

41 String realPath = request.getSession().getServletContext().getRealPath("/");

42 // 自定义的文件名称

43 String trueFileName = fileName;

44 // 设置存放图片文件的路径

45 path = realPath + "WEB-INF\\images\\head\\" + trueFileName;

46 // 转存文件到指定的路径

47 file.transferTo(new File(path));

48 System.out.println("文件成功上传到指定目录下");

49 }else {

50 System.out.println("不是我们想要的文件类型,请按要求重新上传");

51 return "1";

52 }

53 }else {

54 System.out.println("文件类型为空");

55 return "2";

56 }

57 }else {

58 System.out.println("没有找到相对应的文件");

59 return "3";

60 }

61 return "0";

62 }

63 }

单单有这个还不够,我们还需要进行如下配置:

1.在pom.xml里加入上传文件相关的依赖(版本可根据需要进行更改):

1

2

3 org.apache.commons

4 commons-io

5 1.3.2

6

7

8

9 commons-fileupload

10 commons-fileupload

11 1.3.1

12

2.在springmvc.xml里新增如下配置:

1

2

3 class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

4

5

6

7

然后是用于测试controller的页面,index.jsp(enctype="multipart/form-data"的作用是将form表单的数据以二进制的方式传输)

1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>

2

3

4 Title

5

6

7

8 图片上传

9

只能上传单张10M以下的 PNG、JPG、GIF 格式的图片

10

11 选择文件:

12

13

14

15

16

我们先看一下效果,从本地选择一张符合要求图片:

选择完毕后是这样:

然后点击上传,页面跳转。上传成功的话页面只有一个“0”,图片不再贴出,我们先看一下控制台输出:

从输出的存放路径找到我们上传的图片:

从图中可以看出已经上传成功,证明我们的controller是可行的,接下来就是编写安卓端的代码,尝试从客户端上传图片。

客户端获取图片大致就两种方式:1.拍照;2.本地图库。

由于博主也不是什么技术大佬,所以老老实实地使用大神们造的轮子,主要是以下两个库:

TakePhoto:https://github.com/crazycodeboy/TakePhoto

AndPermission:https://github.com/yanzhenjie/AndPermission

更详细的介绍请到相应网址查看,我这只是简单的使用,首先是页面布局:

1

2

3 xmlns:tools="http://schemas.android.com/tools"

4 android:id="@+id/activity_main"

5 android:orientation="vertical"

6 android:layout_width="match_parent"

7 android:layout_height="match_parent"

8 tools:context=".UserHeadActivity">

9

10 android:layout_width="match_parent"

11 android:layout_height="30dp">

12

13

14 android:layout_width="wrap_content"

15 android:layout_height="wrap_content"

16 android:layout_gravity="center_horizontal"

17 android:text="UserHeadActivity" />

18

19 android:id="@+id/image_view"

20 android:layout_marginTop="10dp"

21 android:layout_gravity="center_horizontal"

22 android:layout_width="150dp"

23 android:layout_height="150dp"

24 android:src="@drawable/ic_launcher"

25 />

26

27 android:id="@+id/take_from_camera"

28 android:text="拍照"

29 android:layout_gravity="center_horizontal"

30 android:layout_width="wrap_content"

31 android:layout_height="wrap_content" />

32

33 android:id="@+id/take_from_galley"

34 android:text="图库"

35 android:layout_gravity="center_horizontal"

36 android:layout_width="wrap_content"

37 android:layout_height="wrap_content" />

38

可能你会有疑问,“com.example.dolphin.utils.RoundImageView”是个什么玩意儿?由于要做用户头像,我就顺便在网上找了一个自定义圆形ImageView控件的例子,非常简单,代码如下:

1 package com.example.dolphin.utils;

2

3 import android.annotation.SuppressLint;

4 import android.content.Context;

5 import android.graphics.Bitmap;

6 import android.graphics.BitmapShader;

7 import android.graphics.Canvas;

8 import android.graphics.Matrix;

9 import android.graphics.Paint;

10 import android.graphics.Shader;

11 import android.graphics.drawable.BitmapDrawable;

12 import android.graphics.drawable.Drawable;

13 import android.util.AttributeSet;

14 import android.widget.ImageView;

15

16 import androidx.annotation.Nullable;

17

18 /**

19 * @author :created by 郭小柒w

20 * 时间 2020/5/16 15

21 * 自定义的圆形ImageView,可以直接当组件在布局中使用。

22 */

23

24 @SuppressLint("AppCompatCustomView")

25 public class RoundImageView extends ImageView {

26

27 //画笔

28 private Paint mPaint;

29 //圆形图片的半径

30 private int mRadius;

31 //图片的宿放比例

32 private float mScale;

33

34 public RoundImageView(Context context) {

35 super(context);

36 }

37

38 public RoundImageView(Context context, @Nullable AttributeSet attrs) {

39 super(context, attrs);

40 }

41

42 public RoundImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

43 super(context, attrs, defStyleAttr);

44 }

45

46 @Override

47 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

48 super.onMeasure(widthMeasureSpec, heightMeasureSpec);

49 //由于是圆形,宽高应保持一致

50 int size = Math.min(getMeasuredWidth(), getMeasuredHeight());

51 mRadius = size / 2;

52 setMeasuredDimension(size, size);

53 }

54

55 @SuppressLint("DrawAllocation")

56 @Override

57 protected void onDraw(Canvas canvas) {

58

59 mPaint = new Paint();

60

61 Drawable drawable = getDrawable();

62

63 if (null != drawable) {

64 Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();

65

66 //初始化BitmapShader,传入bitmap对象

67 BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

68 //计算缩放比例

69 mScale = (mRadius * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());

70

71 Matrix matrix = new Matrix();

72 matrix.setScale(mScale, mScale);

73 bitmapShader.setLocalMatrix(matrix);

74 mPaint.setShader(bitmapShader);

75 //画圆形,指定好坐标,半径,画笔

76 canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);

77 } else {

78 super.onDraw(canvas);

79 }

80 }

81

82 }

RoundImageView.java

在你的项目里创建这个类,之后就可以像上边那样使用啦(使用时注意类的路径,不要直接复制粘贴上面的代码),最后是页面对应的Activity:

1 package com.example.dolphin;

2

3 import android.Manifest;

4 import android.content.Intent;

5 import android.net.Uri;

6 import android.os.Environment;

7 import android.os.Bundle;

8 import android.util.Log;

9 import android.view.View;

10 import android.widget.Button;

11 import android.widget.ImageView;

12 import android.widget.Toast;

13

14 import com.bumptech.glide.Glide;

15 import com.example.dolphin.utils.Constants;

16 import com.jph.takephoto.app.TakePhoto;

17 import com.jph.takephoto.app.TakePhotoActivity;

18 import com.jph.takephoto.compress.CompressConfig;

19 import com.jph.takephoto.model.CropOptions;

20 import com.jph.takephoto.model.TResult;

21 import com.yanzhenjie.permission.AndPermission;

22 import com.yanzhenjie.permission.PermissionListener;

23 import com.zhy.http.okhttp.OkHttpUtils;

24 import com.zhy.http.okhttp.callback.StringCallback;

25

26 import java.io.File;

27 import java.util.List;

28

29 import okhttp3.Call;

30

31 public class UserHeadActivity extends TakePhotoActivity {

32

33 //UIs

34 private Button takeFromCameraBtn, takeFromGalleyBtn; //拍照以及从相册中选取Button

35 private ImageView imageView; //图片展示ImageView

36

37 //TakePhoto

38 private TakePhoto takePhoto;

39 private CropOptions cropOptions; //裁剪参数

40 private CompressConfig compressConfig; //压缩参数

41 private Uri imageUri; //图片保存路径

42

43 @Override

44 protected void onCreate(Bundle savedInstanceState) {

45 super.onCreate(savedInstanceState);

46 setContentView(R.layout.activity_userhead);

47 //申请相关权限

48 initPermission();

49 //设置压缩、裁剪参数

50 initData();

51 takeFromCameraBtn = (Button) findViewById(R.id.take_from_camera);

52 takeFromCameraBtn.setOnClickListener(new View.OnClickListener() {

53 @Override

54 public void onClick(View view) {

55 imageUri = getImageCropUri();

56 //拍照并裁剪

57 takePhoto.onPickFromCaptureWithCrop(imageUri, cropOptions);

58 //仅仅拍照不裁剪

59 //takePhoto.onPickFromCapture(imageUri);

60 }

61 });

62

63 takeFromGalleyBtn = (Button) findViewById(R.id.take_from_galley);

64 takeFromGalleyBtn.setOnClickListener(new View.OnClickListener() {

65 @Override

66 public void onClick(View view) {

67 imageUri = getImageCropUri();

68 //从相册中选取图片并裁剪

69 takePhoto.onPickFromGalleryWithCrop(imageUri, cropOptions);

70 //从相册中选取不裁剪

71 //takePhoto.onPickFromGallery();

72 }

73 });

74

75 imageView = (ImageView) findViewById(R.id.image_view);

76 }

77

78 @Override

79 public void takeSuccess(TResult result) {

80 super.takeSuccess(result);

81 String iconPath = result.getImage().getOriginalPath();

82 //Toast显示图片路径

83 Toast.makeText(this, "imagePath:" + iconPath, Toast.LENGTH_SHORT).show();

84 //上传图片

85 submitHead(iconPath);

86 //Google Glide库 用于加载图片资源,这里是把图片展示在页面上

87 Glide.with(this).load(iconPath).asBitmap().into(imageView);

88 }

89

90 @Override

91 public void takeFail(TResult result, String msg) {

92 super.takeFail(result, msg);

93 Toast.makeText(UserHeadActivity.this, "Error:" + msg, Toast.LENGTH_SHORT).show();

94 }

95

96 @Override

97 public void takeCancel() {

98 super.takeCancel();

99 }

100

101 private void initPermission() {

102 // 申请权限。

103 AndPermission.with(this)

104 .requestCode(100)

105 .permission(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE)

106 .send();

107 }

108

109 @Override

110 public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

111 // 只需要调用这一句,其它的交给AndPermission吧,最后一个参数是PermissionListener。

112 AndPermission.onRequestPermissionsResult(requestCode, permissions, grantResults, listener);

113 }

114

115 //权限申请回调接口

116 private PermissionListener listener = new PermissionListener() {

117 @Override

118 public void onSucceed(int requestCode, List grantedPermissions) {

119 // 权限申请成功回调。

120 if(requestCode == 100) {

121 // TODO 相应代码。

122 //do nothing

123 }

124 }

125 @Override

126 public void onFailed(int requestCode, List deniedPermissions) {

127 // 权限申请失败回调。

128

129 // 用户否勾选了不再提示并且拒绝了权限,那么提示用户到设置中授权。

130 if (AndPermission.hasAlwaysDeniedPermission(UserHeadActivity.this, deniedPermissions)) {

131

132 // 用自定义的提示语

133 AndPermission.defaultSettingDialog(UserHeadActivity.this, 103)

134 .setTitle("权限申请失败")

135 .setMessage("我们需要的一些权限被您拒绝或者系统发生错误申请失败,请您到设置页面手动授权,否则功能无法正常使用!")

136 .setPositiveButton("好,去设置")

137 .show();

138 }

139 }

140 };

141

142 private void initData() {

143 ////获取TakePhoto实例

144 takePhoto = getTakePhoto();

145 //设置裁剪参数

146 cropOptions = new CropOptions.Builder().setAspectX(1).setAspectY(1).setWithOwnCrop(false).create();

147 //设置压缩参数

148 compressConfig=new CompressConfig.Builder().setMaxSize(50*1024).setMaxPixel(800).create();

149 takePhoto.onEnableCompress(compressConfig,true); //设置为需要压缩

150 }

151

152 //获得照片的输出保存Uri

153 private Uri getImageCropUri() {

154 File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis()+".jpg");

155 if (!file.getParentFile().exists())

156 file.getParentFile().mkdirs();

157 return Uri.fromFile(file);

158 }

159

160 private void submitHead(String iconPath){

161 //获取对应图片

162 File file = new File(iconPath);

163 //设置网络请求路径

164 String url = Constants.BASE_URL+"/Upload";

165 OkHttpUtils.post().url(url)

166 .addFile("file",file.getName(),file)

167 .build()

168 .execute(new StringCallback() {

169 @Override

170 public void onError(Call call, Exception e, int id) {

171 Toast.makeText(UserHeadActivity.this,"网络异常,请稍后再试",Toast.LENGTH_SHORT).show();

172 System.out.println("页面请求失败=="+e.getMessage());

173 }

174

175 @Override

176 public void onResponse(String response, int id) {

177 System.out.println("首页请求成功=="+response);

178 ResultOfUpload(response);

179 }

180 });

181 }

182 //对返回结果进行处理

183 private void ResultOfUpload(String code){

184 if(code.equals("0"))

185 Toast.makeText(this,"上传成功",Toast.LENGTH_SHORT).show();

186 else if(code.equals("1"))

187 Toast.makeText(this,"文件格式不符,请重新上传",Toast.LENGTH_SHORT).show();

188 else if(code.equals("2"))

189 Toast.makeText(this,"文件类型为空",Toast.LENGTH_SHORT).show();

190 else

191 Toast.makeText(this,"未找到对应文件",Toast.LENGTH_SHORT).show();

192 }

193 }

所有工作都已完成,接下来看看实际效果如何。下面是调试时的录屏,这里只给出从图库获取并上传的示例,拍照的模块大家可以自行测试,我测试时没问题(录屏转gif还挺麻烦,画质有点糊,各位凑合着看吧🙃)。

IDEA控制台输出信息如下:

可以看到图片已经成功上传:

最后非常感谢下面这几篇博客,有了他们我才能东拼西凑,做出这期想做的东西:

OkHttputils上传用户头像到服务器

《Android三方库--TakePhoto》

SpringMvc MutipartFile图片文件上传

—————————————我———是———分———割———线————————————

拖更快乐!(bushi)

托更也是无奈嘛╮(╯-╰)╭,谁让上周五我又跟着同学们happy去了😜。毕竟是开学前的狂欢呀,虽然我的开学遥遥无期,甚至有的同学已经得到不开学的通知了(酸了🍋),不过还是有点盼望开学的(再不开代码都敲不利索了!)最近的进度也是停滞不前,没有干劲,真怕老师突然宣布要交出点成果了😱。仔细想想,可能还是因为目标不够明确吧,都这个时候了还是不清楚往哪个方向用功,我已经能看到我惨淡的人生了😭。但是不管怎么样,生活还是要继续下去,总不能一直这么颓废,这不一有时间就更新了么,嘿嘿(快夸我( ̄▽ ̄))。最近这个系列应该都不更了,因为也没太多能分享的了,所以断更一段时间,期间可能会更新计算机网络或者算法相关的吧,有兴趣的可以关注一下我的每周动态。那么我们有缘再见👋

相关内容

口罩哪个牌子的质量好?国产医用十大口罩品牌排行榜
365bet体育在线赌场

口罩哪个牌子的质量好?国产医用十大口罩品牌排行榜

⌛ 11-25 👁️ 2958
歡迎使用 Photoshop 使用者指南
365bet体育在线赌场

歡迎使用 Photoshop 使用者指南

⌛ 08-20 👁️ 4936
民宿app排名前十2024
365app下载登录

民宿app排名前十2024

⌛ 06-28 👁️ 2753
Excel将打开一个空白屏幕
365app下载登录

Excel将打开一个空白屏幕

⌛ 10-26 👁️ 6169
淘米游戏客服中心
ibay365

淘米游戏客服中心

⌛ 09-08 👁️ 6724