SpringBoot业务开发 01、Springboot实战:实现Gitee图床上传及删除(含完整代码)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: SpringBoot业务开发 01、Springboot实战:实现Gitee图床上传及删除(含完整代码)

一、实际测试及配置


1.1、接口测试


测试工具Api-Post


包含两个接口:上传图片、删除图片。


上传图片:POST请求,body请求体使用multpart/form-data格式,图片文件名称为file。响应result结果为资源下载路径。



删除图片:POST请求,body使用application/json格式,携带url参数为待删除的图片地址。




1.2、项目配置及使用


核心修改配置点


只需要关注以下配置信息即可:



配置文件中配置的文件路径可覆盖Util中的文件路径,格式为xxx/形式



上面的配置好之后即可启动项目,默认端口为8081,对应的两个接口写在controller/GiteeController.java中:




配置点说明


我们需要提前准备好请求地址中的owner、repo以及请求体中access_token:


owner·:指的是个人空间,如下我的空间地址。



repo:指的是你要上传的仓库名称,如下图:



access_token:用来表示你身份的一串字符串,通过该token就能够确定你的身份!该token生成时只会显示一次,妥善保存好,我的已经生成好了:



关于目录:




二、Gitee的接口API


Gitee为开发者也提供了API,见:Gitee—API文档


对于上传图床我们只需要关注新建文件部分:请求url中{xxx}是我们需要自己填充的部分,下面Response Class是向gitee发出请求后得到的响应实体类结构,得到响应内容中我们关心的就是download_url属性,其是可供我们下载的图片地址。





下面是需要携带的请求体参数(封装到body中):access_token是每次请求必带的,其他的根据指定的接口携带




上传文件接口:POST请求,直接发送请求上传即可。请求体携带access_token、content(文件内容经过base64编码);最后在请求成功后响应对象里属性名为download_url的就是下载地址。


删除文件接口:①GET请求,调用获取仓库具体路径内容接口,取到sha属性。②DELETE请求,携带sha、access_token等其他请求体参数来调用删除接口。


获取sha的接口如下:




三、实现说明


3.1、依赖版本


spring-boot-starter-web:2.6.1


hutool-all:5.5.8


lombok:1.18.20


<!--    额外引入工具类    -->
<!--   lombok     -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>
<!--    Hutool工具类    -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.10</version>
</dependency>


本项目里使用hutool中的HttpUtil来发起请求调用。



3.2、项目结构



3.3、代码实现


config

定义一些调用Gitee的API响应属性:


/**
 * @ClassName Constant
 * @Author ChangLu
 * @Date 2021/12/11 0:36
 * @Description Gitee相关常量
 */
public class GiteeConstant {
    public static String RESULT_BODY_COMMIT = "commit";
    public static String RESULT_BODY_CONTENT = "content";
    public static String RESULT_BODY_DOWNLOAD_URL = "download_url";
    public static String RESULT_BODY_SHA = "sha";
}




controller

控制器:包含封装好的上传、删除接口


import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.changlu.springboot.Exception.CommonEnum;
import com.changlu.springboot.Exception.OwnException;
import com.changlu.springboot.config.GiteeConstant;
import com.changlu.springboot.domain.Basic.ResultBody;
import com.changlu.springboot.domain.Request.BasicRequest;
import com.changlu.springboot.utils.GiteeImgBedUtil;
import com.changlu.springboot.utils.WebTools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
/**
 * @ClassName GiteeController
 * @Author ChangLu
 * @Date 2021/12/1 0:05
 * @Description Gitee控制器
 */
@RestController
@Slf4j
public class GiteeController {
    @Value("${gitee.upload.path}")
    private String MEMBERS_UPLOAD_PATH;
    /**
     * 上传文件
     *
     * @param multipartFile 文件对象
     * @return
     * @throws IOException
     */
    @PostMapping("/gitee/upload")
    public ResultBody uploadFile(@RequestParam("file") MultipartFile multipartFile) throws IOException {
        log.info("uploadFile()请求已来临...");
        //根据文件名生成指定的请求url
        String originalFilename = multipartFile.getOriginalFilename();
        if (originalFilename == null) {
            log.info("服务器接收文件失败!");
            throw new OwnException(CommonEnum.IMAGE_EXIST_ERROR);
        }
        //Gitee请求:发送上传文件请求
        String JSONResult = GiteeImgBedUtil.uploadFile(MEMBERS_UPLOAD_PATH, originalFilename, multipartFile.getBytes());
        //解析响应JSON字符串
        JSONObject jsonObj = JSONUtil.parseObj(JSONResult);
        //请求失败
        if (jsonObj == null || jsonObj.getObj(GiteeConstant.RESULT_BODY_COMMIT) == null) {
            log.info("上传文件失败!");
            return ResultBody.fail(CommonEnum.IMAGE_UPLOAD_ERROR);
        }
        //请求成功:返回下载地址
        JSONObject content = JSONUtil.parseObj(jsonObj.getObj(GiteeConstant.RESULT_BODY_CONTENT));
        log.info("上传成功,下载地址为:" + content.getObj(GiteeConstant.RESULT_BODY_DOWNLOAD_URL));
        return ResultBody.success(content.getObj(GiteeConstant.RESULT_BODY_DOWNLOAD_URL));
    }
    /**
     * 删除文件
     *
     * @param request
     * @return
     */
    @PostMapping("/gitee/del")
    public ResultBody delFile(@RequestBody BasicRequest request) {
        //1、解析取得原始上传路径
        String url = request.getUrl();
        if (WebTools.isNotEmpty(url) && !url.contains("master/")) {
            log.info("url:" + url + " 无法解析路径!");
            throw new OwnException(CommonEnum.URL_PARSE_FAILED);
        }
        String path = url.substring(url.indexOf("master/") + 7);
        log.info("解析取得待删除路径:" + path);
        if (!WebTools.isEmpty(path)) {
            //2、Gitee请求:获取sha
            String shaResult = GiteeImgBedUtil.getSha(path);
            JSONObject jsonObj = JSONUtil.parseObj(shaResult);
            if (jsonObj == null) {
                log.info("delFile中获取sha失败!");
                return ResultBody.fail(CommonEnum.DEL_FILE_FAILED);
            }
            String sha = jsonObj.getStr(GiteeConstant.RESULT_BODY_SHA);
            //3、Gitee请求:发送删除请求
            String JSONResult = GiteeImgBedUtil.deleteFile(path, sha);
            jsonObj = JSONUtil.parseObj(JSONResult);
            if (jsonObj == null || jsonObj.getObj(GiteeConstant.RESULT_BODY_COMMIT) == null) {
                log.info("删除文件失败!");
                return ResultBody.fail(CommonEnum.DEL_FILE_FAILED);
            }
        }
        log.info("文件路径为:" + path + " 删除成功!");
        return ResultBody.success("删除成功!");
    }
}



domain

Basic


BaseExceptionInfoInterface.java:异常信息接口,之后枚举类会实现该接口


/**
 *  基本异常接口
 * @author changlu
 * @date 2021/07/22 17:03
 **/
public interface BaseExceptionInfoInterface {
    /**
     * 得到错误码
     * @date 2021/07/22 17:04
     * @return java.lang.String
     */
    Integer getResultCode();
    /**
     * 得到错误信息
     * @date 2021/07/22 17:05
     * @return java.lang.String
     */
    String getResultMsg();
}



ResultBody.java:响应体封装,统一接口返回对象


import com.changlu.springboot.Exception.CommonEnum;
import lombok.Data;
/**
 * @ClassName ResultBody
 * @Author ChangLu
 * @Date 2021/9/21 9:55
 * @Description 响应体封装
 */
@Data
public class ResultBody {
    /**
     * 响应码
     */
    private Integer code;
    /**
     * 响应消息
     */
    private String message;
    /**
     * 响应结果
     */
    private Object result;
    public ResultBody() {
    }
    /**
     * 内部封装
     * @param code
     * @param message
     */
    private ResultBody(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
    /**
     * 响应码与响应结果封装
     */
    public ResultBody(BaseExceptionInfoInterface baseErrorInfoInterface) {
        this.code = baseErrorInfoInterface.getResultCode();
        this.message = baseErrorInfoInterface.getResultMsg();
    }
    /**
     * 成功
     * @param data 数据
     * @return ResultBody
     */
    public static ResultBody success(Object data){
        ResultBody resultBody = new ResultBody(CommonEnum.SUCCESS);
        resultBody.setResult(data);
        return resultBody;
    }
    /**
     * 错误
     * @param baseErrorInfoInterface 枚举类
     * @return ResultBody
     */
    public static ResultBody fail(BaseExceptionInfoInterface baseErrorInfoInterface){
        ResultBody resultBody = new ResultBody(baseErrorInfoInterface);
        resultBody.setResult(null);
        return resultBody;
    }
    /**
     * 可自定义错误描述,
     * @param baseErrorInfoInterface
     * @param errMsg
     * @return
     */
    public static ResultBody fail(BaseExceptionInfoInterface baseErrorInfoInterface,String errMsg){
        ResultBody resultBody = fail(baseErrorInfoInterface);
        resultBody.setMessage(errMsg);
        return resultBody;
    }
    /**
     * 错误
     * @param code 状态码
     * @param message 描述信息
     * @return ResultBody
     */
    public static ResultBody fail(Integer code,String message){
        ResultBody resultBody = new ResultBody(code,message);
        resultBody.setResult(null);
        return resultBody;
    }
}




BasicRequest


用于取得对象体中的url属性,应用在删除接口中:


import lombok.Data;
import java.io.Serializable;
/**
 * @ClassName BasicRequest
 * @Author ChangLu
 * @Date 2021/12/10 23:53
 * @Description 请求对象封装
 */
@Data
public class BasicRequest implements Serializable {
    private static final long serialVersionUID = 1L;
    private String url;
}



Exception

CommonEnum.java:响应状态码及描述枚举类


import com.changlu.springboot.domain.Basic.BaseExceptionInfoInterface;
/**
 *  常见异常枚举类
 * @author changlu
 * @date 2021/07/22 17:05
 **/
public enum CommonEnum implements BaseExceptionInfoInterface {
    //成功情况
    SUCCESS(200,"成功!"),
    //图床异常处理
    IMAGE_EXIST_ERROR(1001, "服务器未接收到上传资源"),
    IMAGE_UPLOAD_ERROR(1002,"上传Gitee图床失败"),
    DEL_FILE_FAILED(1003,"图片删除失败"),
    URL_PARSE_FAILED(1004,"Gitee图片url无法解析"),
    //系统异常
    SYSTEM_ERROR(2000, "系统异常,请从控制台或日志中查看具体错误信息");
    //错误码
    private final Integer resultCode;
    //描述信息
    private final String resultMsg;
    CommonEnum(Integer resultCode, String resultMsg) {
        this.resultCode = resultCode;
        this.resultMsg = resultMsg;
    }
    @Override
    public Integer getResultCode() {
        return resultCode;
    }
    @Override
    public String getResultMsg() {
        return resultMsg;
    }
}



OwnException.java:自定义异常类,用于抛出一些自定义的异常信息以及用于全局异常处理器捕获


/**
 * @ClassName OwnException
 * @Author ChangLu
 * @Date 2021/7/29 23:40
 * @Description 自定义异常类
 */
public class OwnException extends RuntimeException{
    private final Integer code;
    private final String message;
    public OwnException(Integer code, String message){
        this.code = code;
        this.message = message;
    }
    public OwnException(CommonEnum ex){
        this(ex.getResultCode(),ex.getResultMsg());
    }
    public OwnException(CommonEnum ex, String msg){
        this(ex.getResultCode(),msg);
    }
    public Integer getCode() {
        return code;
    }
    @Override
    public String getMessage() {
        return message;
    }
}


handler

GlobalExceptionHandler.java:全局异常处理器,这里对于Exception以及自定义异常进行异常捕捉


import com.changlu.springboot.Exception.CommonEnum;
import com.changlu.springboot.Exception.OwnException;
import com.changlu.springboot.domain.Basic.ResultBody;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
/**
 * @ClassName GlobalExceptionHandler
 * @Author ChangLu
 * @Date 2021/12/11 0:04
 * @Description 全局异常捕获器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 处理全局异常(Exception)
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ResultBody handleException(HttpServletRequest request, Exception e){
        log.error("Exception:",e);
        return ResultBody.fail(CommonEnum.SYSTEM_ERROR);
    }
    /**
     * 自定义异常(可自行抛出针对于一些受检类型,继承RuntimeException)
     * @param ex 自定义抛出异常
     * @return xyz.changlu.util.ResultBody
     */
    @ExceptionHandler(value = OwnException.class)
    public ResultBody msgExceptionHandler(HttpServletRequest request, OwnException ex){
        log.error("OwnException:",ex);
        return ResultBody.fail(ex.getCode(),ex.getMessage());
    }
}



utils

FileUtil.java:文件工具类


/**
 * @ClassName FileUtils
 * @Author ChangLu
 * @Date 2021/8/1 18:18
 * @Description 文件工具类
 */
public class FileUtil {
    /**
     * 获取文件名的后缀,如:changlu.jpg => .jpg
     * @return 文件后缀名
     */
    public static String getFileSuffix(String fileName) {
        return fileName.contains(".") ? fileName.substring(fileName.indexOf('.')) : null;
    }
}


GiteeImgBedUtil:图床工具类,对外公开了三个API方法用来向Gitee发送请求


import cn.hutool.core.codec.Base64;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
 * @ClassName UploadGiteeImgBedUtil
 * @Author ChangLu
 * @Date 2021/12/10 23:41
 * @Description Gitee图床工具类
 */
public class GiteeImgBedUtil {
    /**
     * 码云私人令牌
     */
    private static final String ACCESS_TOKEN = "";  //这里不展示我自己的了,需要你自己补充
    /**
     * 码云个人空间名
     */
    private static final String OWNER = ""; 
    /**
     * 上传指定仓库
     */
    private static final String REPO = "";
    /**
     * 默认上传时指定存放图片路径
     */
    public static final String PATH = "test1/";
    //API
    /**
     * 新建(POST)、获取(GET)、删除(DELETE)文件:()中指的是使用对应的请求方式
     * %s =>仓库所属空间地址(企业、组织或个人的地址path)  (owner)
     * %s => 仓库路径(repo)
     * %s => 文件的路径(path)
     */
    private static final String API_CREATE_POST = "https://gitee.com/api/v5/repos/%s/%s/contents/%s";
    /**
     * 生成创建(获取、删除)的指定文件路径
     * @param originalFilename 原文件名
     * @param path 存储文件路径
     * @return
     */
    private static String createUploadFileUrl(String originalFilename,String path){
        String targetPath = path == null ? GiteeImgBedUtil.PATH : path;
        //获取文件后缀
        String suffix = FileUtil.getFileSuffix(originalFilename);
        //拼接存储的图片名称
        String fileName = System.currentTimeMillis()+"_"+ UUID.randomUUID().toString()+suffix;
        //填充请求路径
        String url = String.format(GiteeImgBedUtil.API_CREATE_POST,
                GiteeImgBedUtil.OWNER,
                GiteeImgBedUtil.REPO,
                targetPath + fileName);
        return url;
    }
    private static String createDelFileUrl(String path){
        //填充请求路径
        String url = String.format(GiteeImgBedUtil.API_CREATE_POST,
                GiteeImgBedUtil.OWNER,
                GiteeImgBedUtil.REPO,
                path);
        return url;
    }
    private static String createGetUrl(String path){
        String targetPath = path == null ? GiteeImgBedUtil.PATH : path;
        //填充请求路径
        String url = String.format(GiteeImgBedUtil.API_CREATE_POST,
                GiteeImgBedUtil.OWNER,
                GiteeImgBedUtil.REPO,
                targetPath);
        return url;
    }
    /**
     * 获取创建文件的请求体map集合:access_token、message、content
     * @param multipartFile 文件字节数组
     * @return 封装成map的请求体集合
     */
    private static Map<String,Object> getUploadBodyMap(byte[] multipartFile){
        HashMap<String, Object> bodyMap = new HashMap<>(3);
        bodyMap.put("access_token", GiteeImgBedUtil.ACCESS_TOKEN);
        bodyMap.put("message", "add file!");
        bodyMap.put("content", Base64.encode(multipartFile));
        return bodyMap;
    }
    /**
     * 创建普通携带请求体集合内容
     * @param map 额外参数
     * @param message 请求信息
     * @return
     */
    private static Map<String,Object> getCommonBodyMap(HashMap map, String message){
        HashMap<String, Object> bodyMap = new HashMap<>(2);
        bodyMap.put("access_token", GiteeImgBedUtil.ACCESS_TOKEN);
        bodyMap.put("message", message);
        if (map != null){
            bodyMap.putAll(map);
        }
        return bodyMap;
    }
    /**
     * **********封装好的实际调用方法*******************
     */
    //超时
    private static int TIMEOUT = 10 * 1000;
    /**
     * 上传文件
     * @param filename 文件名称
     * @param path 路径
     * @param sha 必备参数from 获取仓库具体路径下的内容
     * @return
     */
    public static String uploadFile(String path, String originalFilename, byte[] data){
        String targetURL = GiteeImgBedUtil.createUploadFileUrl(originalFilename,path);
        //请求体封装
        Map<String, Object> uploadBodyMap = GiteeImgBedUtil.getUploadBodyMap(data);
        return HttpUtil.post(targetURL, uploadBodyMap);
    }
    /**
     * 删除指定path路径下的文件
     * @param filename 文件名称
     * @param path 路径
     * @param sha 必备参数from 获取仓库具体路径下的内容
     * @return
     */
    public static String deleteFile(String path,String sha){
        String delFileUrl = createDelFileUrl(path);
        HashMap<String, Object> needMap = new HashMap<>(1);
        needMap.put("sha",sha);//添加sha参数
        return HttpUtil.createRequest(Method.DELETE, delFileUrl)
                .form(getCommonBodyMap(needMap,"del file!"))  //构建请求表单
                .timeout(TIMEOUT)
                .execute().body();
    }
    /**
     * 获取仓库具体路径下的内容,主要是获取 sha
     * @param path
     * @return
     */
    public static String getSha(String path){
        String getShaUrl = createDelFileUrl(path);
        return HttpUtil.createRequest(Method.GET, getShaUrl)
                .form(getCommonBodyMap(null, "get sha!"))
                .timeout(TIMEOUT)
                .execute().body();
    }
}



WebTools.java:常用工具类


/**
 * @ClassName WebTools
 * @Author ChangLu
 * @Date 2021/10/5 23:35
 * @Description 常用工具
 */
public class WebTools {
    /** 空字符串 */
    private static final String NULLSTR = "";
    /**
     * * 判断一个对象是否为空
     *
     * @param object Object
     * @return true:为空 false:非空
     */
    public static boolean isNull(Object object)
    {
        return object == null;
    }
    /**
     * * 判断一个字符串是否为空串
     *
     * @param str String
     * @return true:为空 false:非空
     */
    public static boolean isEmpty(String str)
    {
        return isNull(str) || NULLSTR.equals(str.trim());
    }
    /**
     * * 判断多个字符串是否为空串
     *
     * @param str String
     * @return true:为空 false:非空
     */
    public static boolean areEmpty(String...strs)
    {
        for (String str : strs) {
            if(isEmpty(str)){
                return true;
            }
        }
        return false;
    }
    /**
     * * 判断一个字符串是否为非空串
     *
     * @param str String
     * @return true:非空串 false:空串
     */
    public static boolean isNotEmpty(String str)
    {
        return !isEmpty(str);
    }
}


Application.yaml

这里要注意配置接口文件的大小,否则一些较大图片上传不了:


# 设置默认运行端口
server:
  port: 8081
# max-file-size:servlet每次接收单个文件的最大容量;max-request-size:指的是单次请求接收的文件最大容量
spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 100MB
# 自定义
# gitee上传的文件路径(可覆盖图床工具类中的默认存储文件路径)
gitee:
  upload:
    path: test1/
相关文章
|
8天前
|
缓存 监控 Java
|
8天前
|
缓存 监控 Java
|
30天前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
90 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
266 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
28天前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
329 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
30天前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
1月前
|
消息中间件 Java 大数据
大数据-56 Kafka SpringBoot与Kafka 基础简单配置和使用 Java代码 POM文件
大数据-56 Kafka SpringBoot与Kafka 基础简单配置和使用 Java代码 POM文件
62 2
|
1月前
|
前端开发 Java
学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例
文章介绍了如何使用SpringBoot创建简单的后端服务器来处理HTTP请求,包括建立连接、编写Controller处理请求,并返回响应给前端或网址。
51 0
学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例
|
17天前
|
监控 Java 开发者
掌握SpringBoot扩展接口:提升代码优雅度的16个技巧
【10月更文挑战第20天】 SpringBoot以其简化配置和快速开发而受到开发者的青睐。除了基本的CRUD操作外,SpringBoot还提供了丰富的扩展接口,让我们能够更灵活地定制和扩展应用。以下是16个常用的SpringBoot扩展接口,掌握它们将帮助你写出更加优雅的代码。
37 0
|
2月前
|
SQL JSON Java
springboot 如何编写增删改查后端接口,小白极速入门,附完整代码
本文为Spring Boot增删改查接口的小白入门教程,介绍了项目的构建、配置YML文件、代码编写(包括实体类、Mapper接口、Mapper.xml、Service和Controller)以及使用Postman进行接口测试的方法。同时提供了SQL代码和完整代码的下载链接。
springboot 如何编写增删改查后端接口,小白极速入门,附完整代码
下一篇
无影云桌面