【SpringBoot新手篇】SpringBoot优雅文件上传方式

2023-11-09

工作中上传文件是常见的场景之一,最典型的情况就是上传头像等,上传文档。自己上传文件中遇到的坑,自己已经填了,现在把它写下来,方便提醒自己,我使用的是Spring Boot 上传文件

Pom

主要引入了webthymeleaf启动器

<!-- web start-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- web end-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!-- io常用工具类 -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.5</version>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>

yml

spring:
  servlet:
    multipart:
      max-file-size: 10MB  # 最大支持文件大小
      max-request-size: 10MB  # 最大支持请求大小
      #enabled: true  #默认支持文件上传.
      # file-size-threshold: #支持文件写入磁盘.
      #location: #上传文件的临时目录

controller

UploadController

UploadController首页的显示

@Controller
public class UploadController {

    @GetMapping("/")
    public String index() {
        return "upload";
    }

}

FileController

FileController文件上传,下载请求

文件上传

/**
     * @author: 三月三
     * @description:  单个文件上传
     * @param: [file]
     * @return: java.lang.String
     */
    @RequestMapping(value = "/upload")
    public String upload(HttpServletRequest request, @RequestParam("file") MultipartFile file, Model model) {
        // 测试MultipartFile接口的各个方法
        System.out.println("文件类型ContentType=" + file.getContentType());
        System.out.println("文件组件名称Name=" + file.getName());
        System.out.println("文件原名称OriginalFileName=" + file.getOriginalFilename());
        System.out.println("文件大小Size=" + file.getSize()/1024 + "KB");
        try {
            if (file.isEmpty()) {
                return "文件为空";
            }
            // 获取文件名
            String fileName = file.getOriginalFilename();
            log.info("上传的文件名为:" + fileName);
            // 获取文件的后缀名
            String suffixName = fileName.substring(fileName.lastIndexOf("."));
            log.info("文件的后缀名为:" + suffixName);

            // 获取文件相对类路径
            //String filePath = request.getServletContext().getRealPath("/");
            //文件绝对路径,项目中一般使用相对类路径,即使文件变更路径也会跟着变
            String filePath = request.getServletContext().getRealPath("G:\\dev_workspace\\springboot-learning-examples\\springboot-13-fileupload\\src\\main\\resources\\static");
            System.out.println("path = " + filePath);
            //构造一个路径
            String newImg = UUID.randomUUID()+suffixName;
            String path = filePath + newImg;
            log.info("构造路径"+path);

            File dest = new File(path);
            // 检测是否存在目录
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();// 新建文件夹
            }
            file.transferTo(dest);// 文件写入
            model.addAttribute("msg","<font color=\"green\">上传成功</font>");
            model.addAttribute("img",newImg);
            return "upload";
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        model.addAttribute("msg","<font color=\"green\">上传失败</font>");
        return "upload";
    }

多文件上传

 /**
     * @author: 三月三
     * @description: 多个文件上传
     * @param: [request]
     * @return: java.lang.String
     */
    @PostMapping("/batch")
    public String handleFileUpload(Model model,HttpServletRequest request) {
        List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");
        MultipartFile file = null;
        BufferedOutputStream stream = null;
        for (int i = 0; i < files.size(); ++i) {
            file = files.get(i);
            //文件绝对路径,项目中一般使用相对类路径,即使文件变更路径也会跟着变
            String filePath = request.getServletContext().getRealPath("G:\\dev_workspace\\springboot-learning-examples\\springboot-13-fileupload\\src\\main\\resources\\static");
            if (!file.isEmpty()) {
                try {
                    byte[] bytes = file.getBytes();
                    stream = new BufferedOutputStream(new FileOutputStream(
                            new File(filePath + file.getOriginalFilename())));//设置文件路径及名字
                    stream.write(bytes);// 写入
                    stream.close();
                } catch (Exception e) {
                    stream = null;

                    model.addAttribute("msg", "第 " + i + " 个文件上传失败 ==> "
                            + e.getMessage());
                    return "upload";
                }
            } else {
                model.addAttribute("msg","第 " + i
                        + " 个文件上传失败因为文件为空");
                return "upload";
            }
        }
        model.addAttribute("msg","上传成功");
        return "upload";
    }

文件下载

/**
     * @author: 三月三
     * @description:  文件下载
     * @param: [model, request, response, fileName]
     * @return: java.lang.String
     */
    @PostMapping("/download")
    public String downloadFile(Model model,HttpServletRequest request, HttpServletResponse response,String fileName) {
        if (fileName != null) {
            //设置文件路径   真实环境是存放在数据库中的
           // String filePath = request.getServletContext().getRealPath("/");
            //文件绝对路径,项目中一般使用相对类路径,即使文件变更路径也会跟着变
            String filePath = request.getServletContext().getRealPath("G:\\dev_workspace\\springboot-learning-examples\\springboot-13-fileupload\\src\\main\\resources\\static");
            File file = new File(filePath);
            if (file.exists()) {
                response.setContentType("application/force-download");// 设置强制下载不打开
                response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名
                byte[] buffer = new byte[1024];
                FileInputStream fis = null;
                BufferedInputStream bis = null;
                try {
                    fis = new FileInputStream(file);

                    bis = new BufferedInputStream(fis);
                    // 创建输出对象
                    OutputStream os = response.getOutputStream();
                    int i = bis.read(buffer);
                    while (i != -1) {
                        os.write(buffer, 0, i);
                        i = bis.read(buffer);
                    }
                    model.addAttribute("msg","<font color=\"green\">下载成功</font>");
                    return "upload";
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (bis != null) {
                        try {
                            bis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        model.addAttribute("msg","<font color=\"red\">下载失败</font>");
        return "upload";
    }

页面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>

<h1>Spring Boot file upload example</h1>

<p>单文件上传</p>
<form action="upload" method="POST" enctype="multipart/form-data">
    文件:<input type="file" name="file"/>
    <input type="submit"/>
</form>

<span  th:if="${msg!=null}" th:utext="${msg}"></span>


<div th:if="${img!=null}">
    <img th:src="${img}">
    <p>文件下载</p>
    <form action="download" method="post">
        <input type="hidden" th:value="${img}" name="fileName"/>
        <input type="submit" value="下载文件"/>
    </form>
</div>


<p>多文件上传</p>
<form method="POST" enctype="multipart/form-data" action="batch">
    <p>文件1:<input type="file" name="file"/></p>
    <p>文件2:<input type="file" name="file"/></p>
    <p><input type="submit" value="上传"/></p>
</form>
</body>
</html>

BUG

  1. 文件上传路径问题
  2. 文件下载的路径问题

解决:

  1. String filePath = request.getServletContext().getRealPath("/");获取的是tomcat目录下webapps下的目录及类路径(class文件存放的路径),因为我使用的是SpringBoot项目,而SringBoot项目内嵌了tomcat,路径为C:\Users\L15096000421\AppData\Local\Temp\tomcat-docbase.2191751665660359817.8080\的一个临时目录,重启项目,文件就丢失了
  2. 还有使用String filePath = request.getServletContext().getRealPath("/")做为下载的路径去下载文件,后台报错没有权限,使用绝对路径下载,及使用绝对路径上传
  3. 可以使用 private static final String parentPath = ClassUtils.getDefaultClassLoader().getResource("static/images").getPath();获取springboot项目static/images的目录

封装版

工具类

StringUtil

/**
 * 字符串工具类,抽取一些常用操作
 */
public class StringUtil {

    /**
     * 判断val是否不为空(null/"")
     * @param val
     * @return
     */
    public static boolean isNotEmpty(String val){
        return val != null && !"".equals(val);
    }

    /**
     * 将给定的驼峰命名值转换为下划线命名
     * @param val
     * @return
     */
    public static String toUnderScoreCase(String val){
        if(!isNotEmpty(val)){
            return val;
        }
        StringBuilder sb = new StringBuilder(val);
        for(int i = 0; i < sb.length(); i++){
            if(sb.charAt(i) >= 'A' && sb.charAt(i) <= 'Z'){
                //将大写字母 "A" 替换为 "_a"
                sb.replace(i, i + 1, "_" + (char)(sb.charAt(i) + 32));
            }
        }
        return sb.toString();
    }

}

MimeTypeUtils

/**
 * 媒体类型工具类
 *
 */
public class MimeTypeUtils
{
    public static final String IMAGE_PNG = "image/png";

    public static final String IMAGE_JPG = "image/jpg";

    public static final String IMAGE_JPEG = "image/jpeg";

    public static final String IMAGE_BMP = "image/bmp";

    public static final String IMAGE_GIF = "image/gif";

    public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };

    public static final String[] DEFAULT_ALLOWED_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};

    public static String getExtension(String prefix)
    {
        switch (prefix)
        {
            case IMAGE_PNG:
                return "png";
            case IMAGE_JPG:
                return "jpg";
            case IMAGE_JPEG:
                return "jpeg";
            case IMAGE_BMP:
                return "bmp";
            case IMAGE_GIF:
                return "gif";
            default:
                return "";
        }
    }
}

FileUploadUtils

/**
 * 文件上传工具类
 */
public class FileUploadUtils
{
    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;

    /**
     * 默认的文件名最大长度 100
     */
    public static final int DEFAULT_FILE_NAME_LENGTH = 100;

    /**
     * 默认存储图片目录
     */
    private static final String parentPath = ClassUtils.getDefaultClassLoader().getResource("static/images").getPath();

    public static final String actorPath = "/actor";
    public static final String cinemaPath = "/cinema";
    public static final String moviePath = "/movie";
    public static final String userPath = "/user";


    /**
     * 默认上传的地址
     */
    private static String defaultBaseDir = userPath;

    public static void setDefaultBaseDir(String defaultBaseDir)
    {
        FileUploadUtils.defaultBaseDir = defaultBaseDir;
    }

    public static String getDefaultBaseDir()
    {
        return defaultBaseDir;
    }

    public static String getParentPath() {
        return parentPath;
    }

    /**
     * 以默认配置进行文件上传
     *
     * @param file 上传的文件
     * @return 文件名称
     * @throws Exception
     */
    public static final String upload(MultipartFile file) throws IOException
    {
        try
        {
            return upload(getParentPath() + getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        }
        catch (Exception e)
        {
            throw new IOException(e.getMessage(), e);
        }
    }

    /**
     * 文件上传
     *
     * @param baseDir 相对应用的基目录
     * @param file 上传的文件
     * @param allowedExtension 上传文件类型
     * @return 返回上传成功的文件名
     */
    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
            InvalidExtensionException
    {
        int fileNamelength = file.getOriginalFilename().length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
        {
            throw new FileNameLengthLimitExceededException("文件名称长度不能超过" + FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }
        //文件大小校验
        assertAllowed(file, allowedExtension);
        //编码文件名
        String fileName = extractFilename(file);
        //
        File desc = getAbsoluteFile(baseDir, fileName);
        file.transferTo(desc);
        String pathFileName = getPathFileName(baseDir, fileName);
        return pathFileName;
    }

    /**
     * 编码文件名 如 : images/user/2020/12/4/***.png
     */
    public static final String extractFilename(MultipartFile file)
    {
        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        fileName = DateFormatUtils.format(new Date(), "yyyy/MM/dd") + "/" + UUID.randomUUID().toString().replaceAll("-","") + "." + extension;
        return fileName;
    }

    private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
    {
        File desc = new File(uploadDir + File.separator + fileName);

        if (!desc.getParentFile().exists())
        {
            desc.getParentFile().mkdirs();
        }
        if (!desc.exists())
        {
            desc.createNewFile();
        }
        return desc;
    }

    private static final String getPathFileName(String uploadDir, String fileName) throws IOException
    {
        int dirLastIndex = parentPath.length() + 1;
        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
        String pathFileName = "/images/" + currentDir + "/" + fileName;
        return pathFileName;
    }

    /**
     * 文件大小校验
     *
     * @param file 上传的文件
     * @return
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws InvalidExtensionException
     */
    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, InvalidExtensionException
    {
        long size = file.getSize();
        if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE)
        {
            throw new FileSizeLimitExceededException("文件大小不能超过" + DEFAULT_MAX_SIZE / 1024 / 1024 + "MB");
        }

        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
        {
           // if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)

                throw new InvalidExtensionException("图片格式不支持" + extension + "格式");

        }

    }

    /**
     * 判断MIME类型是否是允许的MIME类型
     *
     * @param extension
     * @param allowedExtension
     * @return
     */
    public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
    {
        for (String str : allowedExtension)
        {
            if (str.equalsIgnoreCase(extension))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取文件名的后缀
     *
     * @param file 表单文件
     * @return 后缀名
     */
    public static final String getExtension(MultipartFile file)
    {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (!StringUtil.isNotEmpty(extension))
        {
            extension = MimeTypeUtils.getExtension(file.getContentType());
        }
        return extension;
    }

}

异常类

FileNameLengthLimitExceededException

/**
 * 文件名字长度超过限制异常,用于文件校验
 */
public class FileNameLengthLimitExceededException extends RuntimeException{

    private static final long serialVersionUID = 1L;

    public FileNameLengthLimitExceededException(){

    }

    public FileNameLengthLimitExceededException(String message){
        super(message);
    }

}

FileSizeLimitExceededException

/**
 * 文件大小超过限制异常,用于文件校验
 */
public class FileSizeLimitExceededException extends RuntimeException{

    private static final long serialVersionUID = 1L;

    public FileSizeLimitExceededException(){

    }

    public FileSizeLimitExceededException(String message){
        super(message);
    }

}

InvalidExtensionException

/**
 * 文件后缀无效异常,用于文件校验
 */
public class InvalidExtensionException extends RuntimeException{

    private static final long serialVersionUID = 1L;

    public InvalidExtensionException(){

    }

    public InvalidExtensionException(String message){
        super(message);
    }

}

Controller层

multifile.html页面

    <form action="/uploadFile" method="post" enctype="multipart/form-data">
        <p align="center">选择文件1:<input type="file" name="file"/></p>
        <p align="center"><input type="submit" value="提交"/></p>
    </form>

Controller

    @PostMapping("/uploadFile")
    public String uploadFile(@RequestPart("file") MultipartFile file,Model model) throws IOException {
        String upload = FileUploadUtils.upload(file);

        log.info("上传路径:{}",upload);
        model.addAttribute("uploadUrl",upload);
        return "img";
    }

img.html页面

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<img th:src="@{http://localhost:8080{uploadUrl}(uploadUrl=${uploadUrl})}"/>
</body>
</html>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【SpringBoot新手篇】SpringBoot优雅文件上传方式 的相关文章

  • 如何使用Spring WebClient进行同步调用?

    Spring Framework in 休息模板 https docs spring io spring framework docs current javadoc api org springframework web client R
  • NoInitialContextException:heroku 战争部署

    我一直在开发一个 J2EE 项目 并且在其中使用连接池 也通过部署在 heroku 上的数据库进行访问 我使用以下代码来设置 Connection 对象 Context initContext new InitialContext Cont
  • “java.io.IOException:连接超时”和“SocketTimeoutException:读取超时”之间有什么区别

    如果我设置一个套接字 SoTimeout 并从中读取 当读取时间超过超时限制时 我会收到 SocketTimeoutException 读取超时 这是我的例子中的堆栈 java net SocketTimeoutException Read
  • Java 7 默认语言环境

    我刚刚安装了 jre7 我很惊讶地发现我的默认区域设置现在是 en US 对于jre6 它是de CH 与jre7有什么不同 默认区域设置不再是操作系统之一吗 顺便说一句 我使用的是Windows7 谢谢你的回答 编辑 我已经看到了语言环境
  • Android 中的列表(特别是 RecyclerView 和 CardView)如何工作

    请原谅我问这个问题 但我是 Android 开发新手 尽管我正在尝试了解developer android com 网站上的基础知识 但大多数示例 即使他们说它们是为 Android Studio 构建的 尚未设置为使用 Gradle 因此
  • 如何使用 JAVA 代码以编程方式捕获线程转储?

    我想通过 java 代码生成线程转储 我尝试使用 ThreadMXBean 为此 但我没有以正确的格式获得线程转储 因为我们正在使用jstack命令 请任何人提供一些帮助 他们是否有其他方式获取线程转储 使用任何其他 API 我想要的线程转
  • HAProxy SSL终止+客户端证书验证+curl/java客户端

    我希望使用我自己的自签名证书在 HAProxy 上进行 SSL 终止 并使用我创建的客户端证书验证客户端访问 我通过以下方式创建服务器 也是 CA 证书 openssl genrsa out ca key 1024 openssl req
  • 如何将jscrollpane添加到jframe?

    我有以下源代码 有人可以给我建议如何将 jscrollpane 添加到 jframe 上吗 我尝试了几次将其添加到 jframe 但没有任何进展 它甚至没有显示 public class Form3 JFrame jframe new JF
  • Logback:SizeAndTimeBasedRollingPolicy 不遵守totalSizeCap

    我正在尝试以一种方式管理我的日志记录 一旦达到总累积大小限制或达到最大历史记录限制 我最旧的存档日志文件就会被删除 当使用SizeAndTimeBasedRollingPolicy在 Logback 1 1 7 中 滚动文件追加器将继续创建
  • 如何在java Spring Boot中实现通用服务类?

    我有许多具有重复代码的服务 我想知道如何实现通用服务 以便我的所有服务都可以扩展它 服务接口示例 重复代码 Service public interface IUserService List
  • 为什么Iterator接口没有add方法

    In IteratorSun 添加了remove 方法来删 除集合中最后访问的元素 为什么没有add方法来向集合中添加新元素 它可能对集合或迭代器产生什么样的副作用 好的 我们开始吧 设计常见问题解答中明确给出了答案 为什么不提供 Iter
  • Java中的断点和逐步调试?

    抱歉我的问题名称很奇怪 我不知道如何寻找这个 因为我不知道这些东西是如何称呼的 Visual Studio 中至少有一个功能 您可以单击代码左侧并设置一个大红点的起点 然后运行程序 您可以通过按 f8 或 f5 实际上是不同的 f 来跟踪步
  • 是否可以从 servlet 内部以编程方式设置请求上下文路径?

    这是一个特殊情况 我陷入了处理 企业 网络应用程序的困境 企业应用程序正在调用request getContext 并将其与另一个字符串进行比较 我发现我可以使用 getServletContext getContextPath 获取 se
  • 如何通过注解用try-catch包装方法?

    如果应该在方法调用中忽略异常 则可以编写以下内容 public void addEntryIfPresent String key Dto dto try Map
  • 在 Java 中通过 XSLT 分解 XML

    我需要转换具有嵌套 分层 表单结构的大型 XML 文件
  • Spring Data JPA:查询如何返回非实体对象或对象列表?

    我在我的项目中使用 Spring Data JPA 我正在演奏数百万张唱片 我有一个要求 我必须获取各种表的数据并构建一个对象 然后将其绘制在 UI 上 现在如何实现我的 Spring 数据存储库 我读到它可以通过命名本机查询来实现 如果指
  • 避免 Java 中的重复导入:继承导入?

    有没有办法 继承 导入 Example 常见枚举 public enum Constant ONE TWO THREE 使用此枚举的基类 public class Base protected void register Constant
  • 无需登录即可直接从 Alfresco 访问文件/内容

    我的场景是这样的 我有一个使用 ALFRESCO CMS 来显示文件或图像的 Web 应用程序 我正在做的是在 Java servlet 中使用用户名和密码登录 alfresco 并且我可以获得该登录的票证 但我无法使用该票证直接从浏览器访
  • 使用 Java https 上传到 Imgur v3 错误

    我目前正在尝试使用他们当前的 API v3 上传到 imgur 但是我不断收到错误 错误 javax net ssl SSLException 证书中的主机名不匹配 api imgur com imgur com OR imgur com
  • Java 的 PriorityQueue 与最小堆有何不同?

    他们为什么命名PriorityQueue如果你不能插入优先级 它看起来与堆非常相似 有什么区别吗 如果没有区别那为什么叫它PriorityQueue而不是堆 默认的PriorityQueue是用Min Heap实现的 即栈顶元素是堆中最小的

随机推荐

  • 【统计模型】生存分析基本知识介绍

    目录 一 生存分析介绍 1 生存分析用途 2 传统方法在分析随访资料时的困难 1 生存时间和生存结局都是我们关心的因素 2 存在大量失访 3 显然 将失访数据无论是算作死亡还是存活都不合理 3 生存分析的优劣势 1 优势 2 劣势 4 生存
  • 机器学习经典算法,原理及代码实现

    机器学习知识体系 岭回归和LASSO回归 朴素贝叶斯 支持向量机 Logistic回归 K 近邻算法 线性回归 决策树 EM最大期望算法 Apriori算法 自适应增强 Adaboost 算法 PageRank算法
  • java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to java.sql.Connection异常问题解决

    Connection proxy Connection Proxy newProxyInstance Connection class getClassLoader Connection class getInterfaces new In
  • 数据结构——线性结构(7)——链队列的实现

    链队列的实现 头文件 这部分文件实现我们之前所使用的queue类 它主要的原理为 后进后出 LILO ifndef Queue h define Queue h 类型 Queue
  • 使用vue-video-player,播放rtmp直播流

    可直接在新的页面复制使用 测试可用
  • 对cpu与load的理解及线上问题处理思路解读

    前言 2019双11还有不到2个月就要到来了 大家也都知道服务器在大促期间由于流量的增加势必导致机器的cpu与load变高 因此趁着这个时机正好再好好学习 巩固一下cpu和load的概念 为双11做准备的同时也是增加自己的技能储备 不过cp
  • 华为OD机试真题- 宜居星球改造计划-2023年OD统一考试(B卷)

    题目描述 2XXX年 人类通过对火星的大气进行宜居改造分析 使得火星已在理论上具备人类宜居的条件 由于技术原因 无法一次性将火星大气全部改造 只能通过局部处理形式 假设将火星待改造的区域为row column的网格 每个网格有3个值 宜居区
  • Unity Shader入门精要第七章 基础纹理渐变纹理

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一 渐变纹理是什么 参考 前言 尽管在一开始 我们在渲染中使用纹理是为了定义一个物体的颜色 但后来人们发现 纹理 其实可以用于存储任何表面属性 一种常见的用法就是使用渐变纹理来
  • 静态链表的基础操作(详解)

    目录 一 闵版 1 完整代码 2 运行结果 二 钦版 1 结构体的创建 2 静态链表的初始化 3 尾插法 4 按值插入 5 删除元素 6 打印静态链表 7 摧毁链表 8 完整代码 9 运行结果展示 一 闵版 1 完整代码 include
  • Flutter视频播放、Flutter VideoPlayer 视频播详解

    1 添加依赖 视频播放 video player 1 0 1 2 播放视频前的准备 2 1 网络访问权限 在 ios 目录下的 info plist 清单文件中配置 iOS设置的http网络访问权限
  • Netty搭建WebSocket服务端

    Netty服务端 1 引入依赖
  • mysql两个时间相减

    pre class sql SELECT TIMESTAMPDIFF MINUTE NOW flowExpireDate AS minsRemaining FROM FlowDealOrders WHERE SN 1721502100011
  • 纳税计算——案例2_7

    纳税计算 案例2 7 题目 在我国 个人所得税是基于纳税人的情况和应征收人计算的 纳税人情况共分为三种 单身纳税人 已婚纳税人和家庭纳税人 另外 对于不同情况的纳税人 其税率是分档计算的 我国2008年的个人所得税税率如下表所示 税率 单身
  • 对于前端实习小白分享几种常用的前端请求数据的方式(超实用)

    第一种 XMLHttpRequest ajax是一种技术方案 但并不是一种新技术 它依赖的是现有的CSS HTML Javascript 而其中最核心的依赖是浏览器提供的XMLHttpRequest对象 是这个对象使得浏览器可以发出HTTP
  • 前端到接口层的反序列化流程

    前置知识 参考我的另一篇博客 209条消息 Servlet和SpringMVC fengwuJ的博客 CSDN博客 描述了Servlet与SpringMVC的关系 大致可以知道从前端请求 到后端接口的中间过程 反序列化流程 前篇文章中 走到
  • Struts2拦截器的使用 (详解)

    如何使用struts2拦截器 或者自定义拦截器 特别注意 在使用拦截器的时候 在Action里面必须最后一定要引用struts2自带的拦截器缺省堆栈defaultStack 如下 这里我是引用了struts2自带的checkbox拦截器
  • Docker windows安装及遇到的坑爹问题

    本文主要是针对Windows下Docker的安装问题 什么是Docker Docker官网解释 https www docker com what docker Docker是一个开源的引擎 可以轻松的为任何应用创建一个轻量级的 可移植的
  • IDEA快捷键

    IDEA快捷键 JUnit 测试 快速生成 ctrl shift T try catch ctrl alt T 复制并创建一行 ctrl D 删除当前行 ctrl Y 快速格式化代码 reformat code ctrl alt L 和QQ
  • Openwrt开发笔记(2)—— 创建自己的模块HelloWord

    创建自己的包 开发的第一步来自于模仿 我们模仿openwrt内部的软件包来创建自己的软件包helloword 这里为了更好的展示 我们使用uhttpd openwrt默认的web服务器 来运行helloword 这里就需要将hellowor
  • 【SpringBoot新手篇】SpringBoot优雅文件上传方式

    SpringBoot文件上传 Pom yml controller UploadController FileController 文件上传 多文件上传 文件下载 页面 BUG 封装版 工具类 StringUtil MimeTypeUtil