[spring] Spring MVC Thymeleaf(上)

news2024/12/24 2:29:01

[spring] Spring MVC & Thymeleaf(上)

本章内容主要过一下简单的 Spring MVC 的案例

简单来说,spring mvc 就是比较传统的网页开发流程,目前 boot 是可以比较轻松的配置 thymeleaf——毕竟 spring boot 内置对 thymeleaf 的支持

thymeleaf 是一个模板引擎,目前看起来是简单很多——我还依稀记得当年使用 JSP 写 spring mvc 的日子,那写的是真的很痛苦……

简单的 demo

这里就放一个超简单的 demo,能让页面跑起来就行

spring boot initializer

这里主要用的就是这 4 个包,下里用的案例会多一个依赖

在这里插入图片描述

实现简单 demo

因为是 spring mvc,所以肯定是需要有 Mocel-View-Controller 三个实现的。不过这个 demo 里面因为不涉及到数据的交互,所以没有 model

具体实现如下:

  • controller

    package com.example.thymeleafdemo.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @Controller
    public class DemoController {
        // create a mapping for "/hello"
        @GetMapping("/hello")
        public String sayHello(Model model) {
            model.addAttribute("date", java.time.LocalDateTime.now());
    
            return "helloworld";
        }
    }
    
    
    • @Controller 的实现都比较熟悉了,这代表这是一个 Controller 的注解。因为这不是一个前后端分离的 rest api 实现,所以这里不需要使用 @RestController,也不需要做 request mapping

    • @GetMapping 这个就比较熟悉了,当用户访问 http://localhost:8080/hello 是就会调用当前方法

    • sayHello 是方法名,它返回的是一个字符串,而这个字符串代表着 view 的名字。以 thymeleaf 为例,spring mvc 会找到对应的模板渲染 view 层,这个也是下面会提到的

      实现的模板引擎的文件名为这里返回的字符串,即 helloworld.html

    • Model model 是 spring 在察觉到当前方法是 controller 的方法时,自动进行绑定的参数。view 层可以直接调用 model 里被添加的属性——model.addAttribute("date", java.time.LocalDateTime.now());,也就是 date 这个属性

  • view

    view 层具体在的位置位于 resources/templates 下:

    在这里插入图片描述

    实现为:

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
        <meta charset="UTF-8" />
        <link rel="stylesheet" th:href="@{/css/demo.css}" />
        <title>Title</title>
      </head>
      <body>
        <p th:text="'Time on the server is ' + ${date}" class="funny"></p>
    
        <script src="http://localhost:35729/livereload.js"></script>
      </body>
    </html>
    

    这里的的视线相对比较简单,基础的 HTML 就不谈了

    • xmlns:th="http://www.thymeleaf.org 是 thymeleaf 的命名空间,也就是说下面都可以通过 th:<attr> 使用 thymeleaf 特有的属性

    • <link rel="stylesheet" th:href="@{/css/demo.css}" /> 使用的就是 thymeleaf 的语法,这里会自动解析路径去寻找对应的 css 文件,也就是在 static/css/demo.css 这个文件

    • <p th:text="'Time on the server is ' + ${date}" class="funny"></p> 这里用的是一个新的 thymeleaf 的语法,th:text 可以将后面的表达式,也就是 'Time on the server is ' + ${date} 写入到 element 中

      ${date} 就是在 controller 中传到 model 的属性,可以通过 ${} 的方式获得

    • <script src="http://localhost:35729/livereload.js"></script> 是一个热更新的脚本,在开启了 devtool 之后可以实现保存后 HTML 页面自动更新的功能

      换言之不需要刷新页面,也不需要重启服务器……就是稍微有些慢……

效果如下:

在这里插入图片描述

简述 MVC 的工作原理

在这里插入图片描述

这张图可以描述 spring mvc 的流程是什么样的

首先,浏览器会访问 front controller 组件——spring mvc 中一般指的是 DispatcherServlet,它会:

  • 集中处理所有的 HTTP 请求,并通过 URL mapping,将对应的 http 请求委托给对应的 handler/controller 进行处理
  • 解析 view 层
  • 处理 model,并与 model 和 view 层进行交互,实现 MVC 整体的数据交互

一般来说,front controller, controller, model, view 是四个比较高度抽象化的概念,它们的实施可以通过具体的组件去实现,如:

  • DispatcherServlet 是 front controller 的组件
  • @Controller & @RestController 是 controller 的 bean/class
  • @Model 显而易见的是 model 的组件
  • JSP/Thymeleaf 是 view 的组件等
  • spring 配置文件,如 XML,注解,java 配置文件等,也是 spring 的组件

总体来说,这些组件 spring 队伍已经进行实现完毕,并且内部完成了对应的配置,所以开发需要做的事情就是使用这些组件,将具体的业务填写完毕即可,如:

  • model

    声明必要的 entity 并添加对应的属性;通过 front controller 进行 controller 层和 view 层的沟通

  • view

    实现 thymeleaf/jsp 等支持的引擎模板,从 front controller 获取数据,并进行对应的处理以完成 UI 层面的渲染

  • controller

    与 service 层进行沟通,获取并处理对应的数据,并将其处理为 view 层所需的 model 送到 front controller 去

    一般来说,业务逻辑会从 controller 中抽离出来,以保证 SPR 和代码的低耦合性,不过这篇笔记不会涉及到 crud 的操作,因此可以暂时忽略 service 层

表单 demo

下面写一个 MVC 之间互动的 demo,这样可以更好理解上一个部分中比较抽象的概念

业务逻辑如下:

request mapping via /processForm
with data
view
controller

这里省略掉了 front controller 的存在,毕竟这部分是 spring 已经实现好并且封装起来的功能

具体的实现流程如下:

  1. 创建 controller

  2. 展示 view 层,即渲染引擎模板

    这里具体要实现的功能也分为两步:

    1. 创建对应的 controller 方法去显示 html 表单
    2. 创建 HTML 模板去显示页面

    这两步必须要全部实现,才能通过访问对应的 URL 渲染对应的模板引擎

  3. 处理 HTML 表单

    根据上面的流程图所说,view 需要通过 /processForm 去和 controller 进行交互,这个过程中,view 会将用户填写的数据传给 controller

    这一步处理的过程和上面大致是一样的逻辑:

    1. 创建对应的 controller 方法去处理传来的数据,并显示处理完的页面

    2. 创建 HTML 模板去显示页面

controller 初始代码

package com.example.thymeleafdemo.controller;

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

@Controller
public class HelloWorldController {
    // need a controller method to show initial HTML form
    @RequestMapping("/showForm")
    public String showForm() {
        return "helloworld-form";
    }

    // need a controller method to process HTML form
    @RequestMapping("/processForm")
    public String processForm() {
        return "helloworld";
    }
}

这里没有什么特别复杂的地方,和上面简单 demo 提到的一样

模板引擎初始代码

这里要实现的是两个模板引擎,一个是 helloworld-form.html,用来显示表单,让用户填写数据;一个是 helloworld,这是 controller 收集了用户提交的数据后,新定向的页面,这里将会显示用户输入的数据

具体实现如下:

  • helloworld-form

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
        <meta charset="UTF-8" />
        <title>Hello World - Input Form</title>
      </head>
      <body>
        <form th:action="@{/processForm}" method="get">
          <input type="text" name="studentName" placeholder="Student Name" />
          <input type="submit" value="Submit" />
        </form>
    
        <script src="http://localhost:35729/livereload.js"></script>
      </body>
    </html>
    
  • helloworld

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
        <meta charset="UTF-8" />
        <title>Title</title>
      </head>
      <body>
        Hello World of Spring!
        <br />
        <br />
    
        Student name: <span th:text="${param.studentName}"></span>
    
        <script src="http://localhost:35729/livereload.js"></script>
      </body>
    </html>
    

这里简单的过一遍两个模板都做了什么,第一个 helloworld-form 会渲染一个表单,用户可以通过表单输入数据,并且提交数据。这里提交的方式是 get,所以提交的数据会添加到 URL 路径上;同时 action 中的路径是 @{/processForm},这也是 thymeleaf 的语法,表示会 map 到对应的 /processForm,也就是 controller 中的 @RequestMapping("/processForm") 对应的方法

helloworld 会渲染已经处理好的数据,并且通过 URL 获取用户提交的数据并将其渲染到页面上,效果如下:

在这里插入图片描述

使用 model

之前是直接使用 query parameter 通过 URL 去进行数据传递,不过这只能用在 GET 方法上,如果要使用 POST,那么就需要使用 request body 进行和 controller 的沟通

这个情况下,controller 可以通过 HttpServletRequest 或者 @RequestParam("attributeName") 的方式,从模板引擎那里获取对应的资料,具体实现方式如下:

controller 修改:

    // need a controller method to read from data and add data to the model
    @RequestMapping("/processFormV2")
    public String formWithModel(HttpServletRequest request, Model model) {
        // read req param from html form
        String name = request.getParameter("studentName");
        // convert data to all caps
        name = name.toUpperCase();
        // create the message
        String result = "Yo! " + name;
        // add message to the model
        model.addAttribute("message", result);
        return "helloworld";
    }

注意这里是通过 HttpServletRequest 获取对应的数据,HttpServletRequest 通过 dependency injection 动态完成注入的。在使用 GetMapping 的情况下,HttpServletRequest 会从 URL 的 query string 上获取对应数据;在 PostMapping 的情况下,HttpServletRequest 会从 request body 中动态获取,默认的格式为 Content-Type: application/x-www-form-urlencoded

⚠️:我这里用的是 @RequestMapping("/processFormV2"),最好是使用单独的 PostMappingGetMapping 去增强安全性

HTML 部分省略了,主要就是修改一下 form 请求的地址,变更为 processFormV2,随后就是获取信息的方式为 The message: <span th:text="${message}"></span>

完成修改后的结果如下:

在这里插入图片描述

绑定 request params

这是上面提到的,使用注解的方式获取信息:

    // need a controller method to read from data and add data to the model
    @RequestMapping("/processFormV3")
    public String formWithModel(@RequestParam("studentName") String name, Model model) {
        // convert data to all caps
        name = name.toUpperCase();
        // create the message
        String result = "Using Annotation! " + name;
        // add message to the model
        model.addAttribute("message", result);
        return "helloworld";
    }

HTML 模板方面,同样将指向的地址从 v2 修改到 v3 就可以,效果如下:

在这里插入图片描述

GetMapping & PostMapping

这是上面提到的安全性问题,从开发实现的角度来说,其实不太需要特别在意 spring 底层是怎么完成依赖注入的。不过从语义化开发和安全性的角度,分别使用 @PostMapping@GetMapping 还是挺重要的,一般来说:

  • GET 是用来获取数据的(Retrieve),而 POST 是用来发送数据的(Create, Update, Delete)

  • GET 的数据传送通过 URL Query Param,而 POST 通过 body request

  • GET 的安全性更低,而 POST 安全性更高

  • GET 可以被用来保存书签,而 POST 不可以

  • GET 长度限制比较大,而 POST 的长度限制比较小

    一般情况下 GET 是够用的,毕竟好像有 8000 个左右的字符,我只遇到过一个情况被后台拒绝了……那就是老板想要穷举一堆 AND/OR 的操作让后台可以直接拼接到数据库了去搜索,结果就……超过限制了……

目前 HTML 模板中使用的都是 GET ,如果 Spring 这里使用 @PostMapping 的话,那么 spring 就会抛出 method not allow 的错:

在这里插入图片描述

所以这部分还是要注意的,如果特地规范了 @PostMapping@GetMapping,那么 HTML 部分也要进行对应的更新,如:

    @PostMapping("/showForm")
    public String showForm() {
        return "helloworld-form";
    }

以及

    @GetMapping("/processFormV3")
    public String formWithModel(@RequestParam("studentName") String name, Model model) {
        // convert data to all caps
        name = name.toUpperCase();
        // create the message
        String result = "Using Annotation! " + name;
        // add message to the model
        model.addAttribute("message", result);
        return "helloworld";
    }

更换成 POST 的效果展现如下:

在这里插入图片描述

这里数据就不会从 URL 中传递,反而是通过 request body:

在这里插入图片描述

数据绑定

前面一直手动获取 request body 中的数据,不过,其实 spring 也提供数据绑定,回顾一下这张图:

在这里插入图片描述

数据绑定就是直接对数据进行一个预处理,将数据绑定到对应的 POJO 上,省去了很多的手动操作。下面是具体的实现:

实现一个 POJO:

package com.example.thymeleafdemo.model;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@NoArgsConstructor
@ToString
public class Student {
    private String firstName;
    private String lastName;
}

更新 controller,使用新注解 @ModelAttribute

package com.example.thymeleafdemo.controller;

import com.example.thymeleafdemo.model.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class StudentController {
    @GetMapping("/showStudentForm")
    public String showForm(Model model) {
        // create a student obj
        Student student = new Student();
        // add student obj to the model
        model.addAttribute("student", student);
        return "student-form";
    }

    @PostMapping("/processStudentForm")
    public String processForm(@ModelAttribute("student") Student student) {
        // log the input data
        System.out.println("student: " + student.toString());

        return "student-confirmation";
    }
}

⚠️:这里 @ModelAttribute("student") 的名字,必须要和下面 thymeleaf 中的 object 一致

更新 HTML 模板:

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

    <form
      th:action="@{/processStudentForm}"
      th:object="${student}"
      method="post"
    >
      First Name: <input type="text" th:field="*{firstName}" />

      <br /><br />

      Last Name: <input type="text" th:field="${student.lastName}" />

      <br /><br />

      <input type="submit" value="Submit" />

      <script src="http://localhost:35729/livereload.js"></script>
    </form>
  </body>
</html>

⚠️:这里的 th:object="${student}" 就是 @ModelAttribute("student") 中的 student,这里的名字必须一致

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

    The student is confirmed:
    <span th:text="${student.firstName} + ' ' + ${student.lastName}"></span>

    <script src="http://localhost:35729/livereload.js"></script>
  </body>
</html>

⚠️:这里的 student 是手动通过 model.addAttribute("student", student); 进行绑定的

最终效果如下:

在这里插入图片描述

在这里插入图片描述

thymeleaf 属性

这里新增一些比较常用的 thymeleaf 的表单属性的用法

下拉框

即 dropdown,一个比较死板的写法如下:

<select th:field="*{country}">
  <option th:value="Brazil">Brazil</option>
  <option th:value="France">France</option>
  <option th:value="Germany">Germany</option>
  <option th:value="India">India</option>
</select>

在显示的页面新增代码:

<br /><br />

Country: <span th:text="${student.country}"></span>

这时候更新一下 学生 这个 POJO,新增一个 country 的属性:

public class Student {
    private String firstName;
    private String lastName;
    private String country;
}

因为使用了数据绑定,所以 controller 部分的代码不需要进行任何的变动,实现效果如下:

在这里插入图片描述

动态获取下拉框

上面的代码是写死的,不过有的情况下,可能需要通过 properties 文件获取一些数据,这个时候就没有办法在 thymeleaf 写死所有的选项了

properties 文件更新如下:

countries=Brazil,France,Germany,India,Mexico,Spain,United States

这里新增的是一个关于国家的数组

这个时候就需要更新 controller 了,需要从 properties 文件中获取对应的国家,并且将其传到模板引擎中:

    @Value("${countries}")
    private List<String> countries;

    @GetMapping("/showStudentForm")
    public String showForm(Model model) {
        // create a student obj
        Student student = new Student();
        // add student obj to the model
        model.addAttribute("student", student);

        // add the list of countries to the model
        model.addAttribute("countries", countries);
        return "student-form";
    }

HTML 部分更新如下:

<select th:field="*{country}">
  <option
    th:each="tempCountry : ${countries}"
    th:value="${tempCountry}"
    th:text="${tempCountry}"
  ></option>
</select>

这里使用的是一个 thymeleaf 的 for 循环,最终展示效果如下:

在这里插入图片描述

单选

即 radio button,这里也通过两个方式实现,一个就是写死值的方式,另一个是通过 properties 文件导入

写死的方式如下:

Favorite Programming Language:

<label>
  <input type="radio" th:field="*{favoriteLanguage}" th:value="Go" />
  Go
</label>
<label>
  <input type="radio" th:field="*{favoriteLanguage}" th:value="Java" />
  Java
</label>
<label>
  <input type="radio" th:field="*{favoriteLanguage}" th:value="Python" />
  Python
</label>

其余需要更新的地方也只有 POJO,这里略过不提,展现效果如下:

在这里插入图片描述

动态获取单选

实现方法类似,这里也不多赘述

properties 文件更新:

languages=Go,Java,Python,Rust,TypeScript,JavaScript

controller 部分略过不提,下面是 HTML 的修改:

Favorite Programming Language:

<div th:each="language : ${languages}">
  <label>
    <input type="radio" th:field="*{favoriteLanguage}" th:value="${language}" />
    <span th:text="${language}"></span>
  </label>
</div>

⚠️:这里的 for 循环是绑定在一个外部的 div 上,如果直接迭代 label,那就代表着一个 label 会对应不同的 input,就会影响具体的功能实现

最终渲染效果:

在这里插入图片描述

多选

也就是 checkbox,具体不多赘述,丢代码即可

两个 HTML 的修改:

Favorite Operation System:

<input
  type="checkbox"
  id="Linux"
  th:field="*{favoriteOSs}"
  th:value="Linux"
/><label for="Linux">Linux</label>
<input
  type="checkbox"
  id="MacOS"
  th:field="*{favoriteOSs}"
  th:value="MacOS"
/><label for="MacOS">MacOS</label>
<input
  type="checkbox"
  id="ms"
  th:field="*{favoriteOSs}"
  th:value="'Microsoft Windows'"
/><label for="ms">Microsoft Windows</label>
Favorite Operating Systems: <span th:text="${student.favoriteOSs}"></span>

POJO:

private List<String> favoriteOSs;

效果如下:

在这里插入图片描述

循环渲染结果

这里的格式还是稍微有点奇怪的,因为多选的保存格式为 List<String>,尽管 toString() 的默认实现不是很奇怪,不过也可以稍微优化一下:

<ul>
  <li th:each="favOs: ${student.favoriteOSs}" th:text="${favOs}"></li>
</ul>

在这里插入图片描述

动态渲染多选

具体实现也略过了,和之前的实现一样:

systems=Linux,MacOS,Microsoft Windows,Android,IOS
public class StudentController {
    @Value("${systems}")
    private List<String> systems;

    @GetMapping("/showStudentForm")
    public String showForm(Model model) {
        // ...
        model.addAttribute("systems", systems);
        // ...
    }
}
Favorite Operation System:

<span th:each="system: ${systems}">
  <input
    type="checkbox"
    id="${system}"
    th:field="*{favoriteOSs}"
    th:value="${system}"
  />
  <label for="${system}" th:text="${system}"></label>
</span>

最终效果如下:

在这里插入图片描述

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

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

相关文章

Docker与Docker-Compose详解

1、Docker是什么&#xff1f; 在计算机中&#xff0c;虚拟化(英语: Virtualization) 是一种资源管理技术&#xff0c;是将计算机的各种实体资源&#xff0c;如服务器、网络、内存及存储等&#xff0c;予以抽象、转换后呈现出来&#xff0c;打破实体结构间的不可切割的障碍&…

【深度学习】—— 神经网络介绍

神经网络介绍 本系列主要是吴恩达深度学习系列视频的笔记&#xff0c;传送门&#xff1a;https://www.coursera.org/deeplearning-ai 目录 神经网络介绍神经网络的应用深度学习兴起的原因 神经网络&#xff0c;全称人工神经网络&#xff08;Artificial Neural Network&#xf…

c# 下 ScintillaNET 显示XML信息并折叠节点

winform下显示XML信息&#xff08;非WPF&#xff09; 之前使用的是FastColoredTextBox&#xff0c;github地址如下&#xff1a; https://github.com/PavelTorgashov/FastColoredTextBox 但是有个问题&#xff0c;它支持中文&#xff0c;wordwraptrue&#xff0c;自动换行时&…

[大模型]Gemma-2B-Instruct FastApi 部署调用

环境准备 在 平台中租赁一个 3090 等 24G 显存的显卡机器&#xff0c;如下图所示镜像选择 PyTorch-->2.1.0-->3.10(ubuntu22.04)-->12.1。 接下来打开刚刚租用服务器的 JupyterLab&#xff0c;并且打开其中的终端开始环境配置、模型下载和运行演示。 pip 换源加速下载…

【IoT NTN】3GPP R18中关于各类IoT设备在NTN中的增强和扩展

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G技术研究。 博客内容主要围绕…

Nginx学习笔记(十)如何配置HTTPS协议?(公网)

目录 一、简介二、SSL 证书类型介绍三、公网 SSL 证书3.1 证书管理工具3.2 下载安装 acme.sh3.3 申请并下载证书报错1&#xff1a;没有指定账号报错2&#xff1a;DNS无法解析的域名报错3&#xff1a;无效的响应 404 3.4 配置 Nginx3.5 证书过期刷新 四、补充4.1 同一域名的不同…

Unity API学习之消息机制理论与应用

目录 消息机制 示例1&#xff1a;同一物体中不同组件之间发送消息 示例2&#xff1a;父与子对象之间的消息发送(BroadcastMassage) 父对象向子对象发送消息 ​编辑 子对象向父对象发送消息 消息机制 在Unity中&#xff0c;SendMessage 方法用于在游戏对象及其所有子对象上…

【云岚到家】-day02-2-客户管理-认证授权

【云岚到家】-day02-2-客户管理-认证授权 第二章 客户管理1 认证模块1.1 需求分析1.2 小程序认证1.2.1 测试小程序认证1.2.1.1 参考官方流程1.2.1.2 申请小程序账号1.2.1.3 创建jzo2o-customer1.2.1.4 部署前端1.2.1.5 编译运行1.2.1.6 真机调试 2 阅读代码2.1 小程序认证流程2…

虚拟机ping不通主机,但是主机可以ping通虚拟机

我在Windows10系统安装了虚拟机&#xff0c;设置的主机与虚拟机的连接方式是桥接&#xff0c;安装好后&#xff0c;发现虚拟机ping不通主机&#xff0c;但是主机可以ping通虚拟机。 我的操作是&#xff1a;关闭防火墙&#xff0c;发现虚拟机可以ping通主机了。说明是Windows10…

设计高并发秒杀系统:保障稳定性与数据一致性

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 一. 系统架构设计 1. 系统架构图 二、 系统流程 三…

AI绘画工具Ideogram测评:和Midjourney不分伯仲的AI图像工具之一

Ideogram 是一款令人印象深刻的人工智能图像工具&#xff0c;但尽管它于去年 8 月推出并具有不可思议的文本渲染能力&#xff0c;但它并没有引起其他一些更引人注目的 GenAI 服务的关注。 随着该公司推出其生成式人工智能模型 1.0 版本&#xff0c;这种情况即将发生改变&#…

详解 Flink 的容错机制

一、检查点 Checkpoint 1. 介绍 有状态流应用中的检查点&#xff08;checkpoint&#xff09;&#xff0c;其实就是所有任务的状态在某个时间点的一个快照&#xff08;一份拷贝&#xff09;&#xff0c;这个时间点应该是所有任务都恰好处理完一个相同的输入数据的时刻。在一个流…

帕友的小贴士,锻炼

帕金森病作为一种慢性神经系统疾病&#xff0c;对患者的生活质量产生了深远的影响。虽然医学界对于帕金森病的治疗仍在不断探索&#xff0c;但合理的锻炼已经被证实是改善患者症状、提高生活质量的有效途径之一。本文旨在为帕金森病患者推荐一些适合的锻炼方法&#xff0c;帮助…

2024 年最佳 iPhone 数据恢复软件

最好的 iPhone 数据恢复软件是什么&#xff1f; 说到 iPhone 数据恢复&#xff0c;拥有合适的软件对于恢复丢失或删除的文件至关重要&#xff0c;无论是照片、视频、消息、联系人还是其他重要数据。那么&#xff0c;最好的 iPhone 数据恢复软件是什么&#xff1f;有几个因素有…

使用C++结合OpenCV进行图像处理与分类

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的在读研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三…

力扣hot100: 48. 旋转图像

LeetCode&#xff1a;48. 旋转图像 受到力扣hot100&#xff1a;54. 螺旋矩阵的启发&#xff0c;我们可以对旋转图像按层旋转&#xff0c;我们只需要记录四个顶点&#xff0c;并且本题是一个方阵&#xff0c;四个顶点就能完成图像的旋转操作。 1、逐层旋转 注意到&#xff0…

设计随笔 ---- ADR4525 篇

ADR4525一颗超低噪声、高精度2.5V基准电压源&#xff1b; Fluke 17B准确度指标&#xff1a; ADR4525指标&#xff1a; Fluke 17B测试结果&#xff1a; 2.5V的基准&#xff0c;输出只有2.477V&#xff0c;其实这么高精度的电压基准用3位半的万用表来测试本身就是一个错误&#…

3-哈希表-51-四数相加 II-LeetCode454

3-哈希表-51-四数相加 II-LeetCode454 LeetCode: 题目序号454 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&#xff08;纯纯技术文&#xff…

《QT实用小工具·七十》openssl+qt开发的P2P文件加密传输工具

1、概述 源码放在文章末尾 该项目实现了P2P的文件加密传输功能&#xff0c;具体包含如下功能&#xff1a; 1、 多文件多线程传输 2、rsaaes文件传输加密 3、秘钥随机生成 4、断点续传 5、跨域传输引导服务器 项目界面如下所示&#xff1a; 接收界面 发送界面 RSA秘钥生成…

(二)深度学习基础练习题(54道选择题)

本文整理了深度学习基础知识相关的练习题&#xff0c;共54道&#xff0c;适用于想巩固深度学习基础的同学。来源&#xff1a;如荷学数据科学题库&#xff08;技术专项-深度学习&#xff09;。 1&#xff09; 2&#xff09; 3&#xff09; 4&#xff09; 5&#xff09; 6&#…