Vue+SpringBoot+OSS+element实现图片上传服务器+图片展示墙
1、技术选型:
(1)Vue(前端)
(2)Element(上传图片组件)
(3)SpringBoot(后端)
(4)Mybatis(数据库操作)
(3)OSS(阿里云存储服务器)
2、实现效果概述:
(1)图片展示墙(做了一个简单的,没有太花里胡哨)
(2)上传页面
3、项目概述:
注意这是一个练习项目,练习项目,练习项目,可能存在一些小问题!
简单来说,
=(1)图片上传逻辑:=
前端通过elementUI的上传图片的组件将图片进行上传,后端利用SpringBoot写的后端逻辑接受了前端穿过的图片,首先将图片上传到阿里云的OSS对象存储系统上,然后返回图片的地址存储到数据库。
=(2)图片展示墙逻辑:=
通过查询数据库的图片地址返回给前端,然后前端通过for循环,利用img标签对图片进行循环遍历然后显示!
项目简单,易于实现,全代码黏贴!!!!!!
4、图片上传
(1)前端项目结构:
(2)ImagesUpload.vue
=补充:这里主要是借助了elementUI的上传图片组件!!!!
这里只需要将action中的地址改成自己的后端请求地址就可以!!!=
<template><div><el-uploadaction="http://localhost:8086/images/upload"list-type="picture-card":on-preview="handlePictureCardPreview":on-remove="handleRemove"><i class="el-icon-plus"></i></el-upload></div></template><el-dialog :visible.sync="dialogVisible"><img width="100%" :src="dialogImageUrl" alt="">
</el-dialog><script>export default {name: "images-upload",data() {return {dialogImageUrl: '',dialogVisible: false};},methods: {handleRemove(file, fileList) {console.log(file, fileList);},handlePictureCardPreview(file) {this.dialogImageUrl = file.url;this.dialogVisible = true;}}}
</script><style scoped></style>
==前端逻辑完成,开始后端逻辑=
(3)安装阿里云OSS所需依赖:
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>2.8.3</version></dependency>
(4)OSS工具类封装:
=这里根据自己的实际情况合理选择域名,访问用户,秘钥…=
package com.blog.util;/*** @author * @version 1.0* @description TODO* @date 2023/3/12 8:28*/import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.Date;
import java.util.Random;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;public class OSSClientUtil {/*** log日志*/public static final Logger logger = LoggerFactory.getLogger(OSSClientUtil.class);/*** 访问域名*/private String endpoint = "oss-cn-beijing.aliyuncs.com";/*** accessKey访问秘钥* 访问用户*/private String accessKeyId = "########";/*** 密钥*/private String accessKeySecret = "################";/*** 空间 名称*/private String bucketName = "############";/*** 文件存储目录*/private String filedir = "###########/";private OSSClient ossClient;public OSSClientUtil() {ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);}/*** 初始化*/public void init() {ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);}/*** 销毁*/public void destory() {ossClient.shutdown();}/*** 上传图片** @param url* @throws*/public void uploadImg2Oss(String url) throws IOException {File fileOnServer = new File(url);FileInputStream fin;try {fin = new FileInputStream(fileOnServer);String[] split = url.split("/");this.uploadFile2OSS(fin, split[split.length - 1]);} catch (FileNotFoundException e) {throw new IOException("图片上传失败");}}public String uploadImg2Oss(MultipartFile file) throws IOException {if (file.getSize() > 10 * 1024 * 1024) {throw new IOException("上传图片大小不能超过10M!");}String originalFilename = file.getOriginalFilename();String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();Random random = new Random();String name = random.nextInt(10000) + System.currentTimeMillis() + substring;try {InputStream inputStream = file.getInputStream();this.uploadFile2OSS(inputStream, name);return name;} catch (Exception e) {throw new IOException("图片上传失败");}}/*** 获得图片路径** @param fileUrl* @return*/public String getImgUrl(String fileUrl) {System.out.println(fileUrl);if (!StringUtils.isEmpty(fileUrl)) {String[] split = fileUrl.split("/");return this.getUrl(this.filedir + split[split.length - 1]);}return "" ;}/*** 上传到OSS服务器 如果同名文件会覆盖服务器上的** @param instream* 文件流* @param fileName* 文件名称 包括后缀名* @return 出错返回"" ,唯一MD5数字签名*/public String uploadFile2OSS(InputStream instream, String fileName) {String ret = "";try {// 创建上传Object的MetadataObjectMetadata objectMetadata = new ObjectMetadata();objectMetadata.setContentLength(instream.available());objectMetadata.setCacheControl("no-cache");objectMetadata.setHeader("Pragma", "no-cache");objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));objectMetadata.setContentDisposition("inline;filename=" + fileName);// 上传文件PutObjectResult putResult = ossClient.putObject(bucketName, filedir + fileName, instream, objectMetadata);ret = putResult.getETag();} catch (IOException e) {logger.error(e.getMessage(), e);} finally {try {if (instream !=null ) {instream.close();}} catch (IOException e) {e.printStackTrace();}}return ret;}/*** Description: 判断OSS服务文件上传时文件的contentType** @param** @return String*/public static String getcontentType(String filenameExtension) {if (filenameExtension.equalsIgnoreCase("bmp")) {return "image/bmp";}if (filenameExtension.equalsIgnoreCase("gif")) {return "image/gif";}if (filenameExtension.equalsIgnoreCase("jpeg") || filenameExtension.equalsIgnoreCase("jpg")|| filenameExtension.equalsIgnoreCase("png")) {return "image/jpeg";}if (filenameExtension.equalsIgnoreCase("html")) {return "text/html";}if (filenameExtension.equalsIgnoreCase("txt")) {return "text/plain";}if (filenameExtension.equalsIgnoreCase("vsd")) {return "application/vnd.visio";}if (filenameExtension.equalsIgnoreCase("pptx") || filenameExtension.equalsIgnoreCase("ppt")) {return "application/vnd.ms-powerpoint";}if (filenameExtension.equalsIgnoreCase("docx") || filenameExtension.equalsIgnoreCase("doc")) {return "application/msword";}if (filenameExtension.equalsIgnoreCase("xml")) {return "text/xml";}return "image/jpeg";}/*** 获得url链接** @param key* @return*/public String getUrl(String key) {// 设置URL过期时间为10年 3600l* 1000*24*365*10Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);// 生成URL// URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);String url = "https://"+bucketName+"."+endpoint+"/"+key;if (url != null) {return url.toString();}return "";}
}
(5)Controller层:
package com.blog.controller.Vue;import com.blog.pojo.Images;
import com.blog.service.ImagesService;
import com.blog.util.FileUtil;
import com.blog.util.OSSClientUtil;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;/*** @author * @version 1.0* @description TODO* @date 2023/3/11 10:39*/@RestController
@RequestMapping("/images")
public class UploadController {@AutowiredImagesService imagesService;@PostMapping("/upload")public Map<String, Object> fileupload(MultipartFile file, HttpServletRequest req) throws IOException {if (file == null || file.getSize() <= 0) {throw new IOException("file不能为空");}//获取文件的大小,单位/KBlong size = file.getSize();OSSClientUtil ossClient=new OSSClientUtil();//将文件上传String name = ossClient.uploadImg2Oss(file);//获取文件的URl地址 以便前台 显示String imgUrl = ossClient.getImgUrl(name);HashMap<String, Object> map=new HashMap<>();//文件存储的路径map.put("name", imgUrl);Images images = new Images();images.setImg(imgUrl);System.out.println("添加数据");imagesService.insert(images);return map ;}}
(6)Service层:
package com.blog.service;import com.blog.pojo.Images;import java.util.List;public interface ImagesService {int insert(Images images);List<Images> getImages();
}
(7)ServiceImpl:
package com.blog.service.impl;import com.blog.dao.ImagesDao;
import com.blog.pojo.Images;
import com.blog.service.ImagesService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** @author * @version 1.0* @description TODO* @date 2023/3/12 10:38*/
@Service
public class ImagesServiceImpl implements ImagesService {@AutowiredImagesDao imagesDao;@Overridepublic int insert(Images images) {return imagesDao.insert(images);}@Overridepublic List<Images> getImages() {return imagesDao.getImages();}
}
(8)Dao层:
package com.blog.dao;import com.blog.pojo.Images;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;import java.util.List;@Mapper
@Repository
public interface ImagesDao {int insert(Images images);List<Images> getImages();
}
(9)xml层:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.blog.dao.ImagesDao"><resultMap id="images" type="Images"><id property="id" column="id"/><result property="img" column="img"/></resultMap><insert id="insert" parameterType="Images">insert into t_images (img)values (#{img});</insert><select id="getImages" resultMap="images">select * from t_images</select>
</mapper>
(10)实体类:
package com.blog.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @author * @version 1.0* @description TODO* @date 2023/3/12 10:33*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Images {private Integer id;private String img;
}
5、照片墙功能:
(1)前端项目结构:
(2)Waterfall组件(主要是通过一个瀑布流图片展示组件来实现)
<template><div class="m-waterfall-wrap" :style="`background: ${backgroundColor}; width: ${width}px; padding: ${columnGap}px; column-count: ${columnCount}; column-gap: ${columnGap}px;`"><div class="m-img" :style="`margin-bottom: ${columnGap}px;`" v-for="(item, index) in imageData" :key="index"><img class="u-img" :src="item.img" :title="item.title" :alt="item.title" /></div></div>
</template>
<script>/*纯CSS,实现简单,但图片顺序是每列从上往下排列*/export default {name: 'Waterfall',props: {imageData: { // 瀑布流的图片数组type: Array,required: true,default: () => {return []}},columnCount: { // 瀑布流要划分的列数type: Number,default: 3},columnGap: { // 瀑布流各列之间的间隙type: Number,default: 30},totalWidth: { // 瀑布流区域的总宽度type: Number,default: 1200},backgroundColor: { // 瀑布流区域背景填充色type: String,default: '#F2F4F8'}},computed: {width () {return this.totalWidth - 2 * this.columnGap}}}
</script>
<style lang="less" scoped>.m-waterfall-wrap {.m-img {.u-img {width: 100%;vertical-align: bottom;}}}
</style>
(3)ImagesShow.vue(照片墙显示页面,借助于上一个瀑布流图片展示组件)
=①在这里需要注意路径问题,这里./代表了本项目所在的目录,在引入组件地址的时候,要根据自己项目的实际路径合理改变!=
<template><div style="background-color: #fffef9"><p style="text-align: center;font-size: 24px;font-family: 'Adobe 黑体 Std R'" >图片展示墙</p><Waterfall:imageData="images":columnCount="3":columnGap="30":totalWidth="totalWidth"style="margin: 0 auto"backgroundColor="#f6f5ec" /></div>
</template>
<script>import Waterfall from '../../components/Waterfall.vue'import {list} from '../../api/images';export default {name: "images-show",components:{Waterfall},data(){return{//screenWidth: document.body.clientWidth, // 屏幕宽度totalWidth: document.body.clientWidth, // 屏幕高度images:[],}},mounted() {window.screenWidth = document.body.clientWidth;window.screenHeight = document.body.clientHeight;this.screenWidth = window.screenWidth;this.screenHeight = window.screenHeight;console.log(window.screenWidth);console.log(window.screenHeight);console.log(this.screenWidth);console.log(this.screenHeight);},created(){this.test();},methods:{test(){console.log("测试")list().then(res=>{this.images = res.data;console.log(res)})},}}
</script><style scoped></style>
(4)images.js
import request from '@/request/request'
export function list() {return request({url: '/imagesList/list',method: 'get',})
}
=配置到这里,那么前端核心的逻辑已经写完了=
(5)ImagesController
package com.blog.controller.Vue;import com.blog.pojo.Images;
import com.blog.service.ImagesService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** @author * @version 1.0* @description TODO* @date 2023/3/12 11:00*/
@RestController
@RequestMapping("/imagesList")
public class ImagesController {@AutowiredImagesService imagesService;@GetMapping("/list")public List<Images> getImagesList(){List<Images> images = imagesService.getImages();return images;}}
(6)关于service层、Dao层、实体类都在图片上传的ImagesService里,在这里我就不重复添加了!!!
6、总结:
(1)利用了vue、element组件搭建了前端
(2)利用SpringBoot、Mybatis实现了后端
(3)借助OSS组件将图片上传到了阿里云OSS
7、补充:
如果你对阿里云的OSS不太熟悉,那么给你推荐几篇博客,加速理解。
=(1)阿里云OSS注册及功能详解:=
https://blog.csdn.net/weixin_52851967/article/details/126924361
=(2)SpringBoot整合阿里云OSS云存储=
https://blog.csdn.net/qq_43021813/article/details/82665394
=(3)可能碰到的问题,以我为例,我创建的是私有Bucket,所以只有带着秘钥的时候才能访问,只根据图片路径而不带秘钥是无法访问的,这篇博客包含了我遇到的一些问题!=
https://blog.csdn.net/H_Q_Li/article/details/126471699
Vue+SpringBoot+OSS+element实现图片上传服务器+图片展示墙相关推荐
- Vue Element UI 之富文本图片上传服务器 + 图片地址插入富文本
该案例的情况 vue版本:vue cli3 插件:vue-quill-editor vue-quill-editor的增强模块:quill-image-extend-module quill-imag ...
- 使用vue+elementUi+springBoot实现图片上传,图片删除,图片展示
使用vue+elementUi+springBoot实现图片上传,图片删除,图片展示 环境配置 准备环境 使用软件 图片上传 图片删除 图片显示 所有代码均为参考,每个人的方法不一样,效果不一样,该代 ...
- 菜鸟的springboot项目图片上传及图片路径分析
菜鸟的springboot项目图片上传及图片路径分析 说明 一.图片路径分析 二.实现图片上传 (1)单文件上传(非异步) (2)单文件上传(异步) 三.总结 四.更新配置文件 说明 更新时间:202 ...
- vue+vant图片上传压缩图片大小
vue+vant图片上传压缩图片大小 可能在项目中大家都会遇到文件上传的需求,比如头像,图片等,但是太大的文件上传会给服务器造成很大大压力,那么我们就需要压缩上传的文件 其实这儿所说的压缩,就是图片重 ...
- springboot实现图片上传和图片删除
图片上传主要将需要上传的图片上传到对应的存储地址当中,再通过url访问图片就可以了:本文存储地址在本地,如果是在服务器上,配置服务器端的地址就可以了. controller @ApiOperation ...
- java 图片服务器 上传_Java实现把图片上传到图片服务器(nginx+vsftp)
前言: 在我另一篇笔记中已经记载了如何用nginx + vsftp搭建图片服务器(请参考nginx + vsftp搭建图片服务器),并且用vsftp的客户端工具filezilla测试过已经可用.但是在 ...
- Java实现把图片上传到图片服务器(nginx+vsftp)
在我另一篇笔记中已经记载了如何用nginx + vsftp搭建图片服务器,并且用vsftp的客户端工具filezilla测试过已经可用.但是在开发中应该是把用户在前端页面提交的图片保存到图片服务器中, ...
- ios java 图片上传到服务器,iOS 图片上传服务器
最近搞图片上传,折腾了一个星期终于做出来了,网上搜出来的方法几乎都是好几年前的,试了好多都不能用,此次把代码公布出来供大家参考. 注:部分代码是后台写的,此方法没用到第三方库. 1.图片保存到本地同时 ...
- HTML图片上传服务器
图片上传服务器 html <meta http-equiv="Content-Type" content="text/html; charset=utf-8&quo ...
最新文章
- 如何更优雅地对接第三方API
- mysql xml生成工具_自动生成po、dao、xml 工具:mybatis-generator
- 360题带你走进深度学习!吴恩达深度学习课程测试题中英对照版发布
- 每天一道LeetCode-----找到有多少个组合加起来和是n,每个组合的数字只能是1或者2
- oracle收集统计信息sql,Oracle自动统计信息的收集原理及实验
- [JS-BOM]BOM概念与组成
- mysql8优化实战
- 不知该买哪儿的房?数据分析来为你解答哪儿的房值得买
- 如何清除/删除终端中的当前行?
- AcWing 888. 求组合数 IV(高精度求组合数问题)
- Java for LeetCode 036 Valid Sudoku
- 【翻译】IdentityServer4:基于资源的配置
- Dictionary Union and Sort by value
- WINDOWS2016故障转移群集
- 用显卡加速c语言程序,教程 | 如何在Julia编程中实现GPU加速
- 数据结构二叉树学习1-前序序列创建二叉树
- 在别人的空间里看到的收藏在这里
- Stata:终极匹配ultimatch
- 测试无线网网速软件,技术员教你解决怎么测试无线网络网速
- 如何理解奇偶校验只能发现数据代码中奇数位出错的情况
热门文章
- python与hadoop的结合_跟着小编一起学习使用Python操作Hadoop,Python-MapReduce
- QString replace
- python+vue汽车俱乐部网站管理系统django
- 市场热门护照识别性能测评对比
- ❤️华为送别语: 出去之后,好好做人❤️
- 用函数输出一个一元二次方程的根
- 「PAT甲级真题解析」Advanced Level 1009 Product of Polynomials
- c/c++中system函数
- C实验题――求绝对值最大值
- Linux该怎么学?LINUX就该这么学(内含学习教程)【建议新手收藏】