Springboot学习-day17

news2024/12/28 20:27:41

Springboot学习-day17

1. AOP

AOP (Aspect Orient Programming),直译过来就是 面向切面编程,AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。

面向切面编程,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术

AOP 采取横向抽取机制(动态代理),取代了传统纵向继承机制的重复性代码,其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。

主要作用是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少对业务代码的侵入,增强代码的可读性和可维护性。

简单的说,AOP 的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。

在这里插入图片描述

Spring AOP的术语

名称说明
Joinpoint(连接点)指可以被拦截到的点,在Spring中,指可以被动态代理拦截目标类的方法
Pointcut(切入点)指要对哪些Joinpoint进行拦截,即被拦截的连接点
Advice(通知)指拦截到Joinpoint之后要做的事情,即对切入点增强的内容
Target(目标)指代理的目标对象
Weaving(植入)指把增强代码应用到目标上,生成代理对象的过程
Proxy(代理)指生成的代理对象
Aspect(切面)切入点和通知的结合

AOP的通知分类

通知说明
before(前置通知)通知方法在目标方法调用之前执行
after(后置通知)通知方法在目标方法返回或异常后调用
after-returning(返回后通知)通知方法会在目标方法返回后调用
after-throwing(抛出异常通知)通知方法会在目标方法抛出异常后调用
around(环绕通知)通知方法会将目标方法封装起来

创建一个控制类EasyAController

@RestController
public class EasyAController {

    //连接点
    @RequestMapping("testA")
    public String testA(){
        System.out.println("testA方法------");
        return "EasyA method";
    }

}

创建一个切点,并实现通知

@Aspect
@Component
public class AOPObj {

    //定义切点
    //execution(* cn.xxx.dao..*(..))
    @Pointcut("execution(* com.easy.controller.EasyAController.testA(..))")
    public void pointCutTestA(){
        //切点
    }

    //通过动态代理来实现的面向切面的思想,以此在不修改源代码的情况下对已有功能进行增强
    @Before("pointCutTestA()")
    public void before(){
        System.out.println("前置通知----------");
    }

    @After("pointCutTestA()")
    public void after(){
        System.out.println("后置通知----------");
    }

    @AfterThrowing("pointCutTestA()")
    public void afterThrowing(){
        System.out.println("异常后通知----------");
    }

    @AfterReturning("pointCutTestA()")
    public void afterReturning(){
        System.out.println("返回后通知----------");
    }

}

启动Spring项目,访问testA,可以看到如下图所示的输出

在这里插入图片描述

在控制类EasyAController的testA中创造一个异常

@RestController
public class EasyAController {

    @RequestMapping("testA")
    public String testA(){
        System.out.println("testA方法------");
        int a = 12 / 0;
        return "EasyA method";
    }
}

重启Spring项目,访问testA,可以看到如下输出

在这里插入图片描述

以上定义切点注解的@Pointcut中的参数是切点表达式

execution类型的语法如下所示

execution(modifier? ret-type declaring-type?name-pattern(param-pattern) throws-pattern?)
  • modifier:匹配修饰符,public, private 等,省略时匹配任意修饰符

  • ret-type:匹配返回类型,使用 * 匹配任意类型

  • declaring-type:匹配目标类,省略时匹配任意类型

    • … 匹配包及其子包的所有类
  • name-pattern:匹配方法名称,使用 * 表示通配符

    • 匹配任意方法
    • set* 匹配名称以 set 开头的方法
  • param-pattern:匹配参数类型和数量

    • () 匹配没有参数的方法
    • (…) 匹配有任意数量参数的方法
    • (*) 匹配有一个任意类型参数的方法
    • (*,String) 匹配有两个参数的方法,并且第一个为任意类型,第二个为 String 类型
  • throws-pattern:匹配抛出异常类型,省略时匹配任意类型

使用示例

// 匹配public方法
execution(public * *(..))

// 匹配名称以set开头的方法
execution(* set*(..))

// 匹配AccountService接口或类的方法
execution(* com.xyz.service.AccountService.*(..))

// 匹配service包及其子包的类或接口
execution(* com.xyz.service..*(..))

参考: https://blog.csdn.net/weixin_43793874/article/details/124753521

2. 代理模式

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。

代理模式的目的

1.功能增强:通过代理业务对原有业务进行增强

2.控制访问:通过代理对象的方式间接的访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性

2.1 静态代理

简单来说代理模式就是将被代理类包装起来然后重新实现相同的方法,并且调用原来方法的同时可以在方法前后添加一个新的处理。而这种包装可以使用继承或者组合来使用。当我们调用的时候需要使用的是代理类的对象来调用而不是原来的被代理对象。

静态代理的特点

  • 1.代理类是手动实现的,需要自己去创建一个类
  • 2.代理类所代理的目标类是固定的

静态代理可以通过继承或实现代理类的接口来实现

2.1.1 通过继承实现静态代理

通过继承被代理对象,重写被代理方法,可以对其进行代理。
优点:被代理类无需实现接口
缺点:只能代理这个类,要想代理其他类,要想代理其他类需要写新的代理方法。
cglib动态代理就是采用这种方式对类进行代理。不过类是由cglib帮我们在内存中动态生成的。

public class Tank{
    public void move() {
        System.out.println("Tank moving cla....");
    }

    public static void main(String[] args) {
        new ProxyTank().move();
    }
}
class ProxyTank extends Tank{
    @Override
    public void move() {
        System.out.println("方法执行前...");
        super.move();
        System.out.println("方法执行后...");
    }
}
2.1.2 通过组合实现静态代理

定义一个被代理类需要和代理类都需要实现的接口。(接口在这里的目的就是起一个规范作用保证被代理类和代理类都实现了接口中的方法)。代理类需要将该接口作为属性,实例化时需要传入该接口的对象,这样该代理类就可以实现代理所有实现这个接口的类了。
优点:可以代理所有实现接口的类。
缺点:被代理的类必须实现接口。
JDK动态代理就是采用的这种方式实现的。同样的代理类是由JDK自动帮我们在内存生成的。

public class Tank implements Movable{
    @Override
    public void move() {
        System.out.println("Tank moving cla....");
    }

    public static void main(String[] args) {
        Tank tank = new Tank();
        new LogProxy(tank).move();
    }
}

class LogProxy implements Movable{
    private Movable movable;
    public LogProxy(Movable movable) {
        this.movable = movable;
    }
    @Override
    public void move() {
        System.out.println("方法执行前....");
        movable.move();
        System.out.println("方法执行后....");
    }
}
interface Movable {
    void move();
}

静态代理存在的问题

1.当目标类增多时,代理类也需要增多,导致代理类的关系不便

2.当接口当中的功能增多或者修改,都会影响实体类,违反开闭原则(程序对访问开放,对修改关闭)

2.2 动态代理

动态代理其实本质还是 将被代理类包装一层,生成一个具有新的相同功能的代理类。
但是与静态代理不同的是,这个代理类我们自己定义的。而动态代理这个代理类是根据我们的提示动态生成的。

相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。

实现动态代理的方式:

1.JDK动态代理

2.CGLIB动态代理

2.2.1 JDK动态代理

通过java提供的Proxy类帮我们创建代理对象。
优点:可以生成所有实现接口的代理对象
缺点:JDK反射生成代理必须面向接口, 这是由Proxy的内部实现决定的。生成代理的方法中你必须指定实现类的接口,它根据这个接口来实现代理类生成的所实现的接口。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 使用jdk的动态代理
 */
public class Tank implements Movable{
    @Override
    public void move() {
        System.out.println("Tank moving cla....");
    }

    public static void main(String[] args) {
        Tank tank = new Tank();
        // reflection 反射 通过二进制字节码分析类的属性和方法

        //newProxyInstance: 创建代理对象
        // 参数一: 被代理类对象
        // 参数二:接口类对象  被代理对象所实现的接口
        // 参数三:调用处理器。 被调用对象的那个方法被调用后该如何处理
        Movable o = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader()
                ,new Class[]{Movable.class}
                ,new LogProxy(tank));
        o.move();
    }
}

class LogProxy implements InvocationHandler {
    private Movable movable;

    public LogProxy(Movable movable) {
        this.movable = movable;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法:"+method.getName()+"()执行前");
        Object invoke = method.invoke(movable, args);  // 此处相当于 movable.move()
        System.out.println("方法:"+method.getName()+"()执行后");
        return invoke;
    }
}

interface Movable {
    void move();
}

2.2.2 CGLIB动态代理

CGLib(Code Generate Library) 与JDK动态代理不同的是,cglib生成代理是被代理对象的子类。因此它拥有继承方法实现静态代理的优点:不需要被代理对象实现某个接口。
缺点:不能给final类生成代理,因为final类无法拥有子类。

使用cglib生成代理类也很简单,只要指定父类和回调方法即可
首先需要引入依赖

<dependency>
     <groupId>cglib</groupId>
     <artifactId>cglib</artifactId>
     <version>3.2.12</version>
 </dependency>
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer(); // 增强者
        enhancer.setSuperclass(Tank.class); // 指定父类
        enhancer.setCallback(new TimeMethodInterceptor()); // 当被代理对象的方法调用的时候会调用 该对象的intercept
        Tank tank = (Tank)enhancer.create();  // 动态代理的生成
        tank.move();  // 生成之后会调用
    }
}

class TimeMethodInterceptor implements MethodInterceptor{
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("生成的类名"+o.getClass().getName());
        System.out.println("生成的类的父类"+o.getClass().getSuperclass().getName());
        System.out.println("方法执行前,被代理的方法"+method.getName());
        Object result = null;
        result = methodProxy.invokeSuper(o, objects);
        System.out.println("方法执行后,被代理的方法"+method.getName());
        return result;
    }
}
class Tank{
    public void move(){
        System.out.println("Tank moving clacla....");
    }
}

参考:https://blog.csdn.net/Passer_hua/article/details/122617628

3. SpringMVC

Spring MVC 使用 MVC 架构模式的思想,将 Web 应用进行职责解构,把一个复杂的 Web 应用划分成模型(Model)、控制器(Contorller)以及视图(View)三层,有效地简化了 Web 应用的开发,降低了出错风险,同时也方便了开发人员之间的分工配合

3.1 @Controller @RestController

@Controller 注解可以将一个普通的 Java 类标识成控制器(Controller)类

RestController和@Controller的区别
RestController注解相当于@ResponseBody + @Controller合在一起的作用。

(1)如果只是使用@RestController注解Controller层,那么Controller层中的方法无法返回到 jsp 页面,配置的视图解析器InternalResourceViewResolver不起作用,返回的数据就是return语句里面的内容。

例如:本来应该到success.jsp页面的,则其显示success

(2)如果需要返回到指定页面,则需要用@Controller 配合视图解析器lnternalResourceViewResolver才行。

(3)如果需要返回JSON、XML或者自定义mediaType到页面,则需要在对应的方法上加上ResponseBody注解。

3.2 @RequestMapping

@RequestMapping通常被标注在控制器方法上,负责将请求与处理请求的控制器方法关联起来,建立映射关系。

路径映射: 当一个用户访问一个URL的时候,将用户的请求对应到程序中 某个类的某个方法 的过程就叫映射。

@RequestMapping 既可以修饰类,也可以修饰方法。当修饰类和方法时,访问的地址是类路径+方法路径,如果只使用方法路径去访问会报错。

@RequestMapping有五个属性

value:设置控制器方法的请求映射地址

name:方法的注释

method:设置请求方式,如果没有设置则可以处理所有类型的请求

params:用于指定请求中的参数,只有当请求中携带了符合条件的参数时,控制器方法才会对该请求进行处理。

headers:headers 属性用于设置请求中请求头信息,只有当请求中携带指定的请求头信息时,控制器方法才会处理该请求。

3.3 @PathVariable

@PathVariable 注解的作用是将 URL 中的路径参数(Path parameters)绑定到方法的参数上。在 Spring MVC 中,我们可以通过在控制器(Controller)的方法参数上添加 @PathVariable 注解来获取 URL 中的变量值,并将其作为方法参数的值进行使用。

@GetMapping("/users/{id}")
public String getUserInfo(@PathVariable("id") Long userId) {
    // 处理 userId 的逻辑
    return "User ID: " + userId;
}

总结来说,@PathVariable 注解的作用是用于获取 URL 中的路径参数,并将其绑定到方法的参数上,方便在方法中使用。

3.4 @Requestparam

RequestParam 是 Spring MVC 中用来处理 HTTP 请求参数的注解,主要用于绑定请求中的查询参数或表单字段到控制器方法的参数。

@RequestMapping("paramB")
public Map paramB(@RequestParam Map params){
    return params;
}

3.5 @Get/Post/Put/DeleteMapping

  • @GetMapping-------->通常对应查询操作
  • @PostMapping-------->通常对应新增操作
  • @PutMapping------------>通常对应修改操作
  • @DeleteMapping--------->通常对应删除操作

其实是对RequestMapping的一种请求方式的缩写

如@GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写

@RequestMapping(value = "/findAllUser",method = RequestMethod.GET)等于@GetMapping(value = "/findAllUser")

@RequestMapping(value = "/addUser",method = RequestMethod.POST)等于@PostMapping(value = "/addUser")    

@RequestMapping(value = "/updateUser",method = RequestMethod.PUT)等于@PutMapping(value = "/updateUser")

@RequestMapping(value = "/deleteUser",method = RequestMethod.DELETE)等于@DeleteMapping(value = "/deleteUser")
@RestController
//@ControllerAdvice
//@RequestMapping("staff")
public class StaffController {
    @GetMapping("staff")
    public CommonResult getList(Staff staff){
        List<Staff> list = null;
        System.out.println("获取数据");
        return CommonResult.success(list);
    }

    @PostMapping("staff")
    public CommonResult addStaff(Staff staff){

        System.out.println("新增数据");
        return CommonResult.success(staff);
    }

    @DeleteMapping("staff/{id}")
    public CommonResult delStaff(@PathVariable int id){
        System.out.println("删除数据" + id);
        return CommonResult.success();
    }

    @PutMapping("staff")
    public CommonResult editStaff(Staff staff){
        System.out.println("编辑数据");
        return CommonResult.success();
    }
}

3.6 请求转发 重定向

转发:同一个服务器中不同的服务进行转发 forward

浏览器发送了一个请求 可以转发到项目中受保护的资源WEB-INF

转发是request对象执行forward方法

@Controller
public class EasyEController{

    @RequestMapping("methodA")
    public String methodA(){
        System.out.println("------methodA");
        return "forward:/methodB";
    }

    @RequestMapping("methodB")
    @ResponseBody
    public String methodB(){
        System.out.println("------methodB");
        return "this is methodB";
    }
}

访问methodA页面时,页面显示this is methodB但地址栏的url地址没有改变,还是methodA

重定向:可以在不同的服务之间进行跳转

浏览器发送了多次请求

通过response对象通知浏览器,重新访问,执行的是redirect方法

@Controller
public class EasyEController{

    public String methodA(){
        System.out.println("------methodA");
        return "redirect:/methodB";
    }

    @RequestMapping("methodB")
    @ResponseBody
    public String methodB(){
        System.out.println("------methodB");
        return "this is methodB";
    }
}

访问methodA页面时,页面显示this is methodB,地址栏的url地址也变为methodB

3.6 SpirngMVC的运行原理

1.用户通过浏览器发起一个 HTTP 请求,该请求会被 DispatcherServlet(前端控制器)拦截

2.DispatcherServlet 调用 HandlerMapping(处理器映射器)找到具体的处理器(Handler)及拦截器

3.HandlerMapping将Handler以 HandlerExecutionChain 执行链的形式返回给 DispatcherServlet

4.DispatcherServlet 将执行链返回的 Handler 信息发送给 HandlerAdapter(处理器适配器)

5.HandlerAdapter 根据 Handler 信息找到并执行相应的 Handler(即 Controller 控制器)对请求进行处理

6.Handler 执行完毕后会返回给 HandlerAdapter 一个 ModelAndView 对象(Spring MVC 的底层对象,包括 Model 数据模型和 View 视图信息)

7.HandlerAdapter 接收到 ModelAndView 对象后,将其返回给 DispatcherServlet

8.DispatcherServlet 接收到 ModelAndView 对象后,会请求 ViewResolver(视图解析器)对视图进行解析

9.ViewResolver 解析完成后,会将 View 视图并返回给 DispatcherServlet

10.DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图)

11.视图负责将结果显示到浏览器(客户端)

在这里插入图片描述

3.7 SpringMVC的异常处理机制

Spring MVC 提供了一个名为 HandlerExceptionResolver 的异常处理器接口,它可以对控制器方法执行过程中出现的各种异常进行处理。

Spring MVC 允许我们在控制器类(Controller 类)中通过 @ExceptionHandler 注解来定义一个处理异常的方法,以实现对控制器类内发生异常的处理。

@ExceptionHandler 注解中包含了一个 value 属性,我们可以通过该属性来声明一个指定的异常。如果在程序运行过程中,这个 Controller 类中的方法发生了这个指定的异常,那么 ExceptionHandlerExceptionResolver 就会调用这个 @ExceptionHandler 方法对异常进行处理。

定义在某个控制器类中的 @ExceptionHandler 方法只在当前的控制器中有效,它只能处理其所在控制器类中发生的异常。

@ExceptionHandler 方法的优先级–指定异常类型最精确的

@ExceptionHandler(value = {Exception.class})
public CommonResult exh(){
    return CommonResult.success(200, "网页被外星人带走了");
}

全局异常处理,使用@ControllerAdvice注释来修饰控制类,当其他类出现异常时,也会调用该类中被@ExceptionHandler修饰的处理异常的方法

4. 拦截器

在系统中,经常需要在处理用户请求之前和之后执行一些行为,例如检测用户的权限,或者将请求的信息记录到日志中,即平时所说的“权限检测”及“日志记录”。当然不仅仅这些,所以需要一种机制,拦截用户的请求,在请求的前后添加处理逻辑。

Spring MVC 提供了 Interceptor 拦截器机制,用于请求的预处理和后处理。

要想自定义拦截器,必须实现HandlerInterceptor接口

package com.qzcsbj.interceptor;
 
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
 
public class HandlerInterceptorDemo1 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行preHandle方法了。。。");
        return true; // true表示放行,继续后续的操作
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("执行postHandle方法了。。。");
    }
 
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("执行afterCompletion方法了。。。");
    }
}

控制器

package com.qzcsbj.controller;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class TestController {
 
    @RequestMapping("/testInterceptor")
    public String testInterceptor(){
        System.out.println("控制器中的方法执行了。。。");
        return "success";
    }
}

springmvc.xml中配置拦截器

<!-- 配置拦截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <!--拦截的资源URI-->
        <mvc:mapping path="/**"/>
        <bean id="handlerInterceptorDemo1"
              class="com.qzcsbj.interceptor.HandlerInterceptorDemo1">
        </bean>
    </mvc:interceptor>
</mvc:interceptors>

测试

er;

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

@Controller
public class TestController {

@RequestMapping("/testInterceptor")
public String testInterceptor(){
    System.out.println("控制器中的方法执行了。。。");
    return "success";
}

}


springmvc.xml中配置拦截器

```xml
<!-- 配置拦截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <!--拦截的资源URI-->
        <mvc:mapping path="/**"/>
        <bean id="handlerInterceptorDemo1"
              class="com.qzcsbj.interceptor.HandlerInterceptorDemo1">
        </bean>
    </mvc:interceptor>
</mvc:interceptors>

测试

在这里插入图片描述

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

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

相关文章

大模型学习路线图:从入门到精通,我说这是全网详细的,谁赞成谁反对?

随着人工智能技术的飞速发展&#xff0c;大模型&#xff08;Large-Scale Models&#xff09;已经成为推动自然语言处理&#xff08;NLP&#xff09;、计算机视觉&#xff08;CV&#xff09;等领域进步的关键因素。本文将为您详细介绍从零开始学习大模型直至成为专家的全过程&am…

吴恩达机器学习WEEK1

COURSE 1 WEEK 1 机器学习的应用 当我们有一个目标&#xff0c;不知道如何显示地写出来一个程序时&#xff0c;例如自动驾驶等&#xff0c;这时候就需要制定某些规则&#xff0c;让计算机自己去学习&#xff0c;即机器学习 机器学习就是沿用人脑学习的过程&#xff0c;逐步对…

目录文件;链接文件;函数stat/lstat

1.目录文件的操作&#xff1a; 1. mkdir int mkdir(const char *pathname, mode_t mode); 功能: 创建目录 参数&#xff1a; pathname:目录文件的路径 mode:目录文件的权限 返回值&#xff1a; …

6581 Number Triangle

这个问题可以通过动态规划来解决。我们可以从三角形的顶部开始&#xff0c;然后逐行向下计算每个位置的最大和。对于三角形中的每个位置&#xff0c;我们可以选择从其上方或左上方的位置移动到该位置&#xff0c;所以该位置的最大和就是其上方或左上方位置的最大和加上该位置的…

动态规划---观察优化枚举(股票系列问题)

121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09; public class Code01_Stock1 {public static int maxProfit(int[] prices) {int ans 0;for (int i 1, min prices[0]; i < prices.length; i) {// min : 0...i范围上的最小值min Math.min(min, prices…

Android图像显示SurfaceFlinger总结

1 介绍 1.1 框架中位置 ​​ 上图为Android的图形显示系统框架图。 首先上层应用通过ViewRoot的scheduleTraversals函数发起绘制任务&#xff0c;并通过HWUI调用OpenGL接口将绘制数据传递给GPU处理&#xff1b;SF会接收所有应用更新的绘制数据&#xff0c;并根据Z-Order、透明…

实现一个自定义前端脚手架

一、背景 什么前端脚手架&#xff1f; 前端脚手架是一种工具&#xff0c;用于快速搭建前端项目的基础结构&#xff0c;提供了一套约定和标准&#xff0c;帮助开发人员快速启动项目开发。常见的前端脚手架包括Create React App、Vue CLI、Angular CLI、nestjs/cli等。 我为什么…

C语言——二维数组和字符数组

二维数组 二维数组本质上是一个行列式的组合&#xff0c;也就是二维数组是有行和列两部分构成。二维数组数据是通过行列进行解读。 定义形式&#xff1a; 类型&#xff08;说明符&#xff09; 数组名[行数&#xff08;常量表达式1&#xff09;][列数&#xff08;常量表达式…

nginx负载均衡、java、tomcat装包

一、nginx 七层负载均衡 1、七层负载均衡基础配置 2、负载均衡状态 [rootserver]# vim /usr/local/nginx/conf/nginx.confworker_processes 1;event {worker_connections 1024&#xff1b;}http { # 七层负载均衡支持http、ftp协议include mime.types;default_type app…

T3学员领取资料通知0803

T3学员领取资料通知0803 各位学员∶本周MF系列VBA技术资料增加671-680讲&#xff0c;T3学员看到通知后请免费领取,领取时间8月2日晚上19:00-8月3日12:00。本次增加内容&#xff1a; MF671:Shell命令输出计算机的详细信息 MF672:Shell命令输出网络配置信息 MF673:解锁和启用…

QtQuick Text-文本省略

效果 import QtQuickColumn{spacing: 20Text{width: 200text: qsTr("1使文本在单行中对于超出部分不要进行省略")font.pointSize: 20}Text{width: 200elide: Text.ElideLefttext: qsTr("2使文本在单行中对于超出部分从左边进行省略")font.pointSize: 20}Te…

【协作提效 Go - gin ! swagger】

什么是swagger Swagger 是一个用于设计、构建、记录和使用 RESTful Web 服务的工具集。它的主要作用包括&#xff1a; API 文档生成&#xff1a;Swagger 可以自动生成详细的 API 文档&#xff0c;包括每个端点的请求和响应格式、参数、状态码等。这使得开发者和用户可以轻松理…

【香橙派系列教程】(五)Linux的热拔插UDEV机制

【五】Linux的热拔插UDEV机制 在上一篇中我们发现&#xff0c;当手机接入开发板时&#xff0c;系统并不认识&#xff0c;当我们在/etc/udev目录下创建一个规则后&#xff0c;就可以通过adb访问到手机了&#xff0c;这里到底是怎么回事&#xff1f; 文章目录 【五】Linux的热拔插…

【Python】数据类型(上)

本篇文章将讲解&#xff1a; &#xff08;1&#xff09;整型 &#xff08;2&#xff09;布尔类型 一&#xff1a;整型 整型其实就是十进制整数的统称&#xff0c;例如&#xff1a;1 666 都属于整型。 &#xff08;1&#xff09;定义 num11 age45 &#xff08…

【网络】网络入门(第一篇)

网络入门可以从多个方面开始&#xff0c;以下是一个基本的网络入门指南&#xff0c;涵盖了网络的基本概念、网络类型、网络协议、网络拓扑、网络设备以及网络地址等方面。 一、网络基本概念 计算机网络&#xff1a;将多个计算机系统和设备连接在一起&#xff0c;以实现资源共…

Opencv学习-LUT函数

这个函数大概意思根据自己设定的查找表&#xff0c;改变原本像素点值 例如&#xff1a;我们想将一张图片灰度为0-100的像素的灰度变成0,101-200的变成100,201-255的变成255。我们就可已建立如下的一张表格 ​​​​​​​ ​​​​​​​ ​​​​​​​…

Studying-代码随想录训练营day52| 101.孤岛的总面积、102沉没孤岛、103.水流问题、104.建造最大岛屿

第52天&#xff0c;图论part03&#xff0c;岛屿问题继续&#xff01;&#xff01;&#x1f4aa;(ง •_•)ง&#xff0c;编程语言&#xff1a;C 目录 101.孤岛的总面积 102沉没孤岛 103.水流问题 104.建造最大岛屿 101.孤岛的总面积 文档讲解&#xff1a;手撕孤岛的总…

昇思25天学习打卡营第XX天|SSD目标检测

感觉目标检测还是yolo相对最火&#xff1f;ssd有点老了可以更新下 SSD算法数学描述 SSD算法使用卷积神经网络&#xff08;CNN&#xff09;进行特征提取&#xff0c;并通过多尺度的特征图进行目标检测。设 ( C ) 为CNN输出的特征层数量&#xff0c;( F_i ) 为第 ( i ) 层特征…

【Postman的接口测试工具介绍】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 👉Postman接口.👋 👉Postman是一款常用的API开发测试工具,它提…

Harmony学习(四)(应用程序框架基础)

1.应该程序框架基础 多Module设计机制 模块化开发&#xff1a;一个应用多个功能&#xff0c;每个功能可作为一个模块&#xff0c;Module中可以包含源代码、资源文件、第三方库、配置文件等&#xff0c;每一个Module可以独立编译&#xff0c;实现特定的功能支持多设备&#xf…