当前位置: 首页 > news >正文

Web基础 -SpringBoot入门 -HTTP-分层解耦 -三层架构

在HTML、CSS、JS 以及图片、音频、视频等这些资源,我们都称为静态资源。 所谓静态资源,就是指在服务器上存储的不会改变的数据,通常不会根据用户的请求而变化。

那与静态资源对应的还有一类资源,就是动态资源。那所谓动态资源,就是指在服务器端上存储的,会根据用户请求和其他数据动态生成的,内容可能会在每次请求时都发生变化。 在企业开发项目中,都是基于Spring实现的。

而Spring家族旗下这么多的技术,最基础、最核心的是 SpringFramework。其他的spring家族的技术,都是基于SpringFramework的,SpringFramework中提供很多实用功能,如:依赖注入、事务管理、web开发支持、数据访问、消息服务等等。

而如果我们在项目中,直接基于SpringFramework进行开发,存在两个问题:

配置繁琐

入门难度大

所以基于此呢,spring官方推荐我们从另外一个项目开始学习,那就是目前最火爆的SpringBoot。 通过springboot就可以快速的帮我们构建应用程序,所以springboot呢,最大的特点有两个 :

  • 简化配置

  • 快速开发

Spring Boot 可以帮助我们非常快速的构建应用程序、简化开发、提高效率 。

而直接基于SpringBoot进行项目构建和开发,不仅是Spring官方推荐的方式,也是现在企业开发的主流。

一、创建SpringBoot项目

左侧生成器选择SpringBoot,右侧选择Maven依赖即可。

下一步后勾选SpringWeb,项目即创建完成。

基础项目入门

package org.example.springbootwebquickstract;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController//当前类是一个请求处理类
public class HelloController {@RequestMapping("/hello")public String hello(String name){System.out.println("name:"+name);return "hello:"+name;}
}

上述代码中,注解@RestController起到标注当前的类为请求处理类的作用,注解@RequestMapping起到标注请求路径的作用。括号内的hello即为请求路径。

当需要访问对应数据时,可以用请求路径访问,例如本程序可以使用http://localhost:8080/hello?name=CodeBlossom进行访问

运行程序

运行SpringBoot自动生成的引导类 (标识有@SpringBootApplication注解的类)即可自动运行引导类下的包及其子包下的程序。

HTTP协议

HTTP:Hyper Text Transfer Protocol(超文本传输协议),规定了浏览器与服务器之间数据传输的规则。

  • http是互联网上应用最为广泛的一种网络协议

  • http协议要求:浏览器在向服务器发送请求数据时,或是服务器在向浏览器发送响应数据时,都必须按照固定的格式进行数据传输

HTTP协议的特点

基于TCP:面向连接,安全

基于请求-响应模型:一次请求对应一次响应,先请求后响应。请求和响应是一一对应的关系,没有请求就没有响应。

HTTP 协议分为:请求协议和响应协议

请求协议:浏览器将数据以请求格式发送到服务器。包括:请求行、请求头 、请求体

常见的HTTP请求头

请求头

含义

Host

表示请求的主机名

User-Agent

浏览器版本。 例如:Chrome浏览器的标识类似Mozilla/5.0 ...Chrome/79 ,IE浏览器的标识类似Mozilla/5.0 (Windows NT ...)like Gecko

Accept

表示浏览器能接收的资源类型,如text/*,image/*或者*/*表示所有;

Accept-Language

表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;

Accept-Encoding

表示浏览器可以支持的压缩类型,例如gzip, deflate等。

Content-Type

请求主体的数据类型

Content-Length

数据主体的大小(单位:字节)

获取请求体数据

Web对HTTP协议的请求数据进行解析,并进行了封装(HttpServletRequest),使程序员可以直接用代码获取请求体数据

package org.example.springbootwebquickstract;import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RequestController {@RequestMapping("/request")public String resquest(HttpServletRequest request){//1、获取请求方式String method = request.getMethod();System.out.println("method:"+method);//2、获取请求url地址String url = request.getRequestURL().toString();//http://localhost:8080/requestSystem.out.println("请求url地址:"+url);String requestURI = request.getRequestURI();System.out.println("请求uri地址:"+requestURI);//3、获取请求协议String protocol = request.getProtocol();System.out.println("请求协议"+protocol);//4、获取请求参数 -name,age .....String name = request.getParameter("name");String age = request.getParameter("age");System.out.println("name:"+name+",age:"+age);//5、获取请求头:AcceptString header = request.getHeader("Accept");//指定名字的请求头System.out.println("请求头Accept:"+header);return "OK";}
}

HTTP响应协议

响应体的第一行为响应行 分为  协议版本:HTTP/1.1 响应状态码401 以及状态码描述

响应头:响应数据的第二行开始。格式为key:value形式

http是个无状态的协议,所以可以在请求头和响应头中设置一些信息和想要执行的动作,这样,对方在收到信息后,就可以知道你是谁,你想干什么

常见的HTTP响应头有:

Content-Type:表示该响应内容的类型,例如text/html,image/jpeg ; Content-Length:表示该响应内容的长度(字节数);

Content-Encoding:表示该响应压缩算法,例如gzip ; Cache-Control:指示客户端应如何缓存,例如max-age=300表示可以最多缓存300秒 ;

Set-Cookie: 告诉浏览器为当前页面所在的域设置cookie ;

响应体(以上图中绿色部分): 响应数据的最后一部分。存储响应的数据

代码示例

package org.example.springbootwebquickstract;import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ResponseController {/*方式一:设置响应数据基于HttpServletResponse对象*/@RequestMapping("/response")public void response(HttpServletResponse  response) throws  Exception{//1、设置响应状态码response.setStatus(HttpServletResponse.SC_OK);//2、设置响应头response.setHeader("Name","CodeBlossom");//3、设置响应体response.getWriter().write("<h1>Hello World</h1>");}/*方式二:设置响应数据基于ResponseEntity对象(spring提供的方式)*/@RequestMapping("/response2")public ResponseEntity< String> response2(){return ResponseEntity.status(401).header("name","javaweb").body("<h1>Hello response</h1>");}
}

SpringBootWeb案例

基于SpringBoot开发web程序,实现页面的渲染展示

先创建一个封装用户信息的实体类

package org.example.springbootweb01.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {private Integer id;//项目开发建议使用包装类型private String username;private String password;private String name;private Integer age;private LocalDateTime updateTime;}

 

由于在案例中,需要读取文本中的数据,并且还需要将对象转为json格式,所以这里呢,我们在项目中再引入一个非常常用的工具包hutool。 然后调用里面的工具类,就可以非常方便快捷的完成业务操作。

在Maven带有的xml文件中添加依赖

<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.27</version>
</dependency>
package org.example.springbootweb01.controller;import cn.hutool.core.io.IoUtil;
import jakarta.annotation.Resource;
import org.example.springbootweb01.pojo.User;
import org.example.springbootweb01.service.UserService;
import org.example.springbootweb01.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;/*
用户信息Controller*/
@RestController//@ResponseBody ->作用:将controller返回值直接作为响应体的数据直接响应;返回值是对象/集合->json->响应体
public class UserController {@RequestMapping("/list")public List<User> list()throws  Exception{//InputStream in = new FileInputStream(new File("src/main/resources/user.txt"));    //磁盘目录会改变,所以不推荐InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");    //类加载器,将文件放在类路径下,通过类加载器获取//1、加载并读取User.txt文件获取用户数据ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8,new ArrayList<>());//2、解析用户信息,将用户数据封装成User对象->List集合List<User> userList = lines.stream().map(line -> {String[] parts = line.split(",");Integer id = Integer.parseInt(parts[0]);String username = parts[1];String password = parts[2];String name = parts[3];Integer age = Integer.parseInt(parts[4]);LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));return new User(id, username, password, name, age, updateTime);}).toList();//3、返回用户数据(json)return userList;}}

将前端代码放到Spring标注的静态资源库中 

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>用户列表数据</title><style>/*定义css,美化表格*/table{border-collapse: collapse;width: 100%;margin-top: 20px;border: 1px solid #ccc;text-align: center;font-size: 14px;}tr {height: 40px;}th,td{border: 1px solid #ccc;}thead{background-color: #e8e8e8;}h1{text-align: center;font-family: 楷体;}</style>
</head>
<body><div id="app"><h1>用户列表数据</h1><!--定义一个表格,包括6列,分别是: ID, 用户名, 密码, 姓名, 年龄, 更新时间--><table><thead><tr><th>ID</th><th>用户名</th><th>密码</th><th>姓名</th><th>年龄</th><th>更新时间</th></tr></thead><tbody><tr v-for="user in userList"><td>{{user.id}}</td><td>{{user.username}}</td><td>{{user.password}}</td><td>{{user.name}}</td><td>{{user.age}}</td><td>{{user.updateTime}}</td></tr></tbody></table></div><!--引入axios--><script src="js/axios.min.js"></script><script type="module">import { createApp } from './js/vue.esm-browser.js'createApp({data() {return {userList: []}},methods: {async search(){const result = await axios.get('/list');this.userList = result.data;}},mounted() {this.search();}}).mount('#app')</script>
</body>
</html>

@ResponseBody(包含在@RestController内)注解:

  • 类型:方法注解、类注解

  • 位置:书写在Controller方法上或类上

  • 作用:将方法返回值直接响应给浏览器,如果返回值类型是实体对象/集合,将会转换为JSON格式后在响应给浏览器

  1. 三层架构

在我们进行程序设计以及程序开发时,尽可能让每一个接口、类、方法的职责更单一些(单一职责原则)。这样可以让代码维护更简单

那其实我们上述案例的处理逻辑呢,从组成上看可以分为三个部分:​
数据访问:负责业务数据的维护操作,包括增、删、改、查等操作。​
逻辑处理:负责业务逻辑处理的代码。​
请求处理、响应数据:负责,接收页面的请求,给页面响应数据。

按照上述的三个组成部分,在项目开发中,可以将代码分为三层,如图所示:

  • Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。

  • Service:业务逻辑层。处理具体的业务逻辑。

  • Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。

执行流程

浏览器访问页面->控制层->业务逻辑层->数据访问层,这样实现了分层解耦思想,例如对业务层进行变更,不会影响到控制层和Dao层。

分层解耦的思想

耦合:衡量软件中各个层/各个模块的依赖关联层度。

内聚:软件中各个功能模块的功能联系

软件设计原则:高内聚低耦合

上述的思想无法实现解耦思想

例如上图,在控制层需要指定new一个Uservice的实现类创建,当我们需要修改其使用的实现类时还是需要更改控制层。我们可以根据之前的内容实现这个问题。当我们定义常量时,可以专门创建一个常量的容器(类),然后当需要更改常量时在容器内将其更改即可,对调用的代码无影响。此时的解耦也可以用这个操作,将UserService的实现类放到容器中,然后将需要使用的实现类注入到对应的程序中。

们想要实现上述解耦操作,就涉及到Spring中的两个核心概念:

  • 控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。

    • 对象的创建权由程序员主动创建转移到容器(由容器创建、管理对象)。这个容器称为:IOC容器或Spring容器。

  • 依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。

    • 程序运行时需要某个资源,此时容器就为其提供这个资源。

    • 例:EmpController程序运行时需要EmpService对象,Spring容器就为其提供并注入EmpService对象。

Bean的声明

  • bean对象:IOC容器中创建、管理的对象,称之为:bean对象。

实现类加上 @Component 注解,就代表把当前类产生的对象交给IOC容器管理。

在需要注入容器中的类的对象加上@Autowired注解,就代表把容器内的实现类交给当前的对象。

前面我们提到IOC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。IOC容器创建的对象称为bean对象。

在之前的入门案例中,要把某个对象交给IOC容器管理,需要在类上添加一个注解:@Component

而Spring框架为了更好的标识web应用程序开发当中,bean对象到底归属于哪一层,又提供了@Component的衍生注解:

注解

说明

位置

@Component

声明bean的基础注解

不属于以下三类时,用此注解

@Controller

@Component的衍生注解

标注在控制层类上

@Service

@Component的衍生注解

标注在业务层类上

@Repository

@Component的衍生注解

标注在数据访问层类上(由于与mybatis整合,用的少)

DI详解

依赖注入,是指IOC容器要为应用程序去提供运行时所依赖的资源,而资源指的就是对象。​
在入门程序案例中,我们使用了@Autowired这个注解,完成了依赖注入的操作,而这个Autowired翻译过来叫:自动装配。​
@Autowired注解,默认是按照类型进行自动装配的(去IOC容器中找某个类型的对象,然后完成注入操作)

@Autowired用法

 属性注入(常用)

@RestController
public class UserController {//方式一: 属性注入@Autowiredprivate UserService userService;}
  • 优点:代码简洁、方便快速开发。

  • 缺点:隐藏了类之间的依赖关系、可能会破坏类的封装性。

构造函数注入(常用)

@RestController
public class UserController {//方式二: 构造器注入private final UserService userService;@Autowired //如果当前类中只存在一个构造函数, @Autowired可以省略public UserController(UserService userService) {this.userService = userService;}}   
  • 优点:能清晰地看到类的依赖关系、提高了代码的安全性。

  • 缺点:代码繁琐、如果构造参数过多,可能会导致构造函数臃肿。

  • 注意:如果只有一个构造函数,@Autowired注解可以省略。(通常来说,也只有一个构造函数)

3). setter注入

/*** 用户信息Controller*/
@RestController
public class UserController {//方式三: setter注入private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}}    

优点:保持了类的封装性,依赖关系更清晰。

缺点:需要额外编写setter方法,增加了代码量。

注意事项:

在IOC容器中,存在多个相同类型的bean对象,容器会不知道该给当前的对象注入哪个bean对象,程序会报错。

为了解决上述问题,Spring给了以下三种方案

  • @Primary

  • @Qualifier

  • @Resource

方案一:使用@Primary注解

当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现。

在想要注入的bean对象上加此注解即可默认注入该个对象

方案二:使用@Qualifier注解​(bean对象的默认名为实现类的首字母小写)
指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称。 @Qualifier注解不能单独使用,必须配合@Autowired使用。例:@Qualifier("bean对象")

方案三:使用@Resource注解​
是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。例:

@Resource(name = "userServiceImpl")

项目构建

package org.example.springbootweb01.dao;import java.util.List;public interface UserDao {public List<String> findAll();
}
package org.example.springbootweb01.service;import org.example.springbootweb01.pojo.User;import java.util.List;public interface UserService {public List<User> findAll();
}
package org.example.springbootweb01.controller;import cn.hutool.core.io.IoUtil;
import jakarta.annotation.Resource;
import org.example.springbootweb01.pojo.User;
import org.example.springbootweb01.service.UserService;
import org.example.springbootweb01.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;/*
用户信息Controller*/
@RestController//@ResponseBody ->作用:将controller返回值直接作为响应体的数据直接响应;返回值是对象/集合->json->响应体
public class UserController {
//    1部分/*@RequestMapping("/list")public List<User> list()throws  Exception{//InputStream in = new FileInputStream(new File("src/main/resources/user.txt"));    //磁盘目录会改变,所以不推荐InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");    //类加载器,将文件放在类路径下,通过类加载器获取//1、加载并读取User.txt文件获取用户数据ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8,new ArrayList<>());//2、解析用户信息,将用户数据封装成User对象->List集合List<User> userList = lines.stream().map(line -> {String[] parts = line.split(",");Integer id = Integer.parseInt(parts[0]);String username = parts[1];String password = parts[2];String name = parts[3];Integer age = Integer.parseInt(parts[4]);LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));return new User(id, username, password, name, age, updateTime);}).toList();//3、返回用户数据(json)return userList;}*/
//2部分/*private UserService userService = new UserServiceImpl();@RequestMapping("/list")public List<User> list()throws  Exception{List<User> userList =userService.findAll();//3、返回用户数据(json)return userList;*///方式一:属性注入//@Autowired        //@Autowired注解:自动注入//private UserService userService;
//    //方式二:构造方法注入
//    private final UserService userService;
//    @Autowired  //如果构造函数只有一个,@Autowired可以省略
//    public UserController(UserService userService) {
//        this.userService = userService;
//    }//方式三:setter方法注入private UserService userService;//@Qualifier("userServiceImpl")//@Autowired@Resource(name = "userServiceImpl")public void setUserService(UserService userService) {this.userService = userService;}@RequestMapping("/list")public List<User> list()throws  Exception{List<User> userList =userService.findAll();//3、返回用户数据(json)return userList;}
}
package org.example.springbootweb01.dao.impl;import cn.hutool.core.io.IoUtil;
import org.example.springbootweb01.dao.UserDao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@Repository("userDao")//括号内指定bean的名字,默认为类名首字母小写
//@Component  //将当前类交给ioc容器管理
public class UserDaoImpl implements UserDao {@Overridepublic List<String> findAll() {//InputStream in = new FileInputStream(new File("src/main/resources/user.txt"));//1、加载并读取User.txt文件获取用户数据InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8,new ArrayList<>());return lines;}
}
package org.example.springbootweb01.service.impl;import org.example.springbootweb01.dao.UserDao;
import org.example.springbootweb01.dao.impl.UserDaoImpl;
import org.example.springbootweb01.pojo.User;
import org.example.springbootweb01.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
@Service
//@Component//将当前类交给ioc容器管理
public class UserServiceImpl implements UserService {//1、调用dao获取数据//private UserDao userDao = new UserDaoImpl();@Autowired  //应用程序运行时会自动查找该类型的Bean对象,并赋值给该成员变量private UserDao userDao;@Overridepublic List<User> findAll() {List<String> lines = userDao.findAll();//2、解析用户信息,将用户数据封装成User对象->List集合List<User> userList = lines.stream().map(line -> {String[] parts = line.split(",");Integer id = Integer.parseInt(parts[0]);String username = parts[1];String password = parts[2];String name = parts[3];Integer age = Integer.parseInt(parts[4]);LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));return new User(id, username, password, name, age, updateTime);}).toList();return userList;}
}
package org.example.springbootweb01.service.impl;import org.example.springbootweb01.dao.UserDao;
import org.example.springbootweb01.pojo.User;
import org.example.springbootweb01.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
//@Primary    // 指定当前类为默认实现类
@Service
//@Component//将当前类交给ioc容器管理
public class UserServiceImpl2 implements UserService {//1、调用dao获取数据//private UserDao userDao = new UserDaoImpl();@Autowired  //应用程序运行时会自动查找该类型的Bean对象,并赋值给该成员变量private UserDao userDao;@Overridepublic List<User> findAll() {List<String> lines = userDao.findAll();//2、解析用户信息,将用户数据封装成User对象->List集合List<User> userList = lines.stream().map(line -> {String[] parts = line.split(",");Integer id = Integer.parseInt(parts[0]);String username = parts[1];String password = parts[2];String name = parts[3];Integer age = Integer.parseInt(parts[4]);LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));return new User(id+200, username, password, name, age, updateTime);}).toList();return userList;}
}

上述代码实现了分层解耦思想。

http://www.lryc.cn/news/574104.html

相关文章:

  • Protobuf 深度解析:从基础语法到高级应用
  • 【目标检测】图像处理基础:像素、分辨率与图像格式解析
  • “自动化失败归因”测试集-WhoWhen
  • 在大数据求职面试中如何回答分布式协调与数据挖掘问题
  • 云原生 CAD 让制造业设计协同更便捷
  • 3D模式格式转换工具HOOPS Exchange如何将3D PDF转换为STEP格式?
  • 【实时Linux实战系列】使用定时器实现定时任务
  • 计算机网络:(六)超详细讲解数据链路层 (附带图谱表格更好对比理解)
  • docker镜像中集成act工具
  • 刀客doc:阿里巴巴集团品牌部划归集团公关管理
  • Java基础(三):逻辑运算符详解
  • P3258 [JLOI2014] 松鼠的新家
  • (LeetCode 面试经典 150 题) 27.移除元素
  • PR出书启动
  • ✨通义万相2.1深度解析:AI视频生成引擎FLF2V-14B全流程指南(命令行参数+模型架构+数据流)
  • VTK.js
  • 容声冰箱如何让荔枝在世俱杯赛场外再“长7天”
  • Elasticsearch API访问权限控制:禁用外部端点访问
  • 在Ubuntu上设置Selenium自动化测试环境:Chrome与Firefox的详细指南
  • 海拔案例分享-门店业绩管理小程序
  • 小程序 顶部栏标题栏 下拉滚动 渐显白色背景
  • Python Django全功能框架开发秘籍
  • 多模态大语言模型arxiv论文略读(133)
  • 【nvidia-H100-ib排障实战2】:服务器 InfiniBand 网络性能问题深度分析
  • 学习Linux进程冻结技术
  • 科技资讯杂志科技资讯杂志社科技资讯编辑部2025年第9期目录
  • 微算法科技(NASDAQ:MLGO)研发可信共识算法TCA,解决区块链微服务中的数据一致性与安全挑战
  • 笔试强训:Day8
  • Qt for OpenHarmony 编译鸿蒙调用的动态库
  • MCU双分区方案,如何优雅地获知当前运行分区?