[SpringBoot-vue3] 自定义图库

news2024/11/25 0:35:56

✨✨个人主页:沫洺的主页

 📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏 

                           📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏

💖💖如果文章对你有所帮助请留下三连✨✨

🧀图库效果图

描述:

在图库页面点击图片上传按钮,可通过Nginx服务器将图片保存到本地,并且将图片路径等信息保存到数据库,通过调用后端接口,可将数据库中存放的图片路径展示出来对应的图片

🥞环境搭建 

准备工作,上面提到我们需要Nginx代理服务器,先下载Nginx

 Nginx下载网址: nginx: download

解压到图片存储路径位置,可自定义(我的路径是D:\Develop\nginx-1.22.0\下,解压)
解压后在html下新建images文件夹(D:\Develop\nginx-1.22.0\nginx-1.22.0\html\images)

最后点击nginx.exe运行

找到C:\Windows\System32\drivers\etc文件夹
打开hosts文件(作用是定义IP地址和Host name(主机名)的映射关系)

添加一行127.0.0.1 moming.com(修改时可将此文件移到桌面,改好后覆盖源文件即可)

测试在images下放一个图片例如1.jpg


访问http://moming.com/images/1.jpg,访问成功即可

 创建数据库db5

CREATE TABLE `scm_images` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT 'Id',
  `img` varchar(255) NOT NULL COMMENT '图片路径',
  `name` varchar(255) NOT NULL COMMENT '图片名称',
  `createTime` datetime NOT NULL COMMENT '上传时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4;

🌭后端接口搭建 

SpringBoot+MyBatis

相关依赖

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.8.5</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.2.9</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.4</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>

entity

@Data
public class ImagesEntity {
    private Integer id;
    private String img;//图片地址
    private String name;//图片名字
    private LocalDateTime createTime = LocalDateTimeUtil.now();
}

dto

@Data
public class ImagesDto {
    private String imgBase64;
    private String imgName;
    private String imgUrl;
}

mapper

@Mapper
public interface  ImagesMapper{
    @Select("select * from scm_images  order by createTime desc")
    List<ImagesEntity> select();
}

service

@Service
public class ImagesService {
    @Autowired
    private ImagesMapper imagesMapper;

    public Integer add(ImagesDto imagesDto){
        String base64 = imagesDto.getImgBase64();
        String[] dataArray = StrUtil.splitToArray(base64, "base64,");
        byte[] bytes = Base64.decode(dataArray[1]);
        String imgName = imagesDto.getImgName();
        imgName = IdUtil.fastSimpleUUID() +"_"+ imgName;
        FileUtil.writeBytes(bytes,"D:/Develop/nginx-1.22.0/nginx-1.22.0/html/images/"+imgName);
        ImagesEntity entity = new ImagesEntity();
        entity.setImg("http://moming.com/images/"+imgName);
        entity.setName(imagesDto.getImgName());
        int rowNum = imagesMapper.insert(entity);
        return rowNum;
    }

    public List<ImagesDto> select(){
        List<ImagesEntity> entities = imagesMapper.select();
        List<ImagesDto> dtos = new ArrayList<>();
        for(ImagesEntity entity : entities){
            ImagesDto dto = new ImagesDto();
            dto.setImgUrl(entity.getImg());
            dtos.add(dto);
        }
        return dtos;
    }
}

controller

@RestController
@RequestMapping("/api/tuku")
public class ImagesController {
    @Autowired
    private ImagesService imagesService;

    @PostMapping("/add")
    public Integer add(@RequestBody ImagesDto imagesDto){
        return imagesService.add(imagesDto);
    }
    @GetMapping("/select")
    public List<ImagesDto> select(){
        return imagesService.select();
    }

}

🍕前端页面呈现

vue3-vite+TypeScript+Element Plus

api/tukuApi.ts

import http from "@/http/index"

export default  {
    select:{
        name:"图库查询",
        url:"/api/tuku/select",
        call: async function (params:any = {}) {
             return await http.get(this.url,params);
        }
    },
    add:{
        name:"图库添加",
        url:"/api/tuku/add",
        call: async function (params:any) {
             return await http.post(this.url,params);
        }
    },
}

api/index.ts

import tukuApi from "./tukuApi";
export {tukuApi}

router/index.ts

import { createRouter, createWebHistory } from "vue-router";
const routes = [
    {
        path: '/tuku',
        name: 'tuku',
        component: () => import("@/views/tools/Tuku.vue"),
        meta:{ title:"图库" ,icon:"Coordinate",show:true,useFrame:true}
    },

]
const router = createRouter({
    history: createWebHistory(),
    routes
})
export default router

views/tools/Tuku.vue

<template>
    <el-upload class="avatar-uploader" :auto-upload="false" :show-file-list="false" :on-change="onChange">
        <img v-if="imgData.imgBase64" :src="imgData.imgBase64" class="avatar" />
        <el-icon v-else class="avatar-uploader-icon">
            <Plus />
        </el-icon>
    </el-upload>
    <el-divider border-style="dashed" />
    <el-row :gutter="20">
        <el-col v-for="item in imgList">
            <el-image class="demo-image" @click='copy(item.imgUrl)'
                :src="item.imgUrl" />
        </el-col>

    </el-row>
</template>
<script setup lang="ts">
import { onMounted, ref, reactive } from 'vue'
import {tukuApi} from "@/api/index"
import { ElMessage } from 'element-plus'
import useClipboard from 'vue-clipboard3'

const { toClipboard } = useClipboard()
const imgList = ref([])
const imgData = reactive({
    imgBase64: '',
    imgName: ""
})
const copy = async (imgUrl: string) => {
    await toClipboard(imgUrl)
    ElMessage.success('复制成功')
}
onMounted(() => {
    callTukuApi()
})
const callTukuApi = () => {
    tukuApi.select.call().then((res) => {
        imgList.value = res
    })
}
const onChange = (uploadFile: any, uploadFiles: any) => {

    var reader = new FileReader();
    reader.readAsDataURL(uploadFile.raw);
    reader.onload = () => {
        imgData.imgBase64 = reader.result;
        imgData.imgName = uploadFile.raw.name;

        tukuApi.add.call({ imgBase64: imgData.imgBase64, imgName: imgData.imgName }).then((res) => {
            if (res === 1) {
                ElMessage.success('上传成功')
                callTukuApi()
                setTimeout(()=>{
                    imgData.imgBase64=""
                },2000)
            }
        })

    }


}
</script>

<style scoped>
.avatar-uploader .avatar {
    width: 100px;
    height: 100px;
    display: block;
}

.avatar-uploader .el-upload {
    border: 2px dashed var(--el-color-primary);
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
    border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
    font-size: 28px;
    color: #3f2a67;
    width: 100px;
    height: 100px;
    text-align: center;
    border: 1px dashed var(--el-color-primary);
}

.demo-image {
    border-radius: 0.2rem;
    width: 100px;
    height: 100px;
    cursor: pointer;
}

.el-col-24 {
    flex: 0 0 0%;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring框架的IOC和AOP的简单项目实现

一、Spring框架介绍 Spring框架是为了解决企业应用开发复杂性而创建的&#xff0c;是Java应用钟最广的框架&#xff0c;它的成功来源于设计思想&#xff0c;而不是技术本身&#xff0c;即IOC&#xff08;inversion of control&#xff0c;控制反转&#xff09; 和AOP&#xff…

攻防世界-adworld-reverse-game

#adworld-reverse-game 从1依次输入到8,每个数字会车,最后通关,获得flag |-----------------------▲--------||-----------------------●--------||-----------------------◆--------||-----------------------■--------||--------------------|-----------------------…

vite 静态资源打包配置,echart 主题引入,build上线问题,vue3-echart5使用

文章目录前情提要原因分析实战解析最后前情提要 在经历了vite打包实战后&#xff0c;我入手了echart实战&#xff0c;线下运行一切正常&#xff0c;但是打包上线后出现了异常 TypeError: Cannot create property series onstring <IDOCTYPE html>,挑战又来了&#xff0c…

抖音开发对接之订单取消消息

目录 前言 一、抖音开发中的订单取消消息 二、抖音运营反馈的业务需求分析 三、整体的业务开发思路 四、订单取消消息的代码开发 1.订单取消消息的使用 2.实时保存抖音平台过来的订单取消消息 3.具体的订单业务处理 总结 前言 这里主要是介绍一下抖音开放平台的这个消…

Redis数据结构之字典

目录 字典的应用场景 源码实现 hash算法的实现&#xff0c; hash冲突的解决 扩容缩容机制 哈希表的扩展与收缩条件 渐进式rehash 线程是否安全 Redis的dictht 和 Java(jdk1.8)的HashMap有什么区别 线程安全性 hash算法 解决hash冲突的方法 扩容机制 字典的应用场景…

Navicat的安装及如何将PG库内的数据导出CSV

一、Navicat的安装 1、安装 双击安装 Navicat Premium 12.0.18.0 简体中文 64位.exe 2、编辑连接&#xff0c;进行连接测试 具体配置信息可以进docker容器内查看 二、将PG库内的数据导出CSV 1、进入docker容器&#xff08;docker exec -it postgres_v3 bash&#xff09;&#…

中国开源年会报名 | StarRocks 极速湖仓分析的探索与实践

开源年度盛会 2022 第七届中国开源年会 (COSCon22) 来啦&#xff01; 本次年会将于 10 月 29-30 日由开源社举办&#xff0c;线上共设有1个主论坛和16个分论坛&#xff0c;线下分会场遍布成都、深圳、上海、北京等11个城市。StarRocks PMC 赵恒将代表社区出席大数据专场&#…

【Python】pycharm 和 vscode 编辑器设置模版

author: jwensh time: 2022.10.29 1. pycharm 模版 打开 PyCharm 设置界面&#xff0c;搜索 template&#xff0c;选择 File and Code Templates > Python Script 如下图所示&#xff0c;输入自定义模板代码 模版内容设置 #!/usr/bin/env python # -*- coding: utf-8 -*…

非遗在线商城小程序(后台PHP开发)

目 录 1绪论 1 1.1 选题及意义 1 1.2 国内外文献综述 2 1.3 研究的主要内容 3 2 系统工具 5 2.1 微信小程序 5 2.2 ThinkPHP 5 框架 7 2.3 RESTFul API 8 2.4 微信支付技术 10 2.5 MySQL数据库 12 3 系统分析 14 3.1 市场定位分析 14 3.2 可行性分析 14 3.3 需求目标 14 3.3.1 …

彻底理解Java并发:ReentrantLock锁

本篇内容包括&#xff1a;为什么使用 Lock、Lock 锁注意事项、ReentrantLock 和 synchronized 对比、ReentrantLock &#xff08;加锁、解锁、公平锁与非公平锁、ReentrantLock 如何实现可重入&#xff09;等内容。 一、Lock 锁 1、为什么使用 Lock synchronized 线程等待时间…

Filter快速入门、Filter执行流程、Filter使用细节、Listener概念、分类、ServletContextListener使用

文章目录FilterFilter快速入门Filter 执行流程Filter使用细节ListenerServletContextListener 使用Filter 概念&#xff1a;Filter表示过滤器&#xff0c;是 JavaWeb三大组件&#xff08;Servlet、Filter、Listener&#xff09;之一。过滤器可以把对资源的请求拦截下来&#x…

DASCTF X GFCTF 2022十月挑战赛web

前言 晚来的比赛web题解&#xff0c;这次buu的十月赛web部分的题目对于我来说质量还是蛮高的&#xff0c;因为这几天比较忙&#xff0c;一直没有去复现总结&#xff0c;不过该复现的还得复现&#xff0c;复现了这次比赛又能学到不少知识&#xff0c;嘿嘿嘿。 EasyPOP 考察ph…

Mega-Nerf学习笔记

Mega-NeRF:Scalable Construction of Large-Scale NeRFs for Virtual Fly-Throughs 主页&#xff1a;https://meganerf.cmusatyalab.org/ 论文&#xff1a;https://meganerf.cmusatyalab.org/resources/paper.pdf 代码&#xff1a;https://github.com/cmusatyalab/mega-nerf …

【设计模式】简单工厂模式

简单工厂模式–》工厂模式—》抽象工厂模式 文章目录简单工厂模式定义&#xff1a;各个角色1. 抽象产品类2. 具体产品类&#xff1a;3. 工厂类&#xff1a;简单工厂模式的核心。客户端设计图表未使用简单工厂模式&#xff1a;出现的问题&#xff1a;使用简单工厂模式&#xff1…

小熊派-FreeRTOS-点灯学习过程-20221029

一、前言准备 1、小熊派一个&#xff08;STM32L431RCT6&#xff09; 2、STM32CubeMX 3、keil5 4、小熊派的配套开发资料&#xff08;用于出问题的时候替换&#xff09; 二、实现过程 代码主要由STM32CubeMX生成&#xff0c;所以过程主要是配置CubeMX. 1、芯片选型 STM3…

用 Pyinstaller 模块将 Python 程序打包成 exe 文件(全网最全面最详细)

目录 打包前置知识 一、什么是exe可执行文件&#xff1f; 二、为什么要将 Python 程序打包为 exe 可执行文件&#xff1f; 三、为什么 Python 程序不能直接运行呢&#xff1f; 四、我们用什么来打包 Python 文件呢&#xff1f; 五、打包有哪几种分类呢&#xff1f; 打包…

【ArcGIS微课1000例】0041:ArcGIS利用坐标生成点的方法总结

本文讲解ArcGIS利用坐标生成点的3种方法。 文章目录 一、转到XY工具定位二、输入绝对XY生成点三、添加XY数据一、转到XY工具定位 这样确实可以在图上快速定位某个经纬度的点,但是生成的对象是“注记类”要素,即不是地理实体,而仅仅是为了绘图表现的东西。可以用如下工具来控…

Kotlin协程-并发处理-基础

一、协程与并发 Kotlin协程是基于线程执行的。经过一层封装以后&#xff0c;Kotlin协程面对并发&#xff0c;处理方式与Java不同。 在java的世界里&#xff0c;并发往往是多个线程一起工作&#xff0c;存在共享的变量。需要处理好同步问题。要避免把协程与线程的概念混淆。 …

验证码的编写

编写一个验证码(可以通过键盘输入需要获取验证码的位数)&#xff1a; public class IdentifyingCode {public static void main(String[] args) {//验证码的编写IdentifyingCode identifyingCode new IdentifyingCode();//扫描键盘输入Scanner scanner new Scanner(System.i…

【数据结构基础】之数组介绍,生动形象,通俗易懂,算法入门必看

【数据结构基础】数组前言一、数组的定义1.基本概念和内存图2.数组的性质3.数据结构二、玩转数组1.循环遍历打印数组的每一个值2.查找一个数组里存在的值3.打擂台的形式找最大值4.元素的位移5.数组的扩容6.数组的反转三、二维数组四、初识算法1.排序算法2.查找算法3.算法性能4.…