Spring MVC概述

news/2024/9/24 23:48:55/

1.1 MVC设计模式

MVC(Model-View-Controller)是一种软件设计模式,旨在将应用程序的业务逻辑、用户界面和用户输入分离。Spring MVC遵循这一模式,提供了以下几个核心组件:

  • Model:表示应用程序的数据和业务逻辑。
  • View:负责呈现模型数据的用户界面。
  • Controller:接收用户输入并调用相应的业务逻辑。
生活场景比喻
  • Model:厨房,负责准备食材和做菜。
  • View:餐桌,展示菜品和菜单。
  • Controller:服务员,负责接收你的订单,并将其传递给厨房。

1.2 Spring MVC的核心组件

  • DispatcherServlet:前端控制器,负责接收请求并将其分发到相应的处理器。
  • HandlerMapping:根据请求的URL找到对应的处理器。
  • Controller:处理请求的业务逻辑。
  • HandlerAdapter:用于调用具体的处理器。
  • ViewResolver:根据视图名称解析出具体的视图实现。
  • ModelAndView:封装模型数据和视图信息的对象。

1.3 Spring MVC的工作流程

Spring MVC的工作流程如下:

  1. 客户端发送请求到DispatcherServlet
  2. DispatcherServlet通过HandlerMapping查找对应的Controller
  3. Controller处理请求并返回ModelAndView对象。
  4. DispatcherServlet通过ViewResolver解析视图。
  5. 渲染视图并返回响应给客户端。
生活场景比喻
  1. 客户(客户端)向服务员DispatcherServlet)下单。
  2. 服务员根据订单(请求的URL)找到对应的厨师Controller)。
  3. 厨师准备好菜品(处理请求),并返回给服务员(ModelAndView)。
  4. 服务员将菜品放在餐桌上(视图),客户享用美食。

二、Spring MVC的请求处理

2.1 DispatcherServlet的实现

DispatcherServlet是Spring MVC的核心组件,负责接收和处理所有HTTP请求。它是前端控制器,所有请求首先到达这里。 (Spring Boot应用中添加@SpringBootApplication注解,框架会自动创建并配置一个DispatcherServlet

public class DispatcherServlet extends HttpServlet {@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) {// 1. 获取请求的处理器HandlerExecutionChain handler = getHandler(request);// 2. 执行处理器ModelAndView mv = handlerAdapter.handle(request, response, handler.getHandler());// 3. 渲染视图render(mv, request, response);}
}

2.2 HandlerMapping的实现

HandlerMapping用于将请求映射到对应的处理器。Spring MVC提供多种实现,最常用的是RequestMappingHandlerMapping

public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {@Overrideprotected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {// 1. 根据请求信息找到对应的HandlerMethodfor (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {if (entry.getKey().matches(request)) {return entry.getValue();}}return null;}
}

2.3 Controller的实现

Controller是业务逻辑的处理器,负责接收请求并返回模型和视图。

@Controller
public class MyController {@RequestMapping("/hello")public String hello(Model model) {model.addAttribute("message", "Hello, World!");return "helloView"; // 返回视图名称}
}

2.4 HandlerAdapter的实现

HandlerAdapter负责调用具体的处理器方法,并返回一个ModelAndView对象。

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter {@Overridepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1. 执行Controller的方法Method method = ((HandlerMethod) handler).getMethod();Object returnValue = method.invoke(handler, ...); // 传入方法参数return new ModelAndView("viewName", "model", returnValue);}
}

2.5 ViewResolver的实现

ViewResolver根据视图名称解析出实际的视图实现。

public class InternalResourceViewResolver extends AbstractUrlBasedViewResolver {@Overrideprotected View createView(String viewName, Locale locale) throws Exception {// 1. 创建JSP视图String url = getPrefix() + viewName + getSuffix();return new JstlView(url);}
}

三、Spring MVC的请求参数处理

3.1 请求参数的获取

Spring MVC提供了多种方式来获取请求参数。可以使用@RequestParam注解来获取单个参数,也可以使用@RequestParam注解结合数组或集合来获取多个参数。

@GetMapping("/greet")
public String greet(@RequestParam String name, Model model) {model.addAttribute("message", "Hello, " + name);return "greetView";
}

3.2 请求体的处理

对于POST请求,Spring MVC可以使用@RequestBody注解将请求体中的JSON数据自动转换为Java对象。

@PostMapping("/user")
public ResponseEntity<User> createUser(@RequestBody User user) {// 处理用户创建逻辑return ResponseEntity.ok(user);
}

3.3 文件上传处理

Spring MVC支持文件上传,可以使用MultipartFile来处理上传的文件。

@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {// 处理文件上传逻辑return "uploadSuccessView";
}

四、Spring MVC的视图解析

4.1 视图解析器的配置

视图解析器用于将视图名称解析为实际的视图实现。Spring MVC支持多种视图技术,如JSP、Thymeleaf、Freemarker等。

@Bean
public InternalResourceViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");return resolver;
}

4.2 JSP视图的使用

jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head><title>Hello Page</title>
</head>
<body><h1>${message}</h1>
</body>
</html>

4.3 Thymeleaf视图的使用

Thymeleaf是一种现代的服务器端Java模板引擎,支持HTML5和XML。

html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Hello Page</title>
</head>
<body><h1 th:text="${message}">Hello, World!</h1>
</body>
</html>

五、Spring MVC的异常处理

5.1 全局异常处理

Spring MVC提供了全局异常处理机制,可以使用@ControllerAdvice注解定义一个全局异常处理类。

@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public ResponseEntity<String> handleException(Exception e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());}
}

5.2 自定义异常处理

除了全局异常处理,还可以在Controller中使用@ExceptionHandler注解处理特定异常。

@Controller
public class MyController {@GetMapping("/error")public String error() {throw new RuntimeException("Something went wrong");}@ExceptionHandler(RuntimeException.class)public String handleRuntimeException(RuntimeException e) {return "errorView"; // 返回错误视图}
}

六、Spring MVC的拦截器

6.1 拦截器的定义

拦截器可以在请求处理之前和之后执行一些操作。可以通过实现HandlerInterceptor接口定义一个拦截器。

public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 在请求处理之前执行return true; // 返回true继续执行,返回false则中断请求}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 在请求处理之后执行}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 在请求完成之后执行}
}

6.2 拦截器的注册

可以通过实现WebMvcConfigurer接口将拦截器注册到Spring MVC中。

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); // 拦截所有请求}
}

七、Spring MVC的安全性

7.1 Spring Security的集成

Spring Security是一个强大的安全框架,可以与Spring MVC无缝集成。以下是基本的集成步骤:

  1. 添加Spring Security依赖。
  2. 创建Security配置类,继承WebSecurityConfigurerAdapter
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/public/**").permitAll() // 公开路径.anyRequest().authenticated() // 其他路径需要认证.and().formLogin(); // 表单登录}
}

7.2 基于注解的安全控制

可以使用@PreAuthorize@PostAuthorize注解进行方法级别的安全控制。  

八、Spring MVC的测试

8.1 单元测试

可以使用JUnit和Spring Test进行Spring MVC的单元测试。

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
public class MyControllerTest {@Autowiredprivate MockMvc mockMvc;@Testpublic void testGreet() throws Exception {mockMvc.perform(get("/greet").param("name", "John")).andExpect(status().isOk()).andExpect(model().attribute("message", "Hello, John"));}
}

8.2 集成测试

使用@SpringBootTest进行集成测试。

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTest {@Autowiredprivate TestRestTemplate restTemplate;@Testpublic void testGreet() {ResponseEntity<String> response = restTemplate.getForEntity("/greet?name=John", String.class);assertEquals(HttpStatus.OK, response.getStatusCode());}
}

九、Spring MVC的处理流程

9.1 详细处理流程

Spring MVC的处理流程主要分为以下几个步骤:

  1. 请求到达DispatcherServlet:客户端发送HTTP请求,首先到达DispatcherServlet,它是所有请求的入口。
  2. 查找处理器DispatcherServlet使用HandlerMapping查找对应的处理器(Controller)。它根据请求的URL和HTTP方法来匹配合适的处理器。
  3. 执行处理器:找到处理器后,DispatcherServlet使用HandlerAdapter执行该处理器。处理器方法被调用,并处理请求。
  4. 返回ModelAndView:处理器方法返回一个ModelAndView对象,包含模型数据和视图信息。
  5. 视图解析DispatcherServlet使用ViewResolver解析视图名称,找到实际的视图实现(如JSP、Thymeleaf等)。
  6. 渲染视图:视图被渲染,并将最终的HTML响应返回给客户端。
生活场景比喻
  1. 客户(客户端)向服务员DispatcherServlet)下单。
  2. 服务员根据订单(请求的URL)找到对应的厨师Controller)。
  3. 厨师准备好菜品(处理请求),并返回给服务员(ModelAndView)。
  4. 服务员将菜品放在餐桌上(视图),客户享用美食。

十、Spring MVC如何统一封装响应信息?

1. ApiResponse类定义

我们定义一个通用的ApiResponse类,可以接收任意类型的数据。

public class ApiResponse<T> {private int status; // 响应状态码private String message; // 响应消息private T data; // 响应数据// 构造函数public ApiResponse(int status, String message, T data) {this.status = status;this.message = message;this.data = data;}// Getter和Setter方法public int getStatus() {return status;}public void setStatus(int status) {this.status = status;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public T getData() {return data;}public void setData(T data) {this.data = data;}
}
2. GlobalResponseWrapper类

GlobalResponseWrapper中,可以使用不同的方法来处理不同类型的响应。

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;@ControllerAdvice // 该注解用于定义全局的异常处理和响应封装
public class GlobalResponseWrapper {// 处理所有未处理的异常@ExceptionHandler(Exception.class)public ResponseEntity<ApiResponse<Object>> handleException(Exception e) {// 创建一个统一的响应对象,状态码为500,包含异常信息ApiResponse<Object> response = new ApiResponse<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage(), null);// 返回响应实体,包含HTTP状态和响应体return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);}// 在每个请求中添加统一的成功响应结构@ModelAttributepublic void wrapResponse(Model model) {// 向模型中添加一个成功的响应对象model.addAttribute("apiResponse", new ApiResponse<>(200, "Success", null));}
}
3. 控制器示例

在控制器中,可以根据不同的情况返回字符串或对象。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class SampleController {// 返回字符串响应@GetMapping("/message")public ResponseEntity<ApiResponse<String>> getMessage() {// 创建一个字符串响应ApiResponse<String> response = new ApiResponse<>(200, "Success", "Hello, this is a string response!");return ResponseEntity.ok(response);}// 返回对象响应@GetMapping("/user")public ResponseEntity<ApiResponse<User>> getUser() {// 创建一个用户对象User user = new User(1, "John Doe", "john@example.com");// 创建一个对象响应ApiResponse<User> response = new ApiResponse<>(200, "Success", user);return ResponseEntity.ok(response);}
}
4. 用户类定义

定义一个简单的用户类User,以便在响应中使用。

public class User {private int id; // 用户IDprivate String name; // 用户姓名private String email; // 用户邮箱// 构造函数public User(int id, String name, String email) {this.id = id;this.name = name;this.email = email;}// Getter和Setter方法public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}
}

生活场景比喻

  • 状态码(status):就像菜单卡上的价格,告诉你这道菜的价值。
  • 消息(message):就像菜单卡上的描述,告诉你这道菜的特点和风味。
  • 数据(data):就像你点的菜品本身,是你真正想要的内容。

 设计模式

  • 模板方法模式:在GlobalResponseWrapper中,使用了模板方法模式,通过定义统一的异常处理和成功响应的封装,确保所有控制器都遵循相同的响应结构。这种方式使得代码更加一致。

  • 建造者模式:虽然在这个示例中没有明显使用建造者模式,但可以看到ApiResponse类的构造函数允许灵活创建响应对象。将复杂的对象构建过程封装在构造函数中,提升了代码的可读性。

十一、Spring MVC如何处理Date相关的参数

11.1 日期参数处理

在Web应用中,处理日期参数是一项常见需求。Spring MVC提供了多种方式来处理日期参数,例如使用@DateTimeFormat注解。

11.2 使用@DateTimeFormat

可以在控制器的方法参数上使用@DateTimeFormat注解来指定日期格式。

@GetMapping("/date")
public String getDate(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {// 处理日期逻辑return "dateView";
}

11.3 自定义日期格式化器

如果需要更复杂的日期处理,可以自定义格式化器。

@Component
public class CustomDateFormatter implements Formatter<LocalDate> {@Overridepublic LocalDate parse(String text, Locale locale) throws ParseException {return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd"));}@Overridepublic String print(LocalDate object, Locale locale) {return object.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));}
}

十二、相关问题

12.1 常见问题

1. Spring MVC的核心组件

1.1 DispatcherServlet
  • 作用:DispatcherServlet是Spring MVC的前端控制器,负责接收所有HTTP请求并将其分发到相应的处理器(Controller)。它是整个Spring MVC框架的核心。
1.2 HandlerMapping
  • 作用:HandlerMapping用于根据请求的URL查找匹配的Controller。它将请求映射到具体的处理方法,并为DispatcherServlet提供相应的处理器信息。
1.3 Controller
  • 作用:Controller是处理请求的核心组件。它接收来自DispatcherServlet的请求,执行业务逻辑,并返回一个ModelAndView对象,封装了模型数据和视图信息。
1.4 HandlerAdapter
  • 作用:HandlerAdapter用于调用具体的处理方法。它支持多种类型的处理器(Controller),并且以统一的方式调用这些处理器的方法。
1.5 ViewResolver
  • 作用:ViewResolver用于解析视图名称,将其转换为实际的视图实现。它根据返回的视图名称找到对应的视图(如JSP、Thymeleaf等),并将模型数据传递给视图进行渲染。

2. Spring MVC的请求处理流程

  1. 客户端发送请求:用户通过浏览器发送HTTP请求,目标URL对应于DispatcherServlet。
  2. DispatcherServlet接收请求:DispatcherServlet作为前端控制器,接收所有请求。
  3. HandlerMapping查找Controller:DispatcherServlet通过HandlerMapping查找与请求URL匹配的Controller。
  4. Controller处理请求:找到相应的Controller后,DispatcherServlet调用该Controller的方法处理请求,并返回一个ModelAndView对象。
  5. HandlerAdapter调用处理方法:HandlerAdapter负责调用具体的处理方法,确保请求的处理逻辑被执行。
  6. ViewResolver解析视图:DispatcherServlet使用ViewResolver解析返回的视图名称,找到实际的视图实现。
  7. 渲染视图并返回响应:视图被渲染后,生成的HTML内容被返回给客户端,完成请求处理。

3. 如何在Spring MVC中处理异常?

3.1 全局异常处理的实现方式

使用@ControllerAdvice@ExceptionHandler注解可以实现全局异常处理,捕获应用中的所有未处理异常,并返回统一的错误响应。

3.2 示例代码
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;@ControllerAdvice // 定义全局异常处理
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class) // 捕获所有异常public ResponseEntity<ApiResponse<String>> handleException(Exception e) {// 创建统一的错误响应ApiResponse<String> response = new ApiResponse<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage(), null);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);}
}

4. Spring MVC与Spring Boot的区别是什么?

  • Spring MVC是一个用于构建Web应用程序的框架,而Spring Boot是一个用于快速构建Spring应用程序的工具,简化了Spring配置。
  • Spring Boot提供了自动配置功能,简化了Spring MVC的配置过程,允许开发者快速启动项目。
  • Spring Boot集成了Spring MVC,可以通过简单的注解和配置快速构建RESTful API。

5. 如何处理Spring MVC中的跨域请求(CORS)?

  • 可以在Spring MVC中通过@CrossOrigin注解来处理跨域请求。
  • 也可以在WebMvcConfigurer接口的实现中重写addCorsMappings方法进行全局配置。
示例代码:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 允许所有路径.allowedOrigins("http://example.com") // 允许的来源.allowedMethods("GET", "POST", "PUT", "DELETE"); // 允许的方法}
}

6 Spring MVC如何支持文件上传?

  • 可以使用MultipartFile类来处理文件上传。
  • 需要在配置文件中设置文件上传的大小限制和其他相关配置。
示例代码:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;@RestController
public class FileUploadController {@PostMapping("/upload")public String handleFileUpload(@RequestParam("file") MultipartFile file) {// 处理文件上传if (!file.isEmpty()) {// 保存文件或其他操作return "File uploaded successfully: " + file.getOriginalFilename();}return "File upload failed.";}
}

7. Spring MVC如何实现请求参数的验证?

  • 可以使用JSR-303/JSR-380(如Hibernate Validator)进行请求参数的验证。
  • 在模型类属性上使用注解,如@NotNull@Size等,结合@Valid注解进行验证。
示例代码:
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;public class User {@NotNull(message = "Name cannot be null")@Size(min = 2, max = 30, message = "Name must be between 2 and 30 characters")private String name;// getters and setters
}import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class UserController {@PostMapping("/user")public String createUser(@Valid @RequestBody User user) {return "User created: " + user.getName();}
}

8. Spring MVC如何实现请求的限流?

  • 可以使用AOP(面向切面编程)来实现请求限流,记录请求次数并限制频率。
  • 还可以使用第三方库,如Bucket4j或Guava RateLimiter,来实现更复杂的限流策略。
示例代码:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class RateLimiterAspect {private final RateLimiter rateLimiter = RateLimiter.create(1.0); // 每秒1个请求@Before("execution(* com.example.controller.*.*(..))")public void limit() {if (!rateLimiter.tryAcquire()) {throw new RuntimeException("Too many requests");}}
}

9. Spring MVC如何支持异步请求

  • 可以使用@Async注解将方法标记为异步执行。
  • 还可以使用DeferredResultCallable来处理异步请求,避免阻塞。
示例代码:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;@RestController
public class AsyncController {@GetMapping("/async")public DeferredResult<String> async() {DeferredResult<String> deferredResult = new DeferredResult<>();// 模拟异步处理new Thread(() -> {try {Thread.sleep(2000); // 模拟耗时操作deferredResult.setResult("Async response");} catch (InterruptedException e) {deferredResult.setErrorResult("Error occurred");}}).start();return deferredResult;}
}

10. Spring MVC中的拦截器(Interceptor)是什么?如何使用?

  • 拦截器用于在请求处理前后进行处理,可以用于日志记录、权限验证等。
  • 需要实现HandlerInterceptor接口并在配置类中注册拦截器。
示例代码:
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;@Component
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 请求处理前逻辑System.out.println("Request intercepted: " + request.getRequestURI());return true; // 返回true继续处理,false则停止}
}import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate MyInterceptor myInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myInterceptor).addPathPatterns("/**"); // 拦截所有请求}
}

 


http://www.ppmy.cn/news/1517670.html

相关文章

HTML粒子爱心

目录 写在前面 完整代码 代码分析 系列文章 写在最后 写在前面 教你用HTML语言实现粒子爱心动画的效果。 HTML&#xff0c;全称为HyperText Markup Language&#xff0c;即超文本标记语言&#xff0c;是构建网页的基本markup语言&#xff0c;它通过一系列标签tags来定义…

时隔8个月!最新EI期刊目录更新!59本期刊被踢!

2024年8月EI期刊目录更新 重磅消息&#xff01;小编今天查到EI目录更新了&#xff0c;距离上一次更新&#xff08;2024年1月&#xff09;已经过去8个月之久&#xff01; 目录下载 关注公众号“Unionpub学术”&#xff0c;后台回复关键词“EI"&#xff0c;下载最新期刊目…

Android实现自定义方向盘-6mvvm传递数据

为了实现跨 Activity 的 ViewModel 数据共享&#xff0c;你可以使用一个不同的方法&#xff0c;比如使用 ViewModelProvider 与 Activity 范围的 ViewModel 配合 LiveData 进行数据传递&#xff0c;或者更简单地使用 SharedPreferences、Intent 或 Application 级别的单例模式来…

Django+vue自动化测试平台(29)--测试平台集成playwright录制pytest文件执行

需求背景 一、 系统目标与功能概述 脚本管理: 系统需要能够组织和存储所有通过playwright官方插件录制的脚本。这包括脚本的上传、编辑、删除和版本控制功能。 脚本执行: 用户应该能够在后台界面上查看所有可用的脚本&#xff0c;并能够通过简单的点击操作来启动特定脚本的执…

Unity URPShader支持多光源处理

//声明变体并且引用文件 #pragma shader_feature _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" //在数据结构体中声明需要使用的数据 struct Attributes {float4 posit…

C语言——字符函数、字符串函数和内存函数

目录 1.字符分类函数 2.字符转换函数 3.字符串函数 3.1strlen 函数 3.1.1 strlen函数的模拟实现 3.1.1.1第一种方法&#xff1a;计算器方法 3.1.1.2 第二种方法&#xff1a;指针-指针 3.1.1.3 第三种方法&#xff1a;递归 3.2 strcpy 函数 3.2.1 strcpy函数的模拟实现…

DevOps实现CI/CD实战(四)- 集成Harbor

1. Harbor介绍 前面在部署项目时&#xff0c;我们主要采用Jenkins推送jar包到指定服务器&#xff0c;再通过脚本命令让目标服务器对当前jar进行部署&#xff0c;这种方式在项目较多时&#xff0c;每个目标服务器都需要将jar包制作成自定义镜像再通过docker进行启动&#xff0c…

面试官让简述一下elasticsearch

当面试官要求你简述 Elasticsearch 时,你可以从以下几个方面来介绍: 1. 简介 Elasticsearch 是一个分布式的、RESTful 风格的搜索和分析引擎,基于 Lucene 构建。它能够处理海量数据,提供近乎实时的全文搜索功能,并且可以轻松扩展到数百台服务器及 PB 级结构化或非结构化…