【SpringBoot】笔记2

news2024/9/8 23:06:21

文章目录

    • 45、web实验-抽取公共页面
    • 46、web实验-遍历数据与页面bug修改
    • 47、视图解析-【源码分析】-视图解析器与视图[暂时没看]
    • 48、拦截器-登录检查与静态资源放行
    • 49、拦截器-【源码分析】-拦截器的执行时机和原理
    • 50、文件上传-单文件与多文件上传的使用
    • 51、文件上传-【源码流程】文件上传参数解析器
    • 52、错误处理-SpringBoot默认错误处理机制
    • 53、错误处理-【源码分析】底层组件功能分析【看了但是自己没有理解】
    • 54、错误处理-【源码流程】异常处理流程【没看,打算看文档的时候再一起看,现在看不懂】
    • 55、错误处理-【源码流程】几种异常处理原理【没看,打算看文档的时候再一起看,现在看不懂】
    • 56、原生组件注入-原生注解与Spring方式注入
      • 使用原生的注解
      • Spring方式注入
    • 57、原生组件注入-【源码分析】DispatcherServlet注入原理
    • 58、嵌入式Servlet容器-【源码分析】切换web服务器与定制化【没看】
      • 定制Servlet容器
    • 59、定制化原理-SpringBoot定制化组件的几种方式(小结)
      • 定制化的常见方式
      • 原理分析套路
    • 60、数据访问-数据库场景的自动配置分析与整合测试
      • 导入JDBC场景
      • 相关数据源配置类
      • 修改配置项
      • 单元测试数据源
    • 61、数据访问-自定义方式整合druid数据源
      • Druid是什么?
      • 自定义方式
    • 62、数据访问-druid数据源starter整合方式
    • 63、数据访问-整合MyBatis-配置版
      • 小结
    • 64、数据访问-整合MyBatis-注解配置混合版
    • 65、数据访问-整合MyBatisPlus操作数据库
      • MyBatisPlus是什么
    • 66、数据访问-CRUD实验-数据列表展示
    • 67、数据访问-CRUD实验-分页数据展示
    • 68、数据访问-CRUD实验-删除用户完成
    • 69、数据访问-准备阿里云Redis环境
    • 70、数据访问-Redis操作与统计小实验
    • 71、单元测试-JUnit5简介
    • 72、单元测试-常用测试注解
    • 73、单元测试-断言机制
      • 简单断言
      • 数组断言
      • 组合断言
      • 异常断言
      • 超时断言
      • 快速失败
    • 74、单元测试-前置条件
    • 75、单元测试-嵌套测试
    • 76、单元测试-参数化测试
      • 迁移指南
    • 77、指标监控-SpringBoot Actuator与Endpoint
      • 如何使用
    • 78、指标监控-常使用的端点及开启与禁用
      • 常使用的端点
      • Health Endpoint
      • Metrics Endpoint
      • 开启与禁用Endpoints
      • 暴露Endpoints
    • 79、指标监控-定制Endpoint
      • 定制 Health 信息
      • 定制info信息
      • 定制Metrics信息
      • 定制Endpoint
    • 80、指标监控-Boot Admin Server
    • 81、高级特性-Profile环境切换
      • @Profile条件装配功能
    • 82、高级特性-配置加载优先级
      • 外部化配置
    • 83、高级特性-自定义starter细节
      • starter启动原理
      • 自定义starter
    • 84、原理解析-SpringApplication创建初始化流程
      • SpringBoot启动过程
    • 85、原理解析-SpringBoot完整启动过程
    • 86、原理解析-自定义事件监听组件
    • 87、后会有期

45、web实验-抽取公共页面

官方文档 - Template Layout
中文文档
复习Template 语法,把链接放上来

  • 公共页面/templates/common.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"><!--注意要添加xmlns:th才能添加thymeleaf的标签-->
<head th:fragment="commonheader">
    <!--common-->
    
    ...
</head>
<body>
<!-- left side start-->
<div id="leftmenu" class="left-side sticky-left-side">
	...

    <div class="left-side-inner">
		...

        <!--sidebar nav start-->
        <ul class="nav nav-pills nav-stacked custom-nav">
            <li><a th:href="@{/main.html}"><i class="fa fa-home"></i> <span>Dashboard</span></a></li>
            ...
            <li class="menu-list nav-active"><a href="#"><i class="fa fa-th-list"></i> <span>Data Tables</span></a>
                <ul class="sub-menu-list">
                    <li><a th:href="@{/basic_table}"> Basic Table</a></li>
                    <li><a th:href="@{/dynamic_table}"> Advanced Table</a></li>
                    <li><a th:href="@{/responsive_table}"> Responsive Table</a></li>
                    <li><a th:href="@{/editable_table}"> Edit Table</a></li>
                </ul>
            </li>
            ...
        </ul>
        <!--sidebar nav end-->
    </div>
</div>
<!-- left side end-->


<!-- header section start-->
<div th:fragment="headermenu" class="header-section">

    <!--toggle button start-->
    <a class="toggle-btn"><i class="fa fa-bars"></i></a>
    <!--toggle button end-->
	...

</div>
<!-- header section end-->

<div id="commonscript">
    <!-- Placed js at the end of the document so the pages load faster -->
    <script th:src="@{/js/jquery-1.10.2.min.js}"></script>
    <script th:src="@{/js/jquery-ui-1.9.2.custom.min.js}"></script>
    <script th:src="@{/js/jquery-migrate-1.2.1.min.js}"></script>
    <script th:src="@{/js/bootstrap.min.js}"></script>
    <script th:src="@{/js/modernizr.min.js}"></script>
    <script th:src="@{/js/jquery.nicescroll.js}"></script>
    <!--common scripts for all pages-->
    <script th:src="@{/js/scripts.js}"></script>
</div>
</body>
</html>
  • /templates/table/basic_table.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
  <meta name="description" content="">
  <meta name="author" content="ThemeBucket">
  <link rel="shortcut icon" href="#" type="image/png">

  <title>Basic Table</title>
    <div th:include="common :: commonheader"> </div><!--将common.html的代码段 插进来-->
</head>

<body class="sticky-header">

<section>
<div th:replace="common :: #leftmenu"></div>
    
    <!-- main content start-->
    <div class="main-content" >

        <div th:replace="common :: headermenu"></div>
        ...
    </div>
    <!-- main content end-->
</section>

<!-- Placed js at the end of the document so the pages load faster -->
<div th:replace="common :: #commonscript"></div>


</body>
</html>

Difference between th:insert and th:replace (and th:include)

46、web实验-遍历数据与页面bug修改

控制层代码:

@GetMapping("/dynamic_table")
public String dynamic_table(Model model){
   
    //表格内容的遍历
    List<User> users = Arrays.asList(new User("zhangsan", "123456"),
                                     new User("lisi", "123444"),
                                     new User("haha", "aaaaa"),
                                     new User("hehe ", "aaddd"));
    model.addAttribute("users",users);

    return "table/dynamic_table";
}

页面代码:

<table class="display table table-bordered" id="hidden-table-info">
    <thead>
        <tr>
            <th>#</th>
            <th>用户名</th>
            <th>密码</th>
        </tr>
    </thead>
    <tbody>
        <tr class="gradeX" th:each="user,stats:${users}">
            <td th:text="${stats.count}">Trident</td>
            <td th:text="${user.userName}">Internet</td>
            <td >[[${user.password}]]</td>
        </tr>
    </tbody>
</table>

47、视图解析-【源码分析】-视图解析器与视图[暂时没看]

ctrl+b进入代码

视图解析原理流程

  1. 目标方法处理的过程中(阅读DispatcherServlet源码),所有数据都会被放在 ModelAndViewContainer 里面,其中包括数据和视图地址。
  2. 方法的参数是一个自定义类型对象(从请求参数中确定的),把他重新放在 ModelAndViewContainer
  3. 任何目标方法执行完成以后都会返回ModelAndView(数据和视图地址)。
  4. processDispatchResult()处理派发结果(页面改如何响应)
    • render(mv, request, response); 进行页面渲染逻辑
      • 根据方法的String返回值得到 View 对象【定义了页面的渲染逻辑】
      1. 所有的视图解析器尝试是否能根据当前返回值得到View对象
      2. 得到了 redirect:/main.html --> Thymeleaf new RedirectView()
      3. ContentNegotiationViewResolver 里面包含了下面所有的视图解析器,内部还是利用下面所有视图解析器得到视图对象。
      4. view.render(mv.getModelInternal(), request, response); 视图对象调用自定义的render进行页面渲染工作。
      • RedirectView 如何渲染【重定向到一个页面】
      • 获取目标url地址
      • response.sendRedirect(encodedURL);

视图解析
- 返回值以 forward: 开始: new InternalResourceView(forwardUrl); --> 转发request.getRequestDispatcher(path).forward(request, response);
- 返回值以 redirect: 开始: new RedirectView() --> render就是重定向
- 返回值是普通字符串:new ThymeleafView()—>


阅读源码:最好自己在IDE,打断点,且Debug模式运行实例,这样比较没那么沉闷。

48、拦截器-登录检查与静态资源放行

需要复习一些request,response,session等知识点,把复习链接放在这里

  1. 编写一个拦截器实现HandlerInterceptor接口

  2. 拦截器注册到容器中(实现WebMvcConfigureraddInterceptors()

  3. 指定拦截规则(注意,如果是拦截所有,静态资源也会被拦截】

编写一个实现HandlerInterceptor接口的拦截器:

package edu.gdpu.config;

import edu.gdpu.interceptor.LoginInterceptor;
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 AdminWebConfig implements WebMvcConfigurer {
   
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
   
        registry.addInterceptor(new LoginInterceptor()) //拦截器注册到容器中
        .addPathPatterns("/**") //所有请求都被拦截包括静态资源
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**");
//        ?静态资源这里还可以这样子写的,在/static/**全部发现,需要在application.yml配置
//        # 静态资源访问前缀
            //#spring:
            //#  mvc:
            //#    static-path-pattern: /res/**   麻烦的是css,js等静态资源都要加上/static才会被访问到

    }
}

拦截器注册到容器中 && 指定拦截规则:

@Configuration
public class AdminWebConfig implements WebMvcConfigurer{
   
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
   
        registry.addInterceptor(new LoginInterceptor())//拦截器注册到容器中
                .addPathPatterns("/**")  //所有请求都被拦截包括静态资源
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**",
                        "/js/**"); //放行的请求
}

49、拦截器-【源码分析】-拦截器的执行时机和原理

看了老师那么多源码解析,我都是懵懵懂懂的,就是没听,这次认真学习IDEA的debug调试,附上链接

  1. 根据当前请求,找到HandlerExecutionChain(可以处理请求的handler以及handler的所有 拦截器)
  2. 先来顺序执行 所有拦截器的 preHandle()方法。
    • 如果当前拦截器preHandle()返回为true。则执行下一个拦截器的preHandle()
    • 如果当前拦截器返回为false。直接倒序执行所有已经执行了的拦截器的 afterCompletion();
  3. 如果任何一个拦截器返回false,直接跳出不执行目标方法。
  4. 所有拦截器都返回true,才执行目标方法。
  5. 倒序执行所有拦截器的postHandle()方法。
  6. 前面的步骤有任何异常都会直接倒序触发 afterCompletion()
  7. 页面成功渲染完成以后,也会倒序触发 afterCompletion()
    在这里插入图片描述

DispatcherServlet中涉及到HandlerInterceptor的地方:

public class DispatcherServlet extends FrameworkServlet {
   
    
    ...
    
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
   
			ModelAndView mv = null;
			Exception dispatchException = null;

            	...
            
                //该方法内调用HandlerInterceptor的preHandle()
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
   
					return;
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            	...
                //该方法内调用HandlerInterceptor的postHandle()
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}			
        	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
   
            //该方法内调用HandlerInterceptor接口的afterCompletion方法
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
   
            //该方法内调用HandlerInterceptor接口的afterCompletion方法
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
   
			...
		}
	}

	private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, Exception ex) throws Exception {
   

		if (mappedHandler != null) {
   
            //该方法内调用HandlerInterceptor接口的afterCompletion方法
			mappedHandler.triggerAfterCompletion(request, response, ex);
		}
		throw ex;
	}

	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {
   

        ...

		if (mappedHandler != null) {
   
            //该方法内调用HandlerInterceptor接口的afterCompletion方法
			// Exception (if any) is already handled..
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}


}
public class HandlerExecutionChain {
   
    
    ...
    
	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
		for (int i = 0; i < this.interceptorList.size(); i++) {
   
			HandlerInterceptor interceptor = this.interceptorList.get(i);
            //HandlerInterceptor的preHandle方法
			if (!interceptor.preHandle(request, response, this.handler)) {
   
                
				triggerAfterCompletion(request, response, null);
				return false;
			}
			this.interceptorIndex = i;
		}
		return true;
	}
    
   	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
			throws Exception {
   

		for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
   
			HandlerInterceptor interceptor = this.interceptorList.get(i);
            
            //HandlerInterceptor接口的postHandle方法
			interceptor.postHandle(request, response, this.handler, mv);
		}
	}
    
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
   
		for (int i = this.interceptorIndex; i >= 0; i--) {
   
			HandlerInterceptor interceptor = this.interceptorList.get(i);
			try {
   
                //HandlerInterceptor接口的afterCompletion方法
				interceptor.afterCompletion(request, response, this.handler, ex);
			}
			catch (Throwable ex2) {
   
				logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
			}
		}
	}
    
    
} 
    

50、文件上传-单文件与多文件上传的使用

  • 页面代码/static/form/form_layouts.html
<form role="form" th:action="@{/upload}" method="post" enctype="multipart/form-data">
    <div class="form-group">
        <label for="exampleInputEmail1">邮箱</label>
        <input type="email" name="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
    </div>
    
    <div class="form-group">
        <label for="exampleInputPassword1">名字</label>
        <input type="text" name="username" class="form-control" id="exampleInputPassword1" placeholder="Password">
    </div>
    
    <div class="form-group">
        <label for="exampleInputFile">头像</label>
        <input type="file" name="headerImg" id="exampleInputFile">
    </div>
    
    <div class="form-group">
        <label for="exampleInputFile">生活照</label>
        <input type="file" name="photos" multiple>
    </div>
    
    <div class="checkbox">
        <label>
            <input type="checkbox"> Check me out
        </label>
    </div>
    <button type="submit" class="btn btn-primary">提交</button>
</form>

Html中label标签
input标签的multiple,多文件上传
复习request、response
POST提交表单时EnType设置问题

  • 控制层代码
@Slf4j
@Controller
public class FormTestController {
   

    @GetMapping("/form_layouts")
    public String form_layouts(){
   
        return "form/form_layouts";
    }

    @PostMapping("/upload")
    public String upload(@RequestParam("email") String email,
                         @RequestParam("username") String username,
                         @RequestPart("headerImg") MultipartFile headerImg,
                         @RequestPart("photos") MultipartFile[] photos) throws IOException {
   

        log.info("上传的信息:email={},username={},headerImg={},photos={}",
                 email,username,headerImg.getSize(),photos.length);

        if(!headerImg.isEmpty()){
   
            //保存到文件服务器,OSS服务器
            String originalFilename = headerImg.getOriginalFilename();
            headerImg.transferTo(new File("H:\\cache\\"+originalFilename));
        }

        if(photos.length > 0){
   
            for (MultipartFile photo : photos) {
   
                if(!photo.isEmpty()){
   
                    String originalFilename = photo.getOriginalFilename();
                    photo.transferTo(new File("H:\\cache\\"+originalFilename));
                }
            }
        }


        return "main";
    }
}

在这里插入图片描述

文件上传相关的配置类:

  • org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
  • org.springframework.boot.autoconfigure.web.servlet.MultipartProperties

文件大小相关配置项:

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB

51、文件上传-【源码流程】文件上传参数解析器

文件上传相关的自动配置类MultipartAutoConfiguration有创建文件上传参数解析器StandardServletMultipartResolver

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({
    Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class })
@ConditionalOnProperty(prefix = "spring.servlet.multipart", name = "enabled", matchIfMissing = true)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(MultipartProperties.class)
public class MultipartAutoConfiguration {
   

	private final MultipartProperties multipartProperties;

	public MultipartAutoConfiguration(MultipartProperties multipartProperties) {
   
		this.multipartProperties = multipartProperties;
	}

	@Bean
	@ConditionalOnMissingBean({
    MultipartConfigElement.class, CommonsMultipartResolver.class })
	public MultipartConfigElement multipartConfigElement() {
   
		return this.multipartProperties.createMultipartConfig();
	}

	@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
	@ConditionalOnMissingBean(MultipartResolver.class)
	public StandardServletMultipartResolver multipartResolver() {
   
        //配置好文件上传解析器
		StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
		multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
		return multipartResolver;
	}

}
//文件上传解析器
public class StandardServletMultipartResolver implements MultipartResolver {
   

	private boolean resolveLazily = false;

	public void setResolveLazily(boolean resolveLazily) {
   
		this.resolveLazily = resolveLazily;
	}


	@Override
	public boolean isMultipart(HttpServletRequest request) {
   
		return StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/");
	}

	@Override
	public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
   
		return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
	}

	@Override
	public void cleanupMultipart(MultipartHttpServletRequest request) {
   
		if (!(request instanceof AbstractMultipartHttpServletRequest) ||
				((AbstractMultipartHttpServletRequest) request).isResolved()) {
   
			// To be on the safe side: explicitly delete the parts,
			// but only actual file parts (for Resin compatibility)
			try {
   
				for (Part part : request.getParts()) {
   
					if (request.getFile(part.getName()) != null) {
   
						part.delete();
					}
				}
			}
			catch (Throwable ex) {
   
				LogFactory.getLog(getClass()).warn("Failed to perform cleanup of multipart items", ex);
			}
		}
	}

}
public class DispatcherServlet extends FrameworkServlet {
   
    
    @Nullable
	private MultipartResolver multipartResolver;
    
	private void initMultipartResolver(ApplicationContext context) {
   
		...
        
        //这个就是配置类配置的StandardServletMultipartResolver文件上传解析器
		this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
		...
	}
    
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;//最后finally的回收flag
		...
		try {
   
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
   
                //做预处理,如果有上传文件 就new StandardMultipartHttpServletRequest包装类
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);
				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				
                ...

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				...

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                
            }
            ....
            
		finally {
   

            ...
            
            if (multipartRequestParsed) {
   
                cleanupMultipart(processedRequest);
            }
		}
	}

	protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
   
		if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
   
            ...
			return this.multipartResolver.resolveMultipart(request);
            ...
		}
    }

	protected void cleanupMultipart(HttpServletRequest request) {
   
		if (this.multipartResolver != null) {
   
			MultipartHttpServletRequest multipartRequest =
					WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
			if (multipartRequest != null) {
   
				this.multipartResolver.cleanupMultipart(multipartRequest);
			}
		}
	}
}

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());跳到以下的类

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
		implements BeanFactoryAware, InitializingBean {
   
	@Override
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
   
		ModelAndView mav;
		...
		mav = invokeHandlerMethod(request, response, handlerMethod);
        ...
		return mav;
	}
    
    @Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
   

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
   
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			if (this.argumentResolvers != null) {
   //关注点
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			...
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			...

			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
   
			webRequest.requestCompleted();
		}
	}
    
}

this.argumentResolvers其中主角类RequestPartMethodArgumentResolver用来生成

public class ServletInvocableHandlerMethod e

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

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

相关文章

jQuery如何获取动态添加的元素

jQuery如何获取动态添加的元素 使用 on()方法 本质上使用了事件委派&#xff0c;将事件委派在父元素身上 自 jQuery 版本 1.7 起&#xff0c;on() 方法是 bind()、live() 和 delegate() 方法的新的替代品&#xff0c;但是由于on()方法必须有事件&#xff0c;没有事件时可选择de…

elasticsearch 官方优化建议

.一般建议 a.不要返回过大的结果集。这个建议对一般数据库都是适用的&#xff0c;如果要获取大量结果&#xff0c;可以使用search_after api&#xff0c;或者scroll &#xff08;新版本中已经不推荐&#xff09;。 b.避免大的文档。 2. 如何提高索引速度 a.使用批量请求。为了…

HCIP中期考试实验

考试需求 1、该拓扑为公司网络&#xff0c;其中包括公司总部、公司分部以及公司骨干网&#xff0c;不包含运营商公网部分。 2、设备名称均使用拓扑上名称改名&#xff0c;并且区分大小写。 3、整张拓扑均使用私网地址进行配置。 4、整张网络中&#xff0c;运行OSPF协议或者BGP…

Java -接口

接口 基本介绍 接口就是给出一些没有实现的方法&#xff0c;封装到一起&#xff0c;到某个类要使用的时候&#xff0c;再根据具体情况把这些方法写出来。 class 类名 implements 接口{自己属性;自己方法;必须实现的接口的抽象方法; // 只需要重写抽象方法即可 }接口中的方法…

【腾讯云 Cloud Studio 实战训练营】永不宕机的IDE,Coding Everywhere

【腾讯云 Cloud Studio 实战训练营】永不宕机的IDE&#xff0c;随时随地写代码&#xff01; 写在最前视频讲解&#xff1a;Cloud Studio活动简介何为腾讯云 Cloud Studio?Cloud Studio简介免费试用&#xff0c;上手无忧Cloud Studio 特点及优势云端开发多种预制环境可选metawo…

C# 定时器改进版

一、概述 前不久写了一篇名为 “C# 定时器封装版” 的帖子&#xff0c;它是用的定时器 事件订阅 的方式完成的&#xff0c;虽然可以实现需求&#xff0c;但是它有个缺点&#xff0c;就是定时器的执行的间隔时间只能用固定的时间&#xff0c;假设你想每个事件有自己的单独间隔…

HEVC 速率控制(码控)介绍

视频编码速率控制 速率控制&#xff1a; 通过选择一系列编码参数&#xff0c;使得视频编码后的比特率满足所有需要的速率限制&#xff0c;并且使得编码失真尽量小。速率控制属于率失真优化的范畴&#xff0c;速率控制算法的重点是确定与速率相关的量化参数&#xff08;Quantiz…

医学影像PACS系统源码:多功能服务器和阅片系统

PACS系统是以最新的IT技术为基础&#xff0c;遵循医疗卫生行业IHE/DICOM3.0和HL7标准&#xff0c;开发的多功能服务器和阅片系统。通过简单高性能的阅片功能&#xff0c;支持繁忙时的影像诊断业务&#xff0c;拥有保存影像的院内Web传输及离线影像等功能&#xff0c;同时具有备…

Python中的列表怎么排序

目录 Python中的列表是什么 python怎么给列表排序 给列表排序需要注意什么 总结 Python中的列表是什么 在Python中&#xff0c;列表&#xff08;List&#xff09;是一种有序且可变的数据类型。它允许存储多个元素&#xff0c;并且可以根据需要进行修改。 列表使用方括号&…

自定义类型讲解

&#x1f495;痛苦难道是白忍受的吗&#xff1f;&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;自定义类型讲解 一.结构体 定义&#xff1a; 数组&#xff1a;多组相同类型元素的集合 结构体&#xff1a;多组不同类型元素的集合-->管理多组不同类型数据…

大家做性能测试都用什么工具

在进行测试时&#xff0c;选择适合的测试工具至关重要&#xff0c;因为优秀的测试工具能够显著提高工作效率。对于性能测试和自动化测试而言&#xff0c;大多数人会选择传统的JMeter等工具&#xff0c;然而这些工具存在学习成本高、使用门槛高的问题。 因此&#xff0c;我在这…

微信小程序开发学习之--地图绘制行政区域图

不知道大家有没有感觉就是在做微信小程序地图功能时刚刚接触时候真的感觉好迷茫呀&#xff0c;文档看不懂&#xff0c;资料找不到&#xff0c;就很难受呀&#xff0c;比如我现在的功能就想想绘制出一个区域的轮廓图&#xff0c;主要是为了显眼&#xff0c;效果图如下&#xff1…

官方Office 技巧免费学习平台-WPS学堂

WPS学堂是WPS官方Office 技巧免费学习平台&#xff0c;目前网站累计上线 3000个免费教学视频图文&#xff0c;包含WPS表格(Excel)、WPS文字&#xff08;Word&#xff09;、WPS演示(PPT)的操作技巧及新手入门系列课视频&#xff0c;而且教学视频都可以直接在线学习&#xff0c;不…

14.2 【Linux】软件磁盘阵列(Software RAID)

14.2.1 什么是 RAID 磁盘阵列全名是“ Redundant Arrays of Inexpensive Disks, RAID ”&#xff0c;英翻中的意思是&#xff1a;容错式廉价磁盘阵列。 RAID 可以通过一个技术&#xff08;软件或硬件&#xff09;&#xff0c;将多个较小的磁盘整合成为一个较大的磁盘设备&…

图数据库Neo4j学习四——Spring Data NEO

1配置 1.1Maven依赖 <!--neo4j --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-neo4j</artifactId> </dependency>1.2yml配置 spring:data:neo4j:uri: bolt://localhost:76…

【机器学习】Cost Function for Logistic Regression

Cost Function for Logistic Regression 1. 平方差能否用于逻辑回归&#xff1f;2. 逻辑损失函数loss3. 损失函数cost附录 导入所需的库 import numpy as np %matplotlib widget import matplotlib.pyplot as plt from plt_logistic_loss import plt_logistic_cost, plt_two_…

利用易查分制作分班查询系统,怎么导入数据?

暑假过半&#xff0c;新学期即将到来&#xff0c;这对学校来说是一个重要的时刻。新学期的开始意味着学校将面临新生入学和老生升入高年级的情况&#xff0c;这就需要进行分班工作的安排。分班工作是一项繁琐而关键的任务&#xff0c;它直接关系到学生们在新学期中的班级和同学…

【Linux进程篇】进程概念(1)

【Linux进程篇】进程概念&#xff08;1&#xff09; 目录 【Linux进程篇】进程概念&#xff08;1&#xff09;进程基本概念描述进程-PCBtask_struct-PCB的一种task_ struct内容分类 组织进程查看进程通过系统调用获取进程标示符通过系统调用创建进程——fork初识 作者&#xff…

SpringMVC源码分析 —— 拦截器是何时调用的

SpringMVC源码分析&#xff0c;拦截器是何时、以什么方式调用的&#xff1f;本文将进行详细说明 环境准备 springboot 2.3.7.RELEASE 笔者创建一个springboot的web项目&#xff0c;使用的springboot的版本是2.3.7.RELEASE 对应的spring-web版本是5.2.12.RELEASE 下面将对上面…

【NLP-新工具】语音转文本与OpenAI的用途

一、说明 OpenAI最近2022发布了一个名为Whisper的新语音识别模型。与DALLE-2和GPT-3不同&#xff0c;Whisper是一个免费的开源模型。它的主要功能就是将语音翻译成文本。本文将介绍如何使用这个重要应用库。 二、 Whisper概念 2.1 Whisper是啥&#xff1f; Whisper 是一种自动…