SpringBoot 框架学习笔记(七):Thymeleaf、拦截器 和 文件上传实现(解决了文件重名 和 按日期分目录存放问题)

news2024/11/24 11:01:26

1 Thymeleaf

1.1 基本介绍

(1)官方文档:Tutorial: Using Thymeleaf

(2)Thymeleaf 是什么

  • Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,可完全替代 JSP
  • Thymeleaf 是一个 java 类库,它是一个 xml/xhtml/html5 的模板引擎,可以作为mvc的web应用的view层

(3)Thymeleaf的优点

  • 实现 JSTL、OGNL 表达式效果,语法类似,上手快
  • Thymeleaf 模板页面无需服务器渲染,也可以被浏览器运行,页面简洁
  • SpringBoot支持 Thymeleaf、Velocity、FreeMarker

(4)Thymeleaf的缺点 

  • 并不是一个高性能的引擎,适用于单体应用
  • 如果要做一个高并发的应用,选择前后端分离更好,但是作为SpringBoot推荐的模板引擎,还是需要了解一下

1.2 Thymeleaf机制说明

(1)Thymeleaf 是服务器渲染技术,页面数据是在服务器端进行渲染的

(2)比如:manage.html 中一段 Thymeleaf 代码,是在客户请求该页面时,由 Thymeleaf 模板引擎完成处理的(在服务器端完成),并将结果返回。因此使用了Thymeleaf,并不是前后端分离

<tr bgcolor="pink" th:each="user:${users}">
    <td th:text="${user.id}">a</td>
    <td th:text="${user.name}">b</td>
    <td th:text="${user.age}">c</td>
    <td th:text="${user.eamil}">d</td>
    <td th:text="${user.password}">e</td>
</tr>

1.3 Thymeleaf语法

3.3.1 表达式

3.3.1.1 表达式一览
表达式名字语法用途
变量取值${...}获取请求域、session域、对象等值
选择变量*{...}获取上下文对象值
消息#{...}获取国际化等值
链接@{...}生成链接
片段表达式~{...}jsp:include 作用,引入公共页面片段
1.3.1.2 字面量

文本值:'hello'

数字:10,7,36.8

布尔值:true,false

空值:null

变量:name,age

注意:变量不能有空格

1.3.1.3 文本操作

字符串拼接:+

变量替换:|age= ${age}|

1.3.2 运算符

(1)数学运算

运算符:+,-,*,/,%

(2)布尔运算

运算符:and,or

一元运算符:!,not

(3)比较运算

比较:>,<,>=,<=( gt,lt,ge,le)

等式:==,!=(eq,ne)

(4)条件运算

If-then:(if) ? (then)

If-then-else:(if)?(then):(else)

Default:(value)?:(defaultvalue)

1.3.3 th属性

html有的属性,Thymeleaf基本都有,而常用的属性大概有七八个。其中th属性执行的优先级从1到8,数字越低,优先级越高

  • th:text:设置当前元素的文本内容,相同功能的还有th:utext,两者的区别在于前者不会转义html标签,后者会。优先级不高,order=7
  • th:value:设置当前元素的value值。类似修改指定属性的还有th:src,th:href。优先级不高,order=6
  • th:each:遍历循环元素,和th:text或th:value一起使用。注意该属性修饰的标签位置,详细往后看。优先级很高,order=2
<tr th:each="prod : ${prods}">
    # ${prod.name}的值会替换Onions
    <td th:text="${prod.name}">Onions</td>
    <td th:text="${prod.price}">2.41</td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
<tr th:each="prod,iterStar : ${prods}" th:class="${iterStar.odd}?'odd'">
    <td th:text="${prod.name}">Onions</td>
    <td th:text="${prod.price}">2.41</td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
  • th:if:条件判断,类似的还有th:unless,th:switch,th:case。优先级较高,order=3
<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:if="${not #lists.isEmpty(prod.comments)}">view</a>

<div th:switch="${user.role}">
    <p th:case="'admin'">User is an administrator</p>
    <p th:case="#{roles.manager}">User is a manage</p>
    <p th:case="*">User is some other thing</p>
</div>
  • th:insert:代码块引入,类似的还有th:replace,th:include,三者的区别较大,若使用不恰当会破坏html结构,常用于公共代码块提取的场景。优先级最高,order=1
  • th:fragment:定义代码块,方便被th:insert引用。优先级最低,order=8
  • th:object:声明变量,一般和*{}一起配合使用,达到偷懒的效果。优先级一般,order=4
  • th:attr:修改任意属性,实际开发中用的较少,因为有丰富的其他th属性帮忙,类似的还有th:attrappend,th:attrprepend。优先级一般,order=5

1.3.4 使用Thymeleaf的th属性需要注意的点

  • 若要使用Thymeleaf语法,首先要声明名称变量:xmlns:th="http://www.thymeleaf.org"
  • 设置文本内容 th:text,设置 input 的值 th:value,循环输出 th:each,条件判断 th:if,插入代码块 th:insert,定义代码块 th:fragment,声明变量 th:object
  • th:each 的用法需要格外注意:如果你要循环一个div中的标签,则th:each属性必须放在p标签上。若将th:each属性放在div上,则循环的是整个div
  • 变量表达式中提供了很多内置方法,该内置方法是用#开头,请不要与 #{} 消息表达式弄混

1.4 Thymeleaf综合案例

需求说明:使用SpringBoot + Thymeleaf 完成简单的用户登录-列表功能

代码实现:

(1)创建maven项目,项目名使用 springboot-usersys

(2)要支持Thymeleaf,需要引入starter-Thymeleaf,在 pom.xml 配置(其他依赖是springboot项目开发需要)

<!-- 导入 springboot 父工程 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.3</version>
</parent>

<dependencies>

    <!--引入Thymeleaf-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <dependency>
        <!-- 导入 web 项目场景启动器,会自动导入和 web 开发相关依赖 -->
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--引入lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

<!--        引入配置处理器-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
    </dependency>
</dependencies>

Thymeleaf 默认在类路径下的templates目录下去找对应的html文件,查看 ThymeleafProperties 源码即可知

(3)在resources目录下(maven项目的类路径就是resources)新建 templates 目录,在  templates 目录下创建 login.html 和 manage.html(这里使用了 Thymeleaf)

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>login</title>

  <style>
    * {
      margin: 0;
      padding: 0;
    }
    html {
      height: 100%;
    }
    body {
      height: 100%;
    }
    .container {
      height: 100%;
      background-image: linear-gradient(to right, #999999, #330867);
    }
    .login-wrapper {
      background-color: bisque;
      width: 358px;
      height: 588px;
      border-radius: 15px;
      padding: 0 50px;
      position: relative;
      left: 50%;
      top: 50%;
      transform: translate(-50%,-50%);
    }
    .header {
      font-size: 38px;
      font-weight: bold;
      text-align: center;
      line-height: 200px;
    }
    .input-item {
      display: block;
      width: 100%;
      margin-bottom: 20px;
      border: 0;
      padding: 10px;
      border-bottom: 1px solid rgb(128,125,125);
      font-size: 15px;
      outline: none;
    }
    .input-item::placeholder {
      text-transform: uppercase;
    }
    .btn {
      text-align: center;
      padding: 10px;
      width: 100%;
      margin-top: 40px;
      background-image: linear-gradient(to right,#a6c1ee, #fbc2eb);
      color: #fff;
    }
    .msg {
      text-align: center;
      line-height: 88px;
    }
    a {
      text-decoration-line: none;
      color: #abc1ee;
    }
  </style>
</head>
<body>
<div class="container">
  <div class="login-wrapper">
    <div class="header">Login</div>
    <form class="form-wrapper" action="#" th:action="@{/login}" method="post">
      <label style="color: red" th:text="${msg}"></label>
      <input type="text" name="name" placeholder="username" class="input-item">
      <input type="password" name="password" placeholder="password" class="input-item" />
      <button type="submit" class="btn" >Login</button>
      <button type="reset" class="btn">Login</button>
    </form>
    <div class="msg">
      Don't have account?
      <a href="#">Sign up</a>
    </div>
  </div>
</div>
</body>
</html>


<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>管理后台</title>
</head>
<body bgcolor="#CED3FE">
<a href="#">返回管理页面</a>
<a href="#" th:href="@{/}">安全退出</a> 欢迎您:[[${session.adminLogin.name}]]
<hr/>
<div style="text-align: center">
    <h1>管理雇员</h1>
    <table border="1px" cellspacing="0" bordercolor="green" style="">
        <tr bgcolor="#ffc0cb">
            <td>id</td>
            <td>name</td>
            <td>pwd</td>
            <td>email</td>
            <td>job</td>
        </tr>
        <tr bgcolor="#ffc0cb" th:each="user:${users}">
            <td th:text="${user.id}">a</td>
            <td th:text="${user.name}">b</td>
            <td th:text="${user.password}">c</td>
            <td th:text="${user.email}">d</td>
            <td th:text="${user.age}">e</td>
        </tr>
    </table>
</div>
</body>
</html>

(4)新建软件包bean,在该包下创建两个实体类 User.java 和 Admin.java

package org.wwj.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
    private Integer id;
    private String name;
    private String password;
    private Integer age;
    private String email;
}
package org.wwj.bean;

import lombok.Data;

@Data
public class Admin {
    private String name;
    private String password;
}

(5)新建软件包 controller,在该包下创建 IndexController.java 和 AdminController,java

IndexController.java 用于请求转发到登录页面,实现功能:浏览器输入 localhost:8080/ 和localhost:8080/login 均可以访问到登录页面

package org.wwj.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {

    // 编写方法,转发到登录页
    @GetMapping(value = {"/", "/login"})
    public String login() {
        // 因为引入了 Thymeleaf,Thymeleaf里面包含了视图解析
        // 这里就会直接使用视图解析器解析到templates下的模板文件login.html
        return "login";
    }
}

AdminController,java 用于对登录的校验,以及登录成功页面的跳转。实现功能:用户没有登录直接访问登录成功页面 以及 登录账号/密码 返回错误信息,并跳转到登录页面;如果校验通过就转发到 manage.html 页面显示用户信息

package org.wwj.controller;

import jakarta.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.wwj.bean.Admin;
import org.wwj.bean.User;

import java.util.ArrayList;

@Controller
public class AdminController {

    //响应用户的登录请求
    @PostMapping("/login")
    public String login(Admin admin, HttpSession session, Model model) {

        // 验证用户是否合法
        if (StringUtils.hasText(admin.getName()) && "666".equals(admin.getPassword())){
            session.setAttribute("adminLogin", admin);
            // 合法,重定向到 manage.html,重定向的请求方式为 get
            // 不能使用请求转发,防止刷新页面后表单重复提交
            // return "redirect: /manage.html"; 表示要去找映射路径为manage.html的controller方法
            return "redirect:/manage.html";
        }else {
            // 不合法,重新登录
            model.addAttribute("msg","账号/密码错误");
            return "login";
        }
    }

    // 处理用户的请求到 manage.html
    @GetMapping("/manage.html")
    public String mainPage(Model model, HttpSession session) {
        if (session.getAttribute("adminLogin") != null) {// 这里可以使用集合模拟用户数据,放入 request 域中
            ArrayList<User> users = new ArrayList<>();
            users.add(new User(1, "关羽~", "666666", 20, "gr@sohu.com"));
            users.add(new User(2, "张飞", "666666", 30, "zi@sohu.com"));
            users.add(new User(3, "赵云", "666666", 22, "zy@sohu.com"));
            users.add(new User(4, "马超", "666666", 28, "me@sohu.com"));
            users.add(new User(5, "黄忠", "666666", 50, "hz@sohu.com"));

            // 将数据放入到request域中
            model.addAttribute("users", users);

            // 因为引入了 Thymeleaf,Thymeleaf里面包含了视图解析
            // 这里的manage才会使用视图解析器转发到templates目录下相应的页面
            return "manage";
        }else {
            // 返回登录页,并给出提示
            model.addAttribute("msg", "你没有登录/请登录");
            return "login";
        }
    }
}

 (6)编写并启动主程序

package org.wwj;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;


@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ApplicationContext ioc = SpringApplication.run(Application.class, args);
    }
}

(7)浏览器输入 localhost:8080/ 进行测试

2 拦截器

2.1 基本介绍

(1)在Spring Boot项目中,拦截器是开发中常用手段,用来做登录验证、性能验证、日志记录等。

(2)使用拦截器基本步骤

  • 编写一个拦截器实现 HandlerInterceptor接口
  • 将拦截器注册到配置类中(实现WebMvcConfigurer的addInterceptors)
  • 指定拦截规则

(3) Spring Boot实现拦截器的方式和springmvc差不多,区别是配置方式不同

2.2 拦截器应用实例

需求说明:使用拦截器防止用户非法访问,例如用户直接在浏览器输入 localhost:8080/manage.html,如果用户没有登录,则返回登录页面,并给出提示信息

代码实现:

在上面Thymeleaf案例的基础上进行拦截

(1)创建软件包 interceptor 用来存放拦截器,在该软件包下创建 LoginInterceptor.java 作为拦截器,该拦截器会对拦截的请求进行登录验证,只有用户是登录状态时才放行,非登录状态转发到登录页面

package org.wwj.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 为了看到访问的URL
        String requestURI = request.getRequestURI();
        log.info("preHandle拦截到的请求的URL={}",requestURI);
        // 进行登录验证
        HttpSession session = request.getSession();
        if (session.getAttribute("adminLogin") != null) return true;
        else {
            // 拦截,重新返回到登录页面
            request.setAttribute("msg", "你没有登录");
            request.getRequestDispatcher("/login").forward(request, response);
            return false;
        }
    }
}

(2)在配置类中注册拦截器,新建软件包 config,在该软件包下创建 WebConfig.java 作为配置类。这里注册拦截器的方式有两种

第一种

package org.wwj.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.wwj.interceptor.LoginInterceptor;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") //拦截所有请求
                .excludePathPatterns("/", "/login");// 放行登录请求
    }
}

第二种

package org.wwj.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.wwj.interceptor.LoginInterceptor;

@Configuration
public class WebConfig{

    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        return new WebMvcConfigurer() {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(new LoginInterceptor())
                        .addPathPatterns("/**")
                        .excludePathPatterns("/", "/login");
            }
        };
    }
}

2.3 注意事项和细节

(1)URI 和 URL 的区别

URI = Universal Resource Identifier

URL = Universal Resource Locator

Identifier:标识符,Locator:定位器。从字面上来看,URI可以唯一标识一个资源,URL可以提供找到该资源的路径

举例:

URI=/manage.html

URL=http://localhost:8080/manage.html

3 文件上传应用实例

需求说明:演示Spring-Boot 通过表单注册用户,并支持上传图片(简化了 Spring MVC文件上传的方式)

代码实现:

(1)创建 templates/upload.html,要求头像只能选择一个,而宠物可以上传多个图片

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div style="text-align: center">
  <h1>注册用户~</h1>
  <form action="#" th:action="@{/upload}" method="post" enctype="multipart/form-data">
    用户名:<input type="text" style="width: 150px" name="name"><br/><br/>
    电 邮:<input type="text" style="width: 150px" name="email"><br/><br/>
    年 龄:<input type="text" style="width: 150px" name="age"><br/><br/>
    职 位:<input type="text" style="width: 150px" name="job"><br/><br/>
    头 像:<input type="file" style="width: 150px" name="header"><br/><br/>
    <!--在该标签尾部加个 multiple 即可选择多张图片-->
    宠 物:<input type="file" style="width: 150px" name="photos" multiple><br/><br/>
    <input type="submit" value="注册"/>
    <input type="reset" value="重新填写"/>
  </form>
</div>
<hr/>
</body>
</html>

(2)创建 UploadController.java,对注册的请求进行处理

package org.wwj.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;

@Controller
@Slf4j
@SuppressWarnings("all")
public class UploadController {
    // 处理转发到用户注册-可以完成文件上传页面
    @GetMapping("/upload.html")
    public String uploadPage(){
        // Thymeleaf 进行视图解析,转发到templates/upload.html
        return "upload";
    }

    // 处理用户注册请求,包含处理文件上传
    @PostMapping("/upload")
    @ResponseBody
    public String upload(String name,
                         String email,
                         Integer age,
                         String job,
                         MultipartFile header,
                         MultipartFile[] photos) throws IOException {
        // 输出获取到的信息
        log.info("上传的信息 name={} email={} age={} job={} header={} photos={}",
                name,email,age,job,header.getSize(),photos.length);

        // 成功获取到信息,将文件保存到当前项目类路径下的static/images/upload目录下
        // 得到类路径
        String path = ResourceUtils.getURL("classpath:").getPath();
        log.info("path = {}",path);
        // 拼接目录
//        String fullPath = path+"static/images/upload/";
        File file = new File(path + "static/images/upload/");
        if (!file.exists()){//如果目录不存在,就创建
            file.mkdirs();
        }
        // 处理头像
        if (!header.isEmpty()){

            String headerName = header.getOriginalFilename();
            header.transferTo(new File(file, headerName));
        }

        // 处理宠物头像
        for (MultipartFile multipartFile : photos) {
            String fileName = multipartFile.getOriginalFilename();
            multipartFile.transferTo(new File(file,fileName));
        }

        return "注册成功/文件上传成功";
    }
}

(3)在注册拦截器的配置类中放行注册请求

package org.wwj.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.wwj.interceptor.LoginInterceptor;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") //拦截所有请求
                .excludePathPatterns("/", "/login","/upload.html","/upload");// 放行登录注册请求
    }
}

(4)浏览器输入 localhost:8080/upload.html 进行测试

 

 

 注意事项:

(1)默认单个文件最大1MB,一次上传多文件最大10MB可以通过yaml配置文件修改该默认参数,在resouces目录下创建application.yml

spring:
  servlet:
    multipart:
      max-file-size: 2MB
      max-request-size: 20MB

(2)如果文件名相同,会出现覆盖问题,解决办法如下

对上传的文件名进行处理,前面加一个前缀,保证前缀是是唯一即可

// 处理头像
if (!header.isEmpty()){

    String headerName = UUID.randomUUID().toString()+"_"+System.currentTimeMillis() + "_"
            + header.getOriginalFilename();

    header.transferTo(new File(file, headerName));
}

// 处理宠物头像
for (MultipartFile multipartFile : photos) {
    String fileName = UUID.randomUUID().toString()+"_"+System.currentTimeMillis() + "_"
            + multipartFile.getOriginalFilename();
    multipartFile.transferTo(new File(file,fileName));
}

效果如下

(3)解决文件分目录存放问题,如果将文件都上传到一个目录下,当上传文件很多时,会造成访问文件速度变慢,因此可以将文件上传到不同目录,比如一天上传的文件,统一放到一个文件夹 年/月/日,比如2022/11/11目录 

编写一个工具类用来动态生成当前日期的目录

package org.wwj.utils;

import java.text.SimpleDateFormat;
import java.util.Date;

public class WebUtils {

    // 定义文件上传的路径
    public static String UPLOAD_FILE_DIRECTORY = "static/images/upload/";

    // 编写方法,生成一个当前日期的目录 年/月/日
    public static String getUploadFileDirectory(){
        return UPLOAD_FILE_DIRECTORY +
                new SimpleDateFormat("yyyy/MM/dd").format(new Date());
    }
}

修改 UploadController.java,将固定文件上传目录修改为由工具类方法动态生成

测试效果如下 

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

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

相关文章

AnyGo(虚拟定位软件) for MacOS苹果电脑安装下载 支持最高系统 兼容M芯片

AnyGo for Mac是一款专为Mac用户设计的虚拟定位软件。它允许用户在Mac设备上模拟GPS位置&#xff0c;从而改变设备在各种基于位置的应用和服务中的显示位置。AnyGo提供了简单直观的操作界面&#xff0c;用户可以轻松地在地图上选择任意地点作为模拟位置&#xff0c;或者通过输入…

【平衡二叉树】数据结构—平衡二叉树

平衡二叉树&#xff08;Balanced Binary Tree&#xff09;是一种特殊的二叉树&#xff0c;它的左右子树的高度差不超过1&#xff0c;这样可以保证树的高度相对较低&#xff0c;从而使得查找、插入和删除操作的时间复杂度保持在 。 平衡二叉树的基本概念 1. 二叉树&#xff1a…

LeetCode 热题 HOT 100 (020/100)【宇宙最简单版】[创作中]

【链表】No. 0142 环形链表 II【中等】&#x1f449;力扣对应题目指路 希望对你有帮助呀&#xff01;&#xff01;&#x1f49c;&#x1f49c; 如有更好理解的思路&#xff0c;欢迎大家留言补充 ~ 一起加油叭 &#x1f4a6; 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&#…

C++ 简单学习

C简单编译 auto关键字 auto 关键字用于自动类型推导。它允许编译器自动推断变量的类型&#xff0c;使得代码更加简洁和易于编写&#xff0c;尤其是在处理复杂类型或模板编程时。使用 auto 可以避免编写冗长的类型声明&#xff0c;同时减少由于类型不匹配导致的编译错误 auto x…

学习vue3 三,组件基础,父子组件传值

组件基础 每一个.vue 文件都可以充当组件来使用 每一个组件都可以复用 父组件引入之后可以直接当标签使用 案例&#xff1a; App.vue <script setup lang"ts"> import BaseRefAndReactive from "./components/BaseRefAndReactive.vue";</sc…

Docker部署Node+Koa+TS+Mongo项目

Docker 简介 简而言之&#xff0c;Docker 容器轻量级、启动快、可移植&#xff0c;适合微服务架构。主要组件包括 Docker Engine、Docker 镜像、Docker 容器和 Docker Hub&#xff0c;它通过容器打包应用程序及其依赖项&#xff0c;使得应用在任何环境中都能一致运行。 这里不…

Selenium中send_keys上传图片方法以及可能失败的原因

Python Selenium是一个用于自动化浏览器操作的工具&#xff0c;可以用于模拟用户在浏览器中的各种操作。在使用Python Selenium进行自动化测试时&#xff0c;有时需要上传图片。下面是在这种情况下如何上传图片的步骤&#xff1a; 今天是主要说的是input标签&#xff0c;这种可…

基于R语言绘制GGE双标图3

参考资料&#xff1a; https://cran.r-project.org/web/packages/GGEBiplots/GGEBiplots.pdf GGE叠图法一分析品种环境互作模式的理想方法【作物学报】 GGE 双标图如何看&#xff1f;-CSDN博客 1、品种间两两比较 GGE 双标图可用于直接比较两个品种在各个试验点的表现&…

白银市场暴跌的技术分析与投资策略

一、白银市场暴跌与技术分析 周一&#xff08;8月5日&#xff09;&#xff0c;现货白银暴跌逾4.5%&#xff0c;并跌破关键的100日移动均线。FXStreet分析师Christian Borjon Valencia对银价技术走势进行了分析&#xff0c;指出银价前景转为看跌&#xff0c;技术面显示白银将进一…

探索Python并发的秘境:Greenlet库的奇幻之旅

文章目录 探索Python并发的秘境&#xff1a;Greenlet库的奇幻之旅背景&#xff1a;为何选择Greenlet&#xff1f;绿野仙踪&#xff1a;Greenlet是什么&#xff1f;安装&#xff1a;如何将Greenlet纳入囊中&#xff1f;功能探索&#xff1a;Greenlet的五大法宝场景应用&#xff…

【系统分析师】-综合知识-软件工程与项目管理

1、按照成本性态分类&#xff0c;可以分为固定成本、变动成本和混合成本。 &#xff08;1&#xff09;固定成本。管理人员的工资、办公费、固定资产折旧费、员工培训费、广告费、员工培训费、技术开发经费、办公场地及机器设备的折旧费、房屋及设备租金、管理人员的工资等。 …

提示工程:CO-STAR框架

在人工智能领域&#xff0c;尤其是大型语言模型&#xff08;LLM&#xff09;的应用中&#xff0c;提示工程已成为一项至关重要的技能。它不仅需要对技术有深刻的理解&#xff0c;还需要创造力和战略思维的结合。本文将探讨提示工程的重要性&#xff0c;详细介绍CO-STAR框架的使…

0209-开发状态切换(场景切换)功能

一、设置场景状态 1、已有方法 2、实现步骤 引用API&#xff1a;using UnityEngine.SceneManagement 写设置场景状态的方法 场景名字切换&#xff0c;需要获取mSceneName&#xff0c;他是私有的&#xff0c;给一个getset 3、问题 &#xff08;1&#xff09;同步加载 加载场…

【Web开发手礼】探索Web开发的秘密(十六)-Vue2(2)前端工程化、Element组件表格、分页

主要介绍了前端工程化Vue的开发流程、Element组件介绍以及常见的Element组件表格、分页&#xff01;&#xff01;&#xff01; 目录 前言 前端工程化 Vue项目-创建 Vue项目-目录结构 Vue项目-启动 Vue项目-配置端口 Vue项目开发流程 Element组件 快速入门 常见组件 表格…

2024杭电多校(4) 1008. 树形DNA【01Trie、哈希】

题意 给定两颗二叉树 S S S 和 T T T&#xff0c;如果对于 S S S 的某个子树 S ′ S^\prime S′&#xff0c;删除若干个&#xff08;或不删除&#xff09;其子树后&#xff0c;可以和 T T T 相同&#xff08;左子树与左子树匹配&#xff0c;右子树与右子树匹配&#xff0…

C++入门基础知识

在之前我们学习了C语言和初阶数据结构的相关知识&#xff0c;现在已经有了一定的代码能力和对数据结构也有了基础的认识&#xff0c;接下来我们将进入到新的专题当中&#xff0c;这个专题就是C。在C中我们需要花费更大的精力和更长的时间去学习这门建立在C语言基础之上的计算机…

新一代AI软件基础设施 | ZStack AIOS平台“智塔”发布

新一代 IT 基础设施&#xff0c;将从通用算力云平台转型为AI算力AIOS平台。 AI正在重构世界。正如世界是立体的&#xff0c;AI重构也正从多维度开启&#xff1a;基础设施重构&#xff0c;业务应用重构&#xff0c;交互模式重构&#xff0c;数据价值重构&#xff0c;生态系统重…

移动IP:让你的设备随时随地保持连接

随着无线网络技术的迅猛发展&#xff0c;在移动中进行数据通信已成为可能。成千上万的人正在使用移动设备畅享互联网&#xff0c;无论是在火车上、汽车内&#xff0c;还是在其他移动场景中。本文将带你了解移动IP&#xff08;Mobile IP&#xff09;的工作原理及其对网络应用的影…

LLM在线理解;神将网络理解;transform架构

目录 LLM在线理解 神将网络理解 transform架构 模型的子结构: 三个计算 计算1 计算2 计算3 LLM在线理解 LLM Visualization 神将网络理解 transform架构 模型的子结构: 词向量(Embedding) 前馈神经网络(Feed Forward) 残差连接(Add)和层标准化(Norm) 线性层(Linear…

Python版本和cuda版本不匹配解决办法

一、检查版本是否匹配 使用Python进入控制台&#xff0c;然后执行&#xff1a; >>>print(torch.cuda.is_available())如果输出为 False&#xff0c;则说明不匹配 退出Python环境&#xff0c;再检查系统版本&#xff1a; exit()nvcc -V 二、安装 去官网 PyTorch …