目录
选择图片上传到后端,生成http:域名:端口:/xxx.jpg,将此URL路径存MySQL,Android查询查询数据库获取URL字段数据,使用Glide加载网络图片。
- @PostMapping("/uploadFile")
- public String uploadFile(@RequestParam(value = "imgFile") MultipartFile imgFile) throws IOException {
- if (imgFile != null && !imgFile.isEmpty()) {
- //获取文件名
- String filename = imgFile.getOriginalFilename(); //图片名
- String[] split = new String[0];
- if (filename != null) {
- split = filename.split("\\.");
- }
- //只接受jpg、png、jpeg格式图片文件,其它格式的文件可按需添加判断,主要是为了防止上传恶意文件,加强安全性
- if ("jpg".equalsIgnoreCase(split[1]) || "png".equalsIgnoreCase(split[1]) || "jpeg".equalsIgnoreCase(split[1])) {
- //图片重命名加后缀
- String photoName = UUID.randomUUID().toString().replace("-", "") + "." + split[1];
- File destFile = new File(logoRealFolderPath + File.separator + photoName);
- //判断是否存在, 不存在就创建
- if (!destFile.getParentFile().exists()) {
- destFile.getParentFile().mkdirs();
- }
- //压缩图片保存
- Thumbnails.of(imgFile.getInputStream()).scale(0.8).toFile(destFile);
- //获取协议、服务器IP、端口号、工程路径
- String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
- String httpUrl = basePath + uploadReflexPath + photoName;
- System.out.println("完成URL地址 = " + httpUrl);
- //获取到URL后,可以将URL保存到数据库中,以便后续使用,这里就不做演示了,使用Mybatis即可
- if (testService.addUrl(httpUrl) == 0) {
- return "保存URL到数据库失败";
- } else {
- return "保存URL到数据库成功,文件地址为:" + httpUrl;
- }
- }
- }
- return "请上传文件后重试";
- }
说明:api接口:/uploadFile,post的key(表单的name):imgFile
- "1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:layout_centerInParent="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/iv_register_permission_logo"
- android:layout_width="80dp"
- android:layout_height="80dp"
- android:scaleType="centerCrop"
- android:layout_gravity="center"
- android:background="@drawable/bg_box_gray"
- android:src="@drawable/ic_baseline_add_24" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv_permission_show"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="5dp"
- android:gravity="center"
- android:text="@string/add_permission_logo"
- android:textColor="#1E88E5"
- android:textSize="14sp"
- android:textStyle="bold" />
- LinearLayout>
-
- RelativeLayout>
bg_box_gray.xml
- "1.0" encoding="utf-8"?>
- <shape xmlns:android="http://schemas.android.com/apk/res/android">
-
- <solid android:color="#00000000"/>
-
- <stroke
- android:width="1dip"
- android:color="#383838"/>
-
- <corners android:radius="15dp" />
- shape>

我是在ViewPager2中Fragment进行布局的,你们可以换成Activity,完全不影响。
代码的话,我进行步骤讲解,涉及到公司业务代码,这里抱歉,不方便全部粘出来,我会尽量按步骤说清楚。
- //图标选择
- private AppCompatImageView ivRegisterPermissionLogo;
- private AppCompatTextView tvPermissionShow;
-
- //图标选择
- ivRegisterPermissionLogo = baseFindView(R.id.iv_register_permission_logo);
- tvPermissionShow = baseFindView(R.id.tv_permission_show);
- tvPermissionShow.setText(R.string.add_permission_logo);
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- //SD存储权限组
- private final String[] PERMISSIONS = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
- //从相册中选择照片Activity的请求码
- public static final int CHOOSE_PHOTO = 2;
- //回调选中图片到真实路径
- private String logoPath = "";
- // 多个权限请求Code
- private final int REQUEST_CODE_PERMISSIONS = 3;
- //图标选择单击事件,触发时获取权限
- ivRegisterPermissionLogo.setOnClickListener(v -> requestMorePermissions());
- /**
- * 自定义申请多个权限
- */
- private void requestMorePermissions() {
- PermissionUtils.checkMorePermissions(fragmentContext, PERMISSIONS, new PermissionUtils.PermissionCheckCallBack() {
- @Override
- public void onHasPermission() {
- // 已授予权限,打开相册获取图片真实路径
- Log.i(TAG, "已授予权限");
- choosePermissionLogo();
- }
-
- @Override
- public void onUserHasAlreadyTurnedDown(String... permission) {
- // 上一次申请权限被拒绝,可用于向用户说明权限原因,然后调用权限申请方法
- Log.i(TAG, "上一次申请权限被拒绝");
- showExplainDialog((dialog, which) -> PermissionUtils.requestMorePermissions(fragmentContext, PERMISSIONS, REQUEST_CODE_PERMISSIONS));
- }
-
- @Override
- public void onUserHasAlreadyTurnedDownAndDonAsk(String... permission) {
- // 第一次申请权限或被禁止申请权限,建议直接调用申请权限方法。
- Log.i(TAG, "第一次申请权限或被禁止申请权限");
- PermissionUtils.requestMorePermissions(fragmentContext, PERMISSIONS, REQUEST_CODE_PERMISSIONS);
- }
- });
- }
-
- /**
- * 解释权限的dialog
- */
- private void showExplainDialog(DialogInterface.OnClickListener onClickListener) {
- new AlertDialog.Builder(fragmentContext)
- .setTitle("申请内存读写权限")
- .setMessage("用于打开相册,读取图片路径")
- .setPositiveButton("确定", onClickListener)
- .show();
- }
-
- /**
- * 打开相册选择权限图标
- */
-
- private void choosePermissionLogo() {
- //如果重复选择的话,先清空,等新图片路径来重新赋值,如果需要多张路的话,需要使用List
来存储多张图片到真实路径 - logoPath = "";
- Intent pickIntent = new Intent(Intent.ACTION_PICK, null);
- // 如果限制上传到服务器的图片类型时可以直接写如:"image/jpeg 、 image/png等的类型"
- pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
- startActivityForResult(pickIntent, CHOOSE_PHOTO);
- }
-
- /**
- * 回调申请的权限组
- */
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- if (requestCode == REQUEST_CODE_PERMISSIONS) {
- PermissionUtils.onRequestMorePermissionsResult(fragmentContext, PERMISSIONS, new PermissionUtils.PermissionCheckCallBack() {
- @Override
- public void onHasPermission() {
- // 权限已被授予
- choosePermissionLogo();
- }
-
- @Override
- public void onUserHasAlreadyTurnedDown(String... permission) {
- // 拒绝权限
- Toast.makeText(fragmentContext, "我们需要" + Arrays.toString(permission) + "权限", Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public void onUserHasAlreadyTurnedDownAndDonAsk(String... permission) {
- //已禁止再次询问权限
- Toast.makeText(fragmentContext, "我们需要" + Arrays.toString(permission) + "权限", Toast.LENGTH_SHORT).show();
- showToAppSettingDialog();
- }
- });
- }
- }
说明:权限请求完整工具类,文末贴出来。
- //从相册中选择照片Activity的请求码
- public static final int CHOOSE_PHOTO = 2;
- //回调选中图片到真实路径
- private String logoPath = "";
-
- /**
- * Android 4.4以上打开相册获取图片真实路径
- */
- @TargetApi(19)
- private String handleImageOnKitKat(Intent data) {
- String imagePath = null;
- Uri uri = data.getData();
- Log.i(TAG, "获取的uri=" + uri);
- if (DocumentsContract.isDocumentUri(fragmentContext, uri)) {
- //如果是document类型的Uri ,则通过document_id来处理
- String docId = DocumentsContract.getDocumentId(uri);
- if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
- String id = docId.split(":")[1];//解析出数据格式的ID
- String selection = MediaStore.Images.Media._ID + "=" + id;
- imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
- Log.i(TAG, "类型=media.documents");
- } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
- Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.parseLong(docId));
- imagePath = getImagePath(contentUri, null);
- Log.i(TAG, "类型=downloads.documents");
- }
- } else if ("content".equalsIgnoreCase(uri.getScheme())) {
- //如果是普通类型的Uri,则使用普通的方式来处理
- imagePath = getImagePath(uri, null);
- //imagePath = getRealPathFromURI(uri);
- Log.i(TAG, "类型=content");
- } else if ("file".equalsIgnoreCase(uri.getScheme())) {
- //如果是file类型的uri,直接获取图片路径就可以了
- imagePath = uri.getPath();
- Log.i(TAG, "类型=file");
- }
- Log.i(TAG, "图片真实路径=" + imagePath);
- return imagePath;
- }
-
- /**
- * Android4.4以下打开相册获取图片真实路径
- */
- private String handleImageBeforeKitKat(Intent data) {
- Uri uri = data.getData();
- String imagePath = getImagePath(uri, null);
- Log.i(TAG, "图片真实路径=" + imagePath);
- return imagePath;
- }
-
- /**
- * 相册选择回调图片Uri
- */
- @SuppressLint({"ObsoleteSdkInt", "SetTextI18n"})
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- // TODO: 从相册获取
- if (requestCode == CHOOSE_PHOTO) {
- if (resultCode == RESULT_OK) {
- if (Build.VERSION.SDK_INT >= 19) {
- logoPath = handleImageOnKitKat(data);
- } else {
- logoPath = handleImageBeforeKitKat(data);
- }
- }
- }
- //必须先进行上面两个handleImage方法去解析Uri,将类型转为真实路径的String路径返回给logoPath,然后进行下面的判断操作业务
- if (TextUtils.isEmpty(logoPath) && logoPath.equals("")) {
- tvPermissionShow.setText("请您选择一张权限图标");
- tvPermissionShow.setTextColor(getResources().getColor(R.color.red)); //字体变红色
- } else {
- //不为空,将图片路径转为Bitmap后,使用图片控件显示出来
- ivRegisterPermissionLogo.setImageBitmap(BitmapFactory.decodeFile(logoPath));
- tvPermissionShow.setText("当前图片名:" + logoPath.substring(logoPath.lastIndexOf("/") + 1));
- tvPermissionShow.setTextColor(getResources().getColor(R.color.blue));
- }
- super.onActivityResult(requestCode, resultCode, data);
- }


- public class HttpUtil {
-
- private static final String TAG = "HttpUtil";
-
- //边界参数
- private String boundary;
- //文件上传接口监听
- private requestListener requestListener;
-
- /**
- * 图片上传
- *
- * @param urlStr URL
- * @param imgPath 图片路径
- */
- public void upLoadFile(String urlStr, final String imgPath) {
- new Thread(() -> {
- Looper.prepare();
- //自己生一个boundary
- boundary = UUID.randomUUID().toString().replace("-", "");
- HttpURLConnection conn = null;
- try {
- String fileName = "zy" + (int) (Math.random() * 1000000) + ".jpg";
- StringBuilder sb = new StringBuilder();
- //表单数据
- sb.append("--").append(boundary).append("\r\n");
- //图标
- sb.append("Content-Disposition: form-data; name=imgFile" + "; filename=").append(fileName).append("\r\n");
- //传图路径创建文件对象
- File file = new File(imgPath);
- //获取文件名
- String filename = file.getName();
- //截取文件后缀,对应设置mime-type支持类型
- String contentType = "";
- if (filename.endsWith(".png")) {
- contentType = "image/png";
- }
- if (filename.endsWith(".jpg")) {
- contentType = "image/jpg";
- }
- if (filename.endsWith(".gif")) {
- contentType = "image/gif";
- }
- if (filename.endsWith(".bmp")) {
- contentType = "image/bmp";
- }
- if (contentType.equals("")) {
- contentType = "application/octet-stream";
- }
- sb.append("Content-Type:").append(contentType).append("\r\n");
- sb.append("\r\n");//此时的sd———>Content-Disposition: form-data; name=imgFile; filename=zy+随机数.jpg
- //字节流处理
- byte[] headerInfo = sb.toString().getBytes(StandardCharsets.UTF_8);
- byte[] endInfo = ("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8);
- conn = (HttpURLConnection) new URL(urlStr).openConnection();
- conn.setDoInput(true);
- conn.setDoOutput(true);
- //文件上传必须为POST
- conn.setRequestMethod("POST");
- //注意这里的格式,模仿表单,出现一点点错误都会导致上传不成功
- conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
- //数据长度
- conn.setRequestProperty("Content-Length", String.valueOf(file.length() + headerInfo.length + endInfo.length));
- //通过conn拿到服务器的字节输出流
- OutputStream out = conn.getOutputStream();
- //需要上传的文件封装成字节输入流
- InputStream in = new FileInputStream(file);
- out.write(headerInfo);
- byte[] buf = new byte[1024];
- int len;
- while ((len = in.read(buf)) != -1) out.write(buf, 0, len);
- out.write(endInfo);
- in.close();
- out.close();
- if (conn.getResponseCode() == 200) {
- requestListener.success(new BufferedReader(new InputStreamReader(conn.getInputStream())).readLine());
- }
- } catch (Exception e) {
- e.printStackTrace();
- if (Objects.requireNonNull(e.getMessage()).contains("to connect to")) {
- Log.i(TAG, "服务器访问失败,请联系管理员修复");
- if (requestListener != null) {
- requestListener.fail("{ \"code\": 502,\n \"msg\": \"服务器访问失败,请联系管理员处理\",\n \"data\":{}}");
- }
- } else if (Objects.requireNonNull(e.getMessage()).contains("Unable to resolve host")) {
- Log.i(TAG, "服务器访问失败,请检查网络是否可用");
- if (requestListener != null) {
- requestListener.fail("{ \"code\": 503,\n \"msg\": \"请求失败,请检查网络是否可用\",\n \"data\":{}}");
- }
- } else {
- Log.i(TAG, "服务器访问失败,未知错误:" + e.getMessage());
- if (requestListener != null) {
- requestListener.fail("{ \"code\": 504,\n \"msg\": \"服务器访问失败,错误原因未知,请联系管理员处理\",\n \"data\":{}}");
- }
- }
- } finally {
- if (conn != null) {
- conn.disconnect();
- }
- }
- Looper.loop();
- }).start();
- }
-
- /**
- * 上传监听接口
- *
- * @param requestListener 上传结果回调
- */
- public void setRequestListener(requestListener requestListener) {
- this.requestListener = requestListener;
- }
-
- /**
- * 定义外部请求结果回调接口
- */
- public interface requestListener {
-
- /**
- * 成功回调
- *
- * @param resultJson 成功JSON数据
- */
- void success(String resultJson) throws JSONException;
-
- /**
- * 失败回调
- *
- * @param resultJson 失败JSON数据
- */
- void fail(String resultJson);
- }
- }
- HttpUtil uploadFileUtil = new HttpUtil();
- uploadFileUtil.upLoadFile(Constant.ADD_PERMISSION_INFO);
- uploadFileUtil.setRequestListener(new HttpUtil.requestListener() {
- @Override
- public void success(String resultJson) {
- Log.i("zyLogin", "成功: " + resultJson);
-
- }
-
- @Override
- public void fail(String resultJson) {
- Log.i("zyLogin", "失败: " + resultJson);
-
- }
- });

说明:执行成功后,后端业务代码处理后,会将图片信息存入到云服务器Linux的硬盘内存上,并将Servlet映射路径后外网可访问的URL地址存进数据库,当Android使用Glide就能直接加载图片信息啦。
- public class PermissionUtils {
-
- /**
- * 检测权限
- *
- * @return true:已授权; false:未授权;
- */
- public static boolean checkPermission(Context context, String permission) {
- if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED)
- return true;
- else
- return false;
- }
-
- /**
- * 检测多个权限
- *
- * @return 未授权的权限
- */
- public static List
checkMorePermissions(Context context, String[] permissions) { - List
permissionList = new ArrayList<>(); - for (int i = 0; i < permissions.length; i++) {
- if (!checkPermission(context, permissions[i]))
- permissionList.add(permissions[i]);
- }
- return permissionList;
- }
-
- /**
- * 请求权限
- */
- public static void requestPermission(Context context, String permission, int requestCode) {
- ActivityCompat.requestPermissions((Activity) context, new String[]{permission}, requestCode);
- }
-
- /**
- * 请求多个权限
- */
- public static void requestMorePermissions(Context context, List permissionList, int requestCode) {
- String[] permissions = (String[]) permissionList.toArray(new String[permissionList.size()]);
- requestMorePermissions(context, permissions, requestCode);
- }
-
- /**
- * 请求多个权限
- */
- public static void requestMorePermissions(Context context, String[] permissions, int requestCode) {
- ActivityCompat.requestPermissions((Activity) context, permissions, requestCode);
- }
-
- /**
- * 判断是否已拒绝过权限
- * 如果应用之前请求过此权限但用户拒绝,此方法将返回 true;
- * 如果应用第一次请求权限或 用户在过去拒绝了权限请求,
- * 并在权限请求系统对话框中选择了 Don't ask again 选项,此方法将返回 false。
- */
- public static boolean judgePermission(Context context, String permission) {
- return ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, permission);
- }
-
- /**
- * 检测权限并请求权限:如果没有权限,则请求权限
- */
- public static void checkAndRequestPermission(Context context, String permission, int requestCode) {
- if (!checkPermission(context, permission)) {
- requestPermission(context, permission, requestCode);
- }
- }
-
- /**
- * 检测并请求多个权限
- */
- public static void checkAndRequestMorePermissions(Context context, String[] permissions, int requestCode) {
- List
permissionList = checkMorePermissions(context, permissions); - requestMorePermissions(context, permissionList, requestCode);
- }
-
-
- /**
- * 检测权限
- * 具体实现由回调接口决定
- */
- public static void checkPermission(Context context, String permission, PermissionCheckCallBack callBack) {
- if (checkPermission(context, permission)) { // 用户已授予权限
- callBack.onHasPermission();
- } else {
- if (judgePermission(context, permission)) // 用户之前已拒绝过权限申请
- callBack.onUserHasAlreadyTurnedDown(permission);
- else // 用户之前已拒绝并勾选了不在询问、用户第一次申请权限。
- callBack.onUserHasAlreadyTurnedDownAndDonAsk(permission);
- }
- }
-
- /**
- * 检测多个权限
- * 具体实现由回调接口决定
- */
- public static void checkMorePermissions(Context context, String[] permissions, PermissionCheckCallBack callBack) {
- List
permissionList = checkMorePermissions(context, permissions); - if (permissionList.size() == 0) { // 用户已授予权限
- callBack.onHasPermission();
- } else {
- boolean isFirst = true;
- for (int i = 0; i < permissionList.size(); i++) {
- String permission = permissionList.get(i);
- if (judgePermission(context, permission)) {
- isFirst = false;
- break;
- }
- }
- String[] unauthorizedMorePermissions = (String[]) permissionList.toArray(new String[permissionList.size()]);
- if (isFirst)// 用户之前已拒绝过权限申请
- callBack.onUserHasAlreadyTurnedDownAndDonAsk(unauthorizedMorePermissions);
- else // 用户之前已拒绝并勾选了不在询问、用户第一次申请权限。
- callBack.onUserHasAlreadyTurnedDown(unauthorizedMorePermissions);
-
- }
- }
-
-
- /**
- * 检测并申请权限
- */
- public static void checkAndRequestPermission(Context context, String permission, int requestCode, PermissionRequestSuccessCallBack callBack) {
- if (checkPermission(context, permission)) {// 用户已授予权限
- callBack.onHasPermission();
- } else {
- requestPermission(context, permission, requestCode);
- }
- }
-
- /**
- * 检测并申请多个权限
- */
- public static void checkAndRequestMorePermissions(Context context, String[] permissions, int requestCode, PermissionRequestSuccessCallBack callBack) {
- List
permissionList = checkMorePermissions(context, permissions); - if (permissionList.size() == 0) { // 用户已授予权限
- callBack.onHasPermission();
- } else {
- requestMorePermissions(context, permissionList, requestCode);
- }
- }
-
- /**
- * 判断权限是否申请成功
- */
- public static boolean isPermissionRequestSuccess(int[] grantResults) {
- if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED)
- return true;
- else
- return false;
- }
-
- /**
- * 用户申请权限返回
- */
- public static void onRequestPermissionResult(Context context, String permission, int[] grantResults, PermissionCheckCallBack callback) {
- if (PermissionUtils.isPermissionRequestSuccess(grantResults)) {
- callback.onHasPermission();
- } else {
- if (PermissionUtils.judgePermission(context, permission)) {
- callback.onUserHasAlreadyTurnedDown(permission);
- } else {
- callback.onUserHasAlreadyTurnedDownAndDonAsk(permission);
- }
- }
- }
-
- /**
- * 用户申请多个权限返回
- */
- public static void onRequestMorePermissionsResult(Context context, String[] permissions, PermissionCheckCallBack callback) {
- boolean isBannedPermission = false;
- List
permissionList = checkMorePermissions(context, permissions); - if (permissionList.size() == 0)
- callback.onHasPermission();
- else {
- for (int i = 0; i < permissionList.size(); i++) {
- if (!judgePermission(context, permissionList.get(i))) {
- isBannedPermission = true;
- break;
- }
- }
- // 已禁止再次询问权限
- if (isBannedPermission)
- callback.onUserHasAlreadyTurnedDownAndDonAsk(permissions);
- else // 拒绝权限
- callback.onUserHasAlreadyTurnedDown(permissions);
- }
-
- }
-
-
- /**
- * 跳转到权限设置界面
- */
- public static void toAppSetting(Context context) {
- Intent intent = new Intent();
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- if (Build.VERSION.SDK_INT >= 9) {
- intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
- intent.setData(Uri.fromParts("package", context.getPackageName(), null));
- } else if (Build.VERSION.SDK_INT <= 8) {
- intent.setAction(Intent.ACTION_VIEW);
- intent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
- intent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName());
- }
- context.startActivity(intent);
- }
-
- public interface PermissionRequestSuccessCallBack {
- /**
- * 用户已授予权限
- */
- void onHasPermission();
- }
-
-
- public interface PermissionCheckCallBack {
-
- /**
- * 用户已授予权限
- */
- void onHasPermission();
-
- /**
- * 用户已拒绝过权限
- *
- * @param permission:被拒绝的权限
- */
- void onUserHasAlreadyTurnedDown(String... permission);
-
- /**
- * 用户已拒绝过并且已勾选不再询问选项、用户第一次申请权限;
- *
- * @param permission:被拒绝的权限
- */
- void onUserHasAlreadyTurnedDownAndDonAsk(String... permission);
- }
- }
仅自己学习记录,如有错误,敬请谅解~,谢谢~~