如何搭建一个WEB服务器项目(六)

您所在的位置:网站首页 gta5相册怎么上传到服务器 如何搭建一个WEB服务器项目(六)

如何搭建一个WEB服务器项目(六)

2023-06-07 22:49| 来源: 网络整理| 查看: 265

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

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

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

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

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



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3