可持续发展项目(八):拖拽功能后端对象提供


前言

为自己搭建一个可以自我思考的平台,其核心为“心想事成”。


一、思考过程?

后端框架搭建完成之后,如果不能允许以及访问不了接口也是不完美的。那么接着继续!

二、完善

接口设计思路

1、首先我要完成的是“心想事成”的第一步,其名为:实现可拖拽列表功能
2、该案例意为组件拖拽切换顺序
3、关于生成对应的Service、Mapper前置步骤就不介绍了(详情借鉴:可持续发展项目(二):后端框架搭建
4、后端主要是提供对象、数据存储、数据获取、数据修改等逻辑

开发过程中出现的问题(未解决,求解)

在组件对象中有imgUrl用来存储组件图片,我想着没有OSS服务器。那么将图片如何在前端展示,网上搜索是放在assets下即可以使用el-image展示出来,我也尝试实现了下放在assets下后确实展示出来了。那么就是将图片通过流的方式从本地A文件夹复制到前端项目的assets下,实现时貌似不行,el-upload组件在上传后调用后端接口获取到路径后展示图片为已删除图片的标识。我尝试在下面展示下复制的图片是可行的,哎,望广大网友能实现这功能提供借鉴。虽该功能已被我司大佬否定在线上并不实际,但我只是想尝试实现这个案例。最后el-upload上传的地方为我司的oss地址,以下是我的原后端逻辑。

1、文件上传接口(考虑到其中文件已经存过则不必重复存储,可以复用的图片)

package com.etp.sustainable.controller;

import com.etp.sustainable.service.FileService;
import com.etp.sustainable.util.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author ETP
 * @since 2023/10/23 16:06
 */
@Tag(name="组件管理")
@RestController
@AllArgsConstructor
@RequestMapping("/file")
public class FileController {

    private final FileService fileService;

    @SneakyThrows
    @PostMapping("upload")
    public R uploadFile(@RequestPart("file")  MultipartFile file) {
        String fileUrl = fileService.uploadFile(file);
        return R.ok(fileUrl);
    }

}

2、service层

package com.etp.sustainable.service;

import org.springframework.web.multipart.MultipartFile;

/**
 * @author ETP
 * @since 2023/10/23 16:07
 */
public interface FileService {

    /**
     * 文件上传
     * @param file
     */
    String uploadFile(MultipartFile file);

}

3、service实现层

package com.etp.sustainable.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etp.sustainable.domain.FileSecret;
import com.etp.sustainable.service.FileSecretService;
import com.etp.sustainable.service.FileService;
import com.etp.sustainable.util.MultipartFileToFile;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.security.MessageDigest;

/**
 * @author ETP
 * @since 2023/10/23 16:08
 */
@AllArgsConstructor
@Service
public class FileServiceImpl implements FileService {

    private final FileSecretService fileSecretService;

    @SneakyThrows
    @Override
    public String uploadFile(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        String fileUrl = "/sustainable/img/" + fileName;
//        String integrityUrl = "/sustainable/img/" + fileName;
        File source = null;
        try {
            //将MultipartFile转为File
            source = MultipartFileToFile.multipartFileToFile(file);
        } catch (Exception e) {
            e.printStackTrace();
        }

        FileSecret fileSecret = new FileSecret();
        if (source != null) {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            try (FileInputStream fis = new FileInputStream(source)) {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = fis.read(buffer)) != -1) {
                    md.update(buffer, 0, bytesRead);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] hash = md.digest();
            StringBuilder hexString = new StringBuilder();
            for (byte b : hash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            String sha256Hash = hexString.toString();
            fileSecret.setSecret(sha256Hash);

            LambdaQueryWrapper<FileSecret> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(FileSecret::getSecret, sha256Hash);
            FileSecret getFile = fileSecretService.getOne(lambdaQueryWrapper);
            if (getFile == null) {
                fileSecret.setFileUrl(fileUrl);
                fileSecretService.save(fileSecret);
                String path = "D:\\XLZ\\MyProject\\sustainable_front\\src\\assets\\img\\" + fileName;
                File toFile = new File(path);
                copyFileUsingFileStreams(source, toFile);
            }
        }
        return fileUrl;
    }

    public static void main(String[] args) {
        File source = new File("C:\\Users\\admin\\Pictures\\Saved Pictures\\2@2x.png");
        File toFile = new File("D:\\XLZ\\MyProject\\sustainable_front\\src\\assets\\img\\copyImg.png");
        try {
            copyFileUsingFileStreams(source, toFile);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static void copyFileUsingFileStreams(File source, File toFile)
            throws IOException {

        InputStream input = null;

        OutputStream output = null;

        try {

            input = new FileInputStream(source);

            output = new FileOutputStream(toFile);

            byte[] buf = new byte[1024];

            int bytesRead;

            while ((bytesRead = input.read(buf)) > 0) {

                output.write(buf, 0, bytesRead);

            }

        } finally {

            input.close();

            output.close();

        }

    }

}

4、FileSecret的文件摘要存储

package com.etp.sustainable.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import lombok.Data;

/**
 * 文件摘要
 * @TableName file_secret
 */
@TableName(value ="file_secret")
@Data
public class FileSecret implements Serializable {
    /**
     * 文件路径
     */
    @TableId
    private String fileUrl;

    /**
     * 文件摘要
     */
    private String secret;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 是否删除(0-否,1-是)
     */
    private Integer isDeleted;

    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

接口

1、组件类型Controller层

package com.etp.sustainable.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.etp.sustainable.domain.ComponentType;
import com.etp.sustainable.service.ComponentTypeService;
import com.etp.sustainable.service.KeywordRecordService;
import com.etp.sustainable.service.KeywordRelationService;
import com.etp.sustainable.util.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @author ETP
 * @since 2023/10/20 11:05
 */
@Tag(name="组件类型管理")
@RestController
@AllArgsConstructor
@RequestMapping("/componentType")
public class ComponentTypeController {

    private final ComponentTypeService componentTypeService;

    private final KeywordRecordService keywordRecordService;
    private final KeywordRelationService keywordRelationService;

    @GetMapping("page")
    public R page(Page<ComponentType> page, ComponentType componentType) {
        List<OrderItem> orderItems = new ArrayList<>();
        OrderItem orderItem = new OrderItem();
        orderItem.setColumn("create_time");
        orderItem.setAsc(false);
        orderItem.setColumn("sort");
        orderItem.setAsc(true);
        orderItems.add(orderItem);
        page.setOrders(orderItems);
        LambdaQueryWrapper<ComponentType> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(componentType.getName())) {
            lambdaQueryWrapper.eq(ComponentType::getName, componentType.getName());

            String name = componentType.getName();
            String[] nameArray = name.split("");
            keywordRecordService.saveKeywordRecord(nameArray, 3);
            keywordRelationService.saveKeywordRelation(nameArray, name, 3);
            List<String> nameWordList = new ArrayList<>();
            StringBuilder nameWord = new StringBuilder();
            int i = 1;
            for (String s : nameArray) {
                int nameIndex = i % 2;
                if (nameIndex == 0) {
                    nameWord.append(s);
                    nameWordList.add(nameWord.toString());
                    nameWord = new StringBuilder();
                } else {
                    nameWord.append(s);
                }
                i++;
            }
            List<String> stringList = nameWordList.stream().distinct().toList();
            keywordRecordService.saveKeywordRecordList(stringList, 3);
            keywordRelationService.saveKeywordRelationList(stringList, name, 3);
        }
        return R.ok(componentTypeService.page(page, lambdaQueryWrapper));
    }

    @GetMapping("/list")
    public R list(ComponentType componentType) {
        LambdaQueryWrapper<ComponentType> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.orderByDesc(ComponentType::getCreateTime);
        return R.ok(componentTypeService.list(lambdaQueryWrapper));
    }

    @PostMapping("/save")
    public R save(@RequestBody ComponentType componentType) {
        return R.ok(componentTypeService.selfSave(componentType));
    }

    @PutMapping("/update")
    public R update(@RequestBody ComponentType componentType) {
        return R.ok(componentTypeService.updateById(componentType));
    }

    @GetMapping("/{id}")
    public R getById(@PathVariable Long id) {
        return R.ok(componentTypeService.getById(id));
    }

    @DeleteMapping("/delById/{id}")
    public R delById(@PathVariable Long id) {
        return R.ok(componentTypeService.removeById(id));
    }

}

2、组件Controller层

package com.etp.sustainable.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.etp.sustainable.domain.Component;
import com.etp.sustainable.service.ComponentService;
import com.etp.sustainable.service.KeywordRecordService;
import com.etp.sustainable.service.KeywordRelationService;
import com.etp.sustainable.util.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @author ETP
 * @since 2023/10/20 11:04
 */
@Tag(name="组件管理")
@RestController
@AllArgsConstructor
@RequestMapping("/component")
public class ComponentController {

    private final ComponentService componentService;

    private final KeywordRecordService keywordRecordService;
    private final KeywordRelationService keywordRelationService;

    @GetMapping("page")
    public R page(Page<Component> page, Component component) {
        List<OrderItem> orderItems = new ArrayList<>();
        OrderItem orderItem = new OrderItem();
        orderItem.setColumn("create_time");
        orderItem.setAsc(false);
        orderItem.setColumn("sort");
        orderItem.setAsc(true);
        orderItems.add(orderItem);
        page.setOrders(orderItems);
        LambdaQueryWrapper<Component> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(component.getName())) {
            lambdaQueryWrapper.eq(Component::getName, component.getName());

            String name = component.getName();
            String[] nameArray = name.split("");
            keywordRecordService.saveKeywordRecord(nameArray, 3);
            keywordRelationService.saveKeywordRelation(nameArray, name, 3);
            List<String> nameWordList = new ArrayList<>();
            StringBuilder nameWord = new StringBuilder();
            int i = 1;
            for (String s : nameArray) {
                int nameIndex = i % 2;
                if (nameIndex == 0) {
                    nameWord.append(s);
                    nameWordList.add(nameWord.toString());
                    nameWord = new StringBuilder();
                } else {
                    nameWord.append(s);
                }
                i++;
            }
            List<String> stringList = nameWordList.stream().distinct().toList();
            keywordRecordService.saveKeywordRecordList(stringList, 3);
            keywordRelationService.saveKeywordRelationList(stringList, name, 3);
        }
        return R.ok(componentService.page(page, lambdaQueryWrapper));
    }

    @PostMapping("/save")
    public R save(@RequestBody Component component) {
        return R.ok(componentService.selfSave(component));
    }

    @PutMapping("/update")
    public R update(@RequestBody Component component) {
        return R.ok(componentService.updateById(component));
    }

    @GetMapping("/{id}")
    public R getById(@PathVariable Long id) {
        return R.ok(componentService.getById(id));
    }

    @DeleteMapping("/delById/{id}")
    public R delById(@PathVariable Long id) {
        return R.ok(componentService.removeById(id));
    }

}

3、组件排序接口

package com.etp.sustainable.controller;

import com.etp.sustainable.domain.req.SortReq;
import com.etp.sustainable.service.SortService;
import com.etp.sustainable.util.R;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author ETP
 * @since 2023/10/25 15:46
 */
@RestController
@AllArgsConstructor
@RequestMapping("/sort")
public class SortController {

    private final SortService sortService;

    @GetMapping("/list")
    public R list(SortReq req) {
        return R.ok(sortService.componentWithTypeList(req));
    }

}

4、请求对象(意在减少前端查询时需要请求的条件)

package com.etp.sustainable.domain.req;

import lombok.Data;

import java.util.List;

/**
 * @author ETP
 * @since 2023/10/25 15:49
 */
@Data
public class SortReq {

    /**
     * 名称
     */
    private String name;

    /**
     * 组件类型ID集合
     */
    private List<Long> componentTypeIdList;

}

5、返回对象(意在减少前端获取的数据字段,使其简洁)

package com.etp.sustainable.domain.resp;

import lombok.Data;

import java.util.List;

/**
 * @author ETP
 * @since 2023/10/25 15:49
 */
@Data
public class SortResp {

    /**
     * 主键ID
     */
    private Long id;

    /**
     * 类型ID
     */
    private Long typeId;

    /**
     * 名称
     */
    private String name;

    /**
     * 排序
     */
    private Integer sort;

    /**
     * 图片
     */
    private String imgUrl;

    /**
     * 组件字集列表
     */
    private List<SortResp> componentList;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要实现js拖拽功能,可以使用html5的拖放API或者jQuery UI等库来实现。下面是一个使用jQuery UI实现拖拽功能的例子: ```html <!DOCTYPE html> <html> <head> <title>拖拽功能实现</title> <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <script src="//code.jquery.com/jquery-1.12.4.js"></script> <script src="//code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jsPlumb/2.4.7/js/jsplumb.min.js"></script> <style type="text/css"> #container{ position: relative; width: 500px; height: 500px; border: 1px solid #000; } .block{ position: absolute; width: 50px; height: 50px; background-color: #f00; cursor: move; text-align: center; line-height: 50px; font-size: 20px; color: #fff; } </style> <script type="text/javascript"> $(function(){ //初始化jsPlumb实例对象 jsPlumb.ready(function(){ var instance = jsPlumb.getInstance({ Endpoint: ["Dot", {radius:2}], Connector:"StateMachine", HoverPaintStyle: {stroke:"#1e8151", strokeWidth:2 }, ConnectionOverlays: [ [ "Arrow", { location:1, id:"arrow", length:14, foldback:0.8 } ] ] }); }); //初始化拖拽功能 $(".block").draggable({ containment: "#container", stop: function(event, ui) { //更新jsplumb连接线 jsPlumb.repaint(ui.helper); } }); //初始化连接功能 jsPlumb.connect({ source: "block1", target: "block2" }); }); </script> </head> <body> <div id="container"> <div id="block1" class="block">1</div> <div id="block2" class="block" style="top: 100px; left: 100px;">2</div> </div> </body> </html> ``` 在上面的代码中,首先通过jQuery UI的draggable方法初始化了拖拽功能,然后通过jsPlumb的connect方法初始化了连接功能。同时在jsPlumb.ready方法中初始化了jsPlumb实例对象,以便后续使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值