SpringBoot Web开发(SpringMVC)
SpringBoot Web开发(SpringMVC)
MVC 核心组件和调用流程
Spring MVC与许多其他Web框架一样,是围绕前端控制器模式设计的,其中中央
ServletDispatcherServlet做整体请求处理调度!
.
除了DispatcherServletSpringMVC还会提供其他特殊的组件协作完成请求处理和响应呈现。
SpringMVC 处理请求流程

SpringMVC 涉及的组件理解
-
DispatcherServlet:SpringMVC提供,我们需要使用web.xml配置使其生效,它是整个流程处理的核心,所有请求都经过它的处理和分发![ CEO ] -
HandlerMapping:SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它内部缓存handler(controller方法)和handler访问路径数据,被DispatcherServlet调用,用于查找路径对应的handler![秘书] -
HandlerAdapter:SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它可以处理请求参数和处理响应数据数据,每次DispatcherServlet都是通过handlerAdapter间接调用handler,他是handler和DispatcherServlet之间的适配器![经理] -
Handler : handler又称处理器,他是Controller类内部的方法简称,是由我们自己定义,用来接收参数,向后调用业务,最终返回响应结果![打工人] -
ViewResovler : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效!视图解析器主要作用简化模版视图页面查找的,但是需要注意,前后端分离项目,后端只返回JSON数据,不返回页面,那就不需要视图解析器!所以,视图解析器,相对其他的组件不是必须的![财务]
简单来讲

调用
Controller层的方法,先通过handlerMapping里面缓存的handler访问路径,和handler(controller方法)识别到需要的请求参数, 通过HandlerAdapter,提取对应的参数 k 对应的 v。然后才执行handler,返回数据再经过handlerAdapter将 handler 返回的数据封装到 response 中,如果是静态资源返回一个字符。利用视图解析器规定的格式拼接访问静态资源
Web 场景原理
自动配置原理
- 整合 web 场景依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 引入了
autoconfigure功能 @EnableAutoConfiguration注解使用@Import(AutoConfigurationImportSelector.class)批量导入组件- 加载
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中配置的所有组件 - 在
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中按需加载关于 web 自动配置类
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration====以下是响应式web场景和现在的没关系======
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.ReactiveMultipartAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.WebSessionIdResolverAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration
================以上没关系=================org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
- 绑定了配置文件的一堆配置项
- SpringMVC的所有配置
spring.mvc - Web场景通用配置
spring.web - 文件上传配置
spring.servlet.multipart - 服务器的配置
server: 比如:编码方式
- SpringMVC的所有配置
自动配置效果
包含了 ContentNegotiatingViewResolver 和 BeanNameViewResolver 组件,方便视图解析
默认的静态资源处理机制: 静态资源放在 static 文件夹下即可直接访问
自动注册了 Converter,GenericConverter, Formatter组件,适配常见数据类型转换和格式化需求
支持 HttpMessageConverters,可以方便返回 json 等数据类型
注册 MessageCodesResolver,方便国际化及错误消息处理
支持 静态
index.html自动使用
ConfigurableWebBindingInitializer,实现消息处理、数据绑定、类型转化、数据校验等功能
WebMvcConfigurer 接口!!!
在
External Libraries中搜索spring-boot-autoconfigure然后再进到
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports找到
WebMvcAutoConfiguration。它是SpringMvC自动配置类再找到
WebMvcAutoConfigurationAdapter。
- 它实现了
WebMvcConfigurer接口- 并且有
@EnableConfigurationProperties({WebMvcProperties.class, WebProperties.class})配置前缀- 得出这个接口包含了所有
SpringMVC组件的默认配置.
通过
WebMvCAutoConfigurationAdapter搜索以下方法可以找到响应组件的默认配置

最佳实践
WebMvcConfigurer 接口:
当你需要对
Spring MVC的一些常见功能进行配置和扩展时,会使用WebMvcConfigurer。比如添加拦截器来实现权限验证、配置视图控制器来简化页面跳转、自定义消息转换器来处理特定格式的数据等。不会影响自动配置
WebMvcConfigurer 接口
当你需要对
Spring MVC的底层请求处理逻辑进行深度定制时,会使用WebMvcRegistrations。例如,你想要自定义RequestMappingHandlerMapping的请求映射规则,让它根据特定的条件来匹配请求;或者自定义ExceptionHandlerExceptionResolver的异常处理逻辑,实现更复杂的异常处理策略。不会影响自动配置
@EnableMVC 注解
当你在配置类上添加
@EnableWebMvc注解时,它会全面接管Spring MVC的配置工作。这意味着Spring Boot默认提供的MVC自动配置会被完全覆盖,你需要手动配置所有与Spring MVC相关的组件,像视图解析器、消息转换器、拦截器、静态资源处理器等。
| 方式 | 用法 | 效果 | |
|---|---|---|---|
| 全自动 | 直接编写控制器逻辑 | 全部使用自动配置默认效果 | |
| 手自一体 | @Configuration + 配置WebMvcConfigurer+ 配置 WebMvcRegistrations | 不要标注 @EnableWebMvc | 保留自动配置效果。手动设置部分功能 ,定义MVC底层组件 |
| 全手动 | @Configuration + 配置WebMvcConfigurer | 标注 @EnableWebMvc | 禁用自动配置效果 全手动设置 |
SpringBoot 访问路径设置
路径注解 @RequestMapping
方法级别
直接在方法上加
@RequestMapping。当多个方法处理同一个路径的不同操作时,可以使用方法级别的@RequestMapping注解进行更精细的映射。
@Controller
public class UserController {//这里路径就是 /index 访问就会执行这个方法@RequestMapping("/index")public String index() {return null;}
}
类级别
在类上加
@RequestMapping,方法上还要再设置一次@RequestMapping设置了@RequestMapping的参数那就自动加上 类级别 的地址当前缀,如果没有参数就直接用 类地址 地址
@Controller
@RequestMapping("/user")
public class UserController {@RequestMapping //这里没有参数就直接用类级别的参数也就是 /userpublic String index() {return null;}@RequestMapping(value = "login") //这里有参数就是自动加上类级别的地址当前缀也就是 /user/loginpublic String login() {return null;}}
特定请求方式限制 —— 枚举方式
注意:违背请求方式,会出现405异常!!!
HTTP协议定义了八种请求方式,在SpringMVC中封装到了下面这个枚举类:public enum RequestMethod {GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE }
@Controller
public class UserController {/*** 精准设置访问地址 /user/login* method = RequestMethod.POST 可以指定单个或者多个请求方式!* 注意:违背请求方式会出现405异常!*/@RequestMapping(value = {"/user/login"} , method = RequestMethod.POST)@ResponseBodypublic String login(){System.out.println("UserController.login");return "login success!!";}
}
特定请求方式限制 —— 注解方式
注意:进阶注解只能添加到 handler 方法上,无法添加到类上!
还有
@RequestMapping的 HTTP 方法特定快捷方式变体:
@GetMapping@PostMapping@PutMapping@DeleteMapping@PatchMapping
@RequestMapping(value="/login",method=RequestMethod.GET)
就等于
@GetMapping(value="/login")
精确路径匹配
SpringMVC中@RequestMapping的/可以省略
.
/就表示绝对路径 ,Tomcat 中表示http://localhost:8080/,设置Tomcat上下文路径为/缺省就可以直接使用/+地址访问对应的Servlet
@RequestMapping(value = "/login", method = RequestMethod.POST) public String login() { return null; }
模糊路径匹配
- 在
@RequestMapping注解指定URL地址时,通过使用通配符,匹配多个类似的地址。*表示任意单层:/user/*这种就是一层可以访问,/user/a/b这就是两层访问不了**表示任意层:/user/**,比如:/user/a,/user/a/b都可以
@Controller
public class ProductController {/*** 路径设置为 /product/* * /* 为单层任意字符串 /product/a /product/aaa 可以访问此handler * /product/a/a 不可以* * 路径设置为 /product/** * /** 为任意层任意字符串 /product/a /product/aaa 可以访问此handler * /product/a/a 也可以访问*/@RequestMapping("/product/*")@ResponseBodypublic String show(){System.out.println("ProductController.show");return "product show!";}
}
SpringBoot 接收参数
param 和 json 参数比较
在 HTTP 请求中,我们可以选择不同的参数类型,如 param 类型和 JSON 类型。下面对这两种参数类型进行区别和对比:
param:key = value & key = valuejson:{ key : value, key : value }
.
- 参数编码:
param 类型的参数会被编码为 ASCII 码。例如,假设name=john doe,则会被编码为name=john%20doe。而 JSON 类型的参数会被编码为 UTF-8。
.- 参数顺序:
param 类型的参数没有顺序限制。但是,JSON 类型的参数是有序的。JSON 采用键值对的形式进行传递,其中键值对是有序排列的。
.- 数据类型:
param 类型的参数仅支持字符串类型、数值类型和布尔类型等简单数据类型。而 JSON 类型的参数则支持更复杂的数据类型,如数组、对象等。- 嵌套性:
param 类型的参数不支持嵌套。但是,JSON 类型的参数支持嵌套,可以传递更为复杂的数据结构。
.- 可读性:
param 类型的参数格式比 JSON 类型的参数更加简单、易读。但是,JSON 格式在传递嵌套数据结构时更加清晰易懂。
.总的来说,param 类型的参数适用于单一的数据传递,而 JSON 类型的参数则更适用于更复杂的数据结构传递。根据具体的业务需求,需要选择合适的参数类型。
.
在实际开发中,
常见的做法是:在GET请求中采用param类型的参数,而在POST请求中采用JSON类型的参数传递。
返回对象就是 json
简单类型接值
客户端请求

Handler 接收参数
- 只要形参参数名和类型与传递的参数相同,即可自动接收!
- 也可以不传递参数
@Controller
@RequestMapping("param")
public class ParamController {/*** 前端请求: http://localhost:8080/param/value?name=xx&age=18** 可以利用形参列表,直接接收前端传递的param参数!* 要求: 参数名 = 形参名* 类型相同* 出现乱码正常,json接收具体解决!!* @return 返回前端数据*/@GetMapping(value="/value")@ResponseBodypublic String setupForm(String name,int age){System.out.println("name = " + name + ", age = " + age);return name + age;}
}
简单类型接值【形参和请求参数不一致】
- 指定绑定的请求参数名:
@RequestParam(value="指定请求参数名")【形参名和请求参数名一致可以省略】- 要求请求参数必须传递:
required = false【前端是否必须传递此此参数,默认是必须,不传报400异常】- 为请求参数提供默认值:
defaultValue = "1"【当非必须传递的时候, 可以设置默认值】)
浏览器请求

handler 接收参数
public class HelloController {//绑定请求参数为 myname 和 myage。myage 不必须传递。默认值为 0@RequestMapping(value = "/springmvc/hello")@ResponseBodypublic String hello(@RequestParam(value = "myname") String name, @RequestParam(value = "myage", required =false, defaultValue = "0") int age) {System.out.println("name:" + name + ",age:" + age);return name + ":" + age;}
}
数组类型接收
param的key和数组参数名一致就会接收
客户端请求

handler 参数
@Controller
@RequestMapping("user")
public class testcontroller {@ResponseBody@RequestMapping//注意这里的 数组 参数名要和 param 的 key 一致public String test1(@RequestParam String[] names) {System.out.println(Arrays.toString(names));return Arrays.toString(names);}
}
集合类型接收
一个名字对应多个值
- 多选框,提交的数据的时候一个key对应多个值,我们可以使用集合进行接收!集合用
@RequestParam声明.
注意:param 的 key 要和集合名字一样
客户端请求

handler 接收参数
@Controller
@RequestMapping("user")
public class testcontroller {@ResponseBody@RequestMapping//注意这里的 List 参数名要和 param 的 key 一致public String test1(@RequestParam List<String> names) {System.out.println(names);return names.toString();}}
实体类型接收
要通过对象接收参数值,只需创建一个实体类,为每个属性配备
get 和 set方法,客户端传递的param key要和实体类的属性名一致。接收参数时,在形参列表中声明实体类对象即可。
.
如果是实体类对象的属性还是个对象那就用address.provice这样来做 param 的 key
.
注意点:实体类必须有 get 和 set
POJO
@Data
public class User {private int age;private String name;private Address address;
}
@Data
public class Address {private String province;private String city;}
客户端

handler
@Controller
@RequestMapping("user")
public class testcontroller {@ResponseBody@RequestMappingpublic String test1(User user) {System.out.println(user);return user.toString();}}
日期参数接收
param 的 key 要和 日期类型的参数名一样。并且用
@DateTimeFormat指定格式
客户端

handler
@Controller
@RequestMapping("user")
public class testcontroller {@ResponseBody@RequestMappingpublic String test1(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDate updateTime) {System.out.println(updateTime);return updateTime.toString();}}
路径参数接收
{} 声明的路径原理就是 *
动态路径参数:
http://localhost:8080/path/key/root这里的key/root假如是动态路径。那它可以当参数传递给handler
- 接收动态路径参数必须要用 @
PathVariable声明。- 如果 handler 形参名和路径的名字一样。那就直接
@PathVariable就行。不一样就手动指定@PathVariable的 name
客户端

handler
@Controller
//这里 key 和 password 可以传递给下面的 handler
@RequestMapping("path/{key}/{password}")
public class testcontroller {@ResponseBody@RequestMappingpublic String //第一个参数因为形参名和路径名不一样所以要设置 name 参数test1(@PathVariable(name= "key") String mykey, @PathVariable String password) {System.out.println(mykey + ":" + password);return mykey + ":" + password;}}
路径匹配默认规则 【路径参数】
Ant 风格路径用法
Ant 风格的路径模式语法具有以下规则:
*:表示任意数量的字符。**?:表示任意一个字符。****:表示任意数量的目录。{}:表示一个命名的模式占位符。[]:表示字符集合,例如 [a-z] 表示小写字母。举例
*.html匹配任意名称,扩展名为.html的文件。
/folder1/*/*.java 匹配在folder1目录下的任意两级目录下的.java文件。
/folder2/**/*.jsp匹配在folder2目录下任意目录深度的.jsp文件。
/{type}/{id}.html匹配任意文件名为{id}.html,在任意命名的{type}目录下的文件。注意:Ant 风格的路径模式语法中的特殊字符需要转义,如:
- 要匹配文件路径中的星号,则需要转义为
\\*- 要匹配文件路径中的问号,则需要转义为
\\?。
新规则和旧规则改变
AntPathMatcher与PathPatternParser
- PathPatternParser 在 jmh 基准测试下,有 6~8 倍吞吐量提升,降低 30%~40%空间分配率
- PathPatternParser 兼容 AntPathMatcher语法,并支持更多类型的路径模式
- PathPatternParser
\**多段匹配的支持仅允许在模式末尾使用
@GetMapping("/a*/b?/{p1:[a-f]+}")public String hello(HttpServletRequest request, @PathVariable("p1") String path) {log.info("路径变量p1: {}", path);//获取请求路径String uri = request.getRequestURI();return uri;}
总结
- 使用默认的路径匹配规则,是由
PathPatternParser提供的 - 如果路径中间需要有
\**,替换成ant风格路径
# 改变路径匹配策略:
# ant_path_matcher 老版策略;
# path_pattern_parser 新版策略;
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
JSON 参数接收
前端发送 JSON 数据时,
Spring MVC框架可通过@RequestBody注解将其转为 Java 对象。此注解表示方法参数值从请求体获取,Springboot中直接添加该注解就行,无需额外操作,且不用指定 value 属性,它会自动映射到相应的参数上。
- 第一步:给前端来的 JSON 存储的 POJO 类
@Data
public class Person {private String name;private int age;private String gender;}
- 第二步:接收 JSON
@RequestMapping("/json")
@Controller
@ResponseBody
public class JsonController {//data -> 请求体 post {name,age,gender}//前端 传了一个 json 报 415//原因: java原生的api 只支持路径参数和 param 参数 不支持 json// json 本身就是前端的格式//解决: 1. 导入 json 处理的依赖 2.handlerAdapter 配置 json 转化器@PostMapping("data")public String data(@RequestBody Person person) {System.out.println("person = " + person);return person.toString();}
}
Cookie 数据接收

可以使用
@CookieValue注解将HTTP Cookie的值绑定到的方法参数。
@Controller
@ResponseBody
@RequestMapping("/test")
public class testcontroller {@RequestMapping("/cooie")//形参名和 cookie key 一样就不用给 @CookieValue 指定 namepublic String addPerson(@CookieValue String cookieName){System.out.println("value = " + cookieName);return cookieName;}//创建 Cookie@GetMapping("save")public String save(HttpServletResponse response) {Cookie cookie = new Cookie("cookieName", "root");response.addCookie(cookie);return "ok";}}
请求头信息接收

- 第一种:根据参数接收*
@RequestHeader("请求头的 key")
@GetMapping("/demo")
public void handle(@RequestHeader("Accept-Encoding") String encoding, @RequestHeader("Keep-Alive") long keepAlive) { ...
}
- 第二种:根据形参名自动匹配*
//获取 token
//这种是根据根据参数名自动匹配
@GetMapping("/demo")
public void handle(@RequestHeader String token) { }
SpringBoot 响应数据
模板引擎
模板引擎就是类似 vue 的东西
SpringBoot 包含以下模板引擎的自动配置
FreeMarkerGroovyThymeleafMustache
整合 Thymeleaf
- 导入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 在
template放html文件

- 写
controller
@Controller
public class WelcomeController {/*** 利用模板引擎跳转到指定页面* @return*/@GetMapping("/well")public String hello(@RequestParam("name") String name, Model model) {//模板的逻辑视图名//物理视图 = 前缀 + 逻辑视图名 + 后缀//真是地址 = classpath:/templates/welcome.html//把需要给页面共享的数据放到 model 中model.addAttribute("msg", name);return "welcome";}}
返回 JSON 数据
基本使用
- 创建 pojo
@Data
public class User {private String name;private int age;}
- 响应数据
@RequestMapping("json")
@RestController //@Controller + @ResponseBody
public class JsonController {@GetMapping("data2")public List<User> data1() {User user = new User();user.setName("two dogs!");user.setAge(3);List<User> users = new ArrayList<>();users.add(user);return users;}
}
@ResponseBody 注解
- 方法上使用
@ResponseBody
在前后端分离项目里,
@ResponseBody注解加在方法上,它会把方法返回的对象序列化成JSON或 XML 格式的数据,直接发给客户端。这意味着返回值 不会走视图解析器渲染这一步,而是 直接作为数据响应。
@RequestMapping(value = "/user/detail", method = RequestMethod.POST)
@ResponseBody
public User getUser(@RequestBody User userParam) {System.out.println("userParam = " + userParam);User user = new User();user.setAge(18);user.setName("John");//返回的对象,会使用jackson的序列化工具,转成json返回给前端!return user;
}
- 在类上使用
@ResponseBody
如果类中每个方法上都标记了
@ResponseBody注解,那么这些注解就可以提取到类上。
@ResponseBody //responseBody可以添加到类上,代表默认类中的所有方法都生效!
@Controller
@RequestMapping("param")
public class ParamController {
@RestController 注解
类上的
@RestponseBody注解可以和@Controller注解合并为@RestController注解。所以使用了@RestController注解就相当于给类中的每个方法都加了@ResponseBody注解。
内容协商 [ 返回 JSON 原理 ]
@ResponseBody 默认规则
基于请求头内容协商:(默认开启)
- 客户端向服务端发送请求,携带
HTTP标准的Accept请求头。Accept:application/json、text/xml、text/yaml- 服务端根据客户端请求头期望的数据类型进行动态返回
.
.
基于请求参数内容协商:(需要手动开启)
- 发送请求
GET /projects/spring-boot?format=json
format=...的形式进行内容协商- 匹配到
@GetMapping("/projects/spring-boot")- 根据参数协商,优先返回
json类型数据- 如果发送请求
GET /projects/spring-boot?format=xml,优先返回xml类型数据# 开启基于请求参数的内容协商 spring.mvc.contentnegotiation.favor-parameter=true #自定义参数名,默认为format spring.mvc.contentnegotiation.parameter-name=myparam

@ResponseBody 原理
@ResponseBody由HttpMessageConverter处理
HttpMessageConverter会先进行内容协商默认
MessageConverter有以下
ByteArrayHttpMessageConverter: 支持字节数据读写StringHttpMessageConverter: 支持字符串读写ResourceHttpMessageConverter:支持资源读写ResourceRegionHttpMessageConverter: 支持分区资源写出AllEncompassingFormHttpMessageConverter:支持表单xml/json读写MappingJackson2HttpMessageConverter: 支持请求体响应体Json读写系统提供默认的MessageConverter 功能有限,仅用于json或者普通返回数据。额外增加新的内容协商功能,必须增加新的
HttpMessageConverter
静态资源
静态资源路径映射
- 访问
/**默认就来以下路径寻找静态资源
classpath:/META-INF/resources/classpath:/resources/classpath:/static/classpath:/public/
注意:
- 欢迎页
index.html也是默认在以上路径查找。没有就在templates下找index.html项目启动默认访问 favicon.ico(浏览器窗口栏那个图标)也是默认在以上路径查找
静态资源缓存规则
cachePeriod 【大概配置】
cachePeriod是指资源被缓存的时间长度。在此时间范围内,资源会被浏览器或代理服务器缓存,不需要再次从服务器获取。- 默认值:如果没有设置
cachePeriod,则默认没有缓存周期,每次请求都会向服务器发送请求以获取最新的资源。- 单位:
cachePeriod的单位通常是秒(s)。例如,如果设置为3600,则表示资源会被缓存1小时。- 作用:设置
cachePeriod可以减少服务器的负载和网络延迟,提高资源的加载速度,特别是对于不经常变化的资源(如图片、CSS、JavaScript文件)。.
cacheControl 【精确配置】
cacheControl是HTTP协议中的一个头部字段,用于指定在HTTP请求 / 响应链中,资源应该如何被缓存。- 默认:没有
cacheControl- 详细说明:
cacheControl可以设置多个指令,例如:
no-cache:告诉浏览器或代理服务器在重新验证资源之前不能使用缓存资源。no-store:告诉浏览器或代理服务器不存储这次请求或响应的任何部分。max-age=<seconds>:指定资源被缓存的最大时间,单位为秒。public:表明响应可以被任何缓存所存储。private:表明响应只能被单个用户缓存,不能被共享缓存所存储。- 作用:通过
cacheControl,可以更精细地控制资源的缓存行为,确保用户能够获取到最新的资源,或者提高资源的加载速度。.
userLastModified
定义:
useLastModified是一个标志,表示是否在HTTP响应中包含Last-Modified头部。默认::false
详细定义:
userLastModified为true会带上一个Last-Modified(该资源的最后修改时间)。下次请求改资源会获取If-Modified-Since。这个If-Modified-Since的值就是Last-Modified(该资源的最后修改时间)。要是资源从If-Modified-Since开始就没动过。就直接返回 304 。直接使用缓存中的资源通过使用
Last-Modified头部,可以减少不必要的数据传输,因为如果资源没有变化,服务器不需要重新发送资源的内容,只需发送一个状态码即可。有了精确配置就不用大概配置了
自定义静态资源规则
配置方式
翻阅
WebMvConfigurer接口笔记。一直往下进到WebMvcAutoConfigurationAdapter。找到addResourceHandlers方法。这里就是静态资源规则源码

- 静态资源访问路径默认规则
- 照着
getStaticPathPattern()一直往下点 - 可以知道怎么利用 配置文件 自定义这个规则
- 照着



# 重新设置静态资源访问路径
# 从以上图片可以看出前缀是 spring.mvc 后缀是 staticPathPattern
#会覆盖默认规则
spring.mvc.static-path-patteren=/static/**
- 访问静态资源默认到哪个目录去找的默认规则
- 照着
getStaticPathPattern()一直往下点 - 可以知道怎么利用 配置文件 自定义这个规则
- 照着





# 重新设置态资源默认到哪个目录去找的规则# 从以上图片看出 前缀是 spring.web 然后后缀是静态类中的 Resources 中的 staticLocations 属性。然后配置规则是 classpath#会覆盖默认规则
spring.web.resources.static-locations=classpath:/a/, classpath:/b/
- 缓存相关
##大概设置
#设置缓存时间
spring.web.resources.cache.period=3600##详细设置,覆盖period配置:
## 浏览器第一次请求服务器,服务器告诉浏览器此资源缓存7200秒,7200秒以内的所有此资源访问不用发给服务器请求,7200秒以后发请求给服务器
spring.web.resources.cache.cachecontrol.max-age=7200
## 共享缓存。只要是这个客户端。就谁都可以用这个缓存数据
spring.web.resources.cache.cachecontrol.cache-public=true#使用资源 last-modified 时间,来对比服务器和浏览器的资源是否相同没有变化。相同返回 304
spring.web.resources.cache.use-last-modified=true
总结:
spring.mvc前缀- 设置静态资源访问路径
spring.web前缀- 设置访问静态资源要找哪个路径
- 设置静态资源缓存策略
代码方式
因为
WebMvcConfigurer接口包含了所有SpringMVC组件的默认配置。所以我们可以自己写一个配置了实现WebMvcConfigurer接口。自己制定规则
- 第一种方式
@Configuration
public class MyConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {//保留以前的配置//没有 @EnableWebMvc 禁用boot 默认配置。就算没这句话默认配置也还在WebMvcConfigurer.super.addResourceHandlers(registry);//自己加一些配置registry.addResourceHandler("/static/**").addResourceLocations("classpath:/a/", "classpath:/b/").setCacheControl(CacheControl.maxAge(1180, TimeUnit.SECONDS))}
}
- 第二种方式
为什么容器中放一个
WebMvcConfigurer就能配置底层行为
**
WebMvcAutoConfiguration是一个自动配置类,它里面有一个EnableWebMvcConfiguration静态类 **
EnableWebMvcConfiguration继承于DelegatingWebMvcConfiguration,这两个都生效
DelegatingWebMvcConfiguration利用 DI 把容器中 所有WebMvcConfigurer注入进来别人调用
DelegatingWebMvcConfiguration的方法配置底层规则,而它调用所有WebMvcConfigurer的配置底层方法。
@Configuration //这是一个配置类, 容器中放一个 webMMvcConfigurer组件, 就能自定义底层
public class MyConfig{@Beanpublic WebMvcConfigurer webMvcConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/").setCacheControl(CacheControl.maxAge(1180, TimeUnit.SECONDS));}};}
}
SpringBoot 异常处理
单独写一个异常类。发生异常就会走此类下的 handler 方法
ControllerAdvice: 走字符串拼接网址那一套。前后端不分离的RestControllerAdvice:直接返回数据。不拼接。前后端分离
只要发生异常就进入这里寻找对应的异常处理,并且要注意在配置类扫描这个全局异常类。注意要让主程序扫描到这个类
//全局异常发生会走此类下的 handler 方法
//@ControllerAdvice //可以返回逻辑视图 转发和重定向
@RestControllerAdvice
public class GlobalExceptionHandler {//发生异常 -> 进入 @ControllerAdvice 注解的类型 -> 根据@ExceptionHandler(指定的异常) 去处理//指定的异常 可以精准查找 或者查找父异常@ExceptionHandler(ArithmeticException.class)public Object ArithmeticException(ArithmeticException e) {String message = e.getMessage();System.out.println("message = " + message);return message;}//如果没有 ArithmeticException 就走 Exception@ExceptionHandler(Exception.class)public Object Exception(Exception e) {String message = e.getMessage();System.out.println("message = " + message);return message;}}
SpringBoot 登录校验
登录校验会话技术方案
概述

会话跟踪方案对比

JWT 令牌技术
概念
- Token
令牌(
Token):在计算机领域,令牌是一种代表某种访问权限或身份认证信息的令牌。它可以是一串随机生成的字符或数字,用于验证用户的身份或授权用户对特定资源的访问。普通的令牌可能以各种形式出现,如访问令牌、身份令牌、刷新令牌等。
.
简单理解 : 每个用户生成的唯一字符串标识,可以进行用户识别和校验

- JWT
jwt工作流程
用户提供其凭据(通常是用户名和密码)进行身份验证。
服务器对这些凭据进行验证,并在验证成功后创建一个
JWT。服务器将
JWT发送给客户端,并客户端在后续的请求中将JWT附加在请求头或参数中。服务器接收到请求后,验证
JWT的签名和有效性,并根据JWT中的声明进行身份验证和授权操作
使用语法
- 导入依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency><!-- JDK9以上需要这个依赖-->
<dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.0</version>
</dependency>
- 生成 JWT 令牌*
- 签名算法可以去 JWT 官网查找,密钥自己设置
public class JWTTest {@Testpublic void jwtTest1() {//自己的内容Map<String, Object> claims = new HashMap<>();claims.put("id", 1);claims.put("name", "com");String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "mangfu")//设置签名算法 和 密钥.setClaims(claims) //自定义内容(载荷)[自己的内容].setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)) //设置 jwt 有效期为 1 h (当前时间往后推).compact(); //拿到字符串类型返回值System.out.println(jwt);}
注意事项:

实战:登录成功,下发令牌
登录成功。令牌发到浏览器。后面浏览器每次访问服务端就携带令牌。到服务端进行登录校验
- JWT 令牌工具类
- 下发 JWT 令牌
- 解析 JWT 令牌
public class JwtUtils {//设置密钥private static String signKey = "mangfu"//设置 JWT 令牌生效时间 12 小时private static Long expire = 43200000L;public static String generateJwt(Map<String, Object> claims) {String jwt = JWTs.builder().addClaims(claims).signWith(SignatureAlgoritth.HS256, signKey).setExpiration(new Date(System.currentTimeMillis() + expire)).compact()return jwx; }public static Claims parseJWT(String jwt) {Claims claims = JWTs.parser().setSigningKey(signKey).parseClaimsJws(jwt).getBody();;return claims; }}
Filter 过滤器
概念

基本使用

- 注意是
servlet包下的filter init和destory提供了默认实现可以不重写
详细使用细节
- 使用流程

- 拦截器路径设置

- 过滤器链

实战:登录校验,令牌校验
用户登录成功后,会下发
JWT令牌,然后在后续的每次请求中,都需要在请求头header中携带到服务端, 请求头名称为token,值为登录时下发的JWT令牌
注意

校验流程

@WebServlet(urlPatterns = "/*")
public class DemoFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) servletRequest;HttpServletResponse resp = (HttpServletResponse) servletResponse;//1. 获取请求 urlString url = req.getRequestURI().toString();System.out.println("请求的 url: " + url);//2.判断请求 url 中是否包含 login, 如果包含, 说明是登录操作, 放行if (url.contains("login")) {System.out.println("登录操作, 放行...");filterChain.doFilter(req, resp);return;}//3. 获取请求头中的令牌 tokenString jwt = req.getHeader("token");//4. 判断令牌是否存在, 如果不存在, 返回错误结果 (未登录)/*public static boolean hasLength(@Nullable String str) {return str != null && !str.isEmpty();}*/if (StringUtils.hasLength(jwt)) {System.out.println("请求头 token 为空, 返回未登录的信息");/*Result error = Result.error("NOT_LOGIN");//把错误信息转成 JSON 发给前端String notLogin = JSONObject.toJSONString(error)resp.getWriter().write(notLogin);*/return;}//5. 如果令牌存在, 解析 token, 如果解析失败, 返回错误结果 (未登录)//解析不报错说明成功, 报错说明失败try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();System.out.println("解析令牌失败, 返回未登录错误信息");/*Result error = Result.error("NOT_LOGIN");//把错误信息转成 JSON 发给前端String notLogin = JSONObject.toJSONString(error)resp.getWriter().write(notLogin);*/}//6. 放行System.out.println("令牌合法, 放行");filterChain.doFilter(req, resp);}
}
Interceptor 拦截器
概念


拦截器使用

就是自定义一个拦截器类实现
HandlerInterceptor,然后配置类实现WebMvcConfigurer扫描拦截器类。配置拦截路径
- 实现
HandlerInterceptor实现其所有方法

- 配置类实现
WebMvcConfigurer添加拦截器
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = {"com.atguigu.controller","com.atguigu.exceptionhandler"})
public class SpringMvcConfig implements WebMvcConfigurer {//添加拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {//配置方案1 拦截全部请求registry.addInterceptor(new MyInterceptor());//配置方案2 指定地址拦截// * 任意一层字符串 ** 任意多层字符串registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/data");//配置方案3 排除拦截 // addPathPatterns 需要拦截的路径// excludePathPatterns 需要拦截的路径中有哪些不拦截registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/**").excludePathPatterns("/user/data1");}
}
多个拦截器情况
- 如果有多个拦截器,执行顺序
- preHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置顺序调用各个 preHandle() 方法。
- postHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置相反的顺序调用各个 postHandle() 方法。
- afterCompletion() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置相反的顺序调用各个 afterCompletion() 方法。
实战:登录校验,令牌校验

@Component
public class DemoInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1. 获取请求 urlString url = request.getRequestURI().toString();System.out.println("请求的 url: " + url);//2.判断请求 url 中是否包含 login, 如果包含, 说明是登录操作, 放行if (url.contains("login")) {System.out.println("登录操作, 放行...");return true;}//3. 获取请求头中的令牌 tokenString jwt = request.getHeader("token");//4. 判断令牌是否存在, 如果不存在, 返回错误结果 (未登录)/*public static boolean hasLength(@Nullable String str) {return str != null && !str.isEmpty();}*/if (StringUtils.hasLength(jwt)) {System.out.println("请求头 token 为空, 返回未登录的信息");/*Result error = Result.error("NOT_LOGIN");//把错误信息转成 JSON 发给前端String notLogin = JSONObject.toJSONString(error)resp.getWriter().write(notLogin);*/return false;}//5. 如果令牌存在, 解析 token, 如果解析失败, 返回错误结果 (未登录)//解析不报错说明成功, 报错说明失败try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();System.out.println("解析令牌失败, 返回未登录错误信息");/*Result error = Result.error("NOT_LOGIN");//把错误信息转成 JSON 发给前端String notLogin = JSONObject.toJSONString(error)resp.getWriter().write(notLogin);*/}//6. 放行System.out.println("令牌合法, 放行");return true;}
}
拦截器和过滤器的区别

RESTFul 风格设计规范
HTTP 协议请求方式要求
REST 风格主张在项目设计、开发过程中,具体的操作符合HTTP协议定义的请求方式的语义。
操作 请求方式 查询操作 GET 保存操作 POST 删除操作 DELETE 更新操作 PUT
URL 风格要求
在
RESTful风格的 API 设计里,URL 路径一般用名词命名,用来表示资源。资源可以是用户、订单这类实体,也能是搜索、计算等服务。设计 URL 路径时,强调用名词标识资源,而非用动词描述操作。比如,把/editEmp(动词)改成/Emp(名词) 。
.
例如:
GET /users:检索用户列表POST /users:创建新用户PUT /users/123:更新ID为123的用户DELETE /users/123:删除ID为123的用户
| 操作 | 传统风格 | REST 风格 |
|---|---|---|
| 保存 | /CRUD/saveEmp | URL 地址:/CRUD/emp 请求方式:POST |
| 删除 | /CRUD/removeEmp?empId=2 | URL 地址:/CRUD/emp/2 请求方式:DELETE |
| 更新 | /CRUD/updateEmp | URL 地址:/CRUD/emp 请求方式:PUT |
| 查询 | /CRUD/editEmp?empId=2 | URL 地址:/CRUD/emp/2 请求方式:GET |
传递参数设计要求
获取数据
GET,删除数据DELTETE
- 参数是 id 标识。使用路径 方式
/url/id- 参数是 是 范围参数。使用 param 方式
/url?page=1&size=10保存数据
POST,修改数据PUT
- 全部使用请求体传递
JSON方式其他原则
- 请求参数应该限制在 10 个以内,过多的请求参数可能导致接口难以维护和使用。
- 对于敏感信息,最好使用 POST 采用请求体来传递参数。
- 如果地址冲突 (请求方式 和 路径都一样) :那就在后面加个动词区分一下,比如
GET /user和GET /user/search
实战举例
接口设计
| 功能 | 接口和请求方式 | 请求参数 | 返回值 |
|---|---|---|---|
| 分页查询 | GET /user | page=1&size=10 | { 响应数据 } |
| 用户添加 | POST /user | { user 数据 } | {响应数据} |
| 用户详情 | GET /user/1 | 路径参数 | {响应数据} |
| 用户更新 | PUT /user | { user 更新数据} | {响应数据} |
| 用户删除 | DELETE /user/1 | 路径参数 | {响应数据} |
| 条件模糊 | GET /user/search | page=1&size=10&keywork=关键字 | {响应数据} |
- 用户 pojo
package com.atguigu.pojo;/*** projectName: com.atguigu.pojo* 用户实体类*/
@Data
public class User {private Integer id;private String name;private Integer age;
}
- controller
/*** projectName: com.atguigu.controller** description: 用户模块的控制器*/
@RequestMapping("user")
@RestController
public class UserController {/*** 模拟分页查询业务接口*/@GetMappingpublic Object queryPage(@RequestParam(name = "page",required = false,defaultValue = "1")int page,@RequestParam(name = "size",required = false,defaultValue = "10")int size){System.out.println("page = " + page + ", size = " + size);System.out.println("分页查询业务!");return "{'status':'ok'}";}/*** 模拟用户保存业务接口*/@PostMappingpublic Object saveUser(@RequestBody User user){System.out.println("user = " + user);System.out.println("用户保存业务!");return "{'status':'ok'}";}/*** 模拟用户详情业务接口*/@PostMapping("/{id}")public Object detailUser(@PathVariable Integer id){System.out.println("id = " + id);System.out.println("用户详情业务!");return "{'status':'ok'}";}/*** 模拟用户更新业务接口*/@PutMappingpublic Object updateUser(@RequestBody User user){System.out.println("user = " + user);System.out.println("用户更新业务!");return "{'status':'ok'}";}/*** 模拟条件分页查询业务接口*/@GetMapping("search")public Object queryPage(@RequestParam(name = "page",required = false,defaultValue = "1")int page,@RequestParam(name = "size",required = false,defaultValue = "10")int size,@RequestParam(name = "keyword",required= false)String keyword){System.out.println("page = " + page + ", size = " + size + ", keyword = " + keyword);System.out.println("条件分页查询业务!");return "{'status':'ok'}";}
}
相关文章:
SpringBoot Web开发(SpringMVC)
SpringBoot Web开发(SpringMVC) MVC 核心组件和调用流程 Spring MVC与许多其他Web框架一样,是围绕前端控制器模式设计的,其中中央 Servlet DispatcherServlet 做整体请求处理调度! . 除了DispatcherServletSpringMVC还会提供其他…...
汽车蓝牙钥匙定位仿真小程序
此需求来自于粉丝的真实需求,假期没事,牛刀小试。 一、项目背景 如今,智能车钥匙和移动端定位技术已经相当普及。为了探索蓝牙 Beacon 在短距离定位场景下的可行性,我们搭建了一个简易原型:利用 UniApp 在移动端采集蓝牙信标的 RSSI(信号强度),通过三边定位算法估算钥…...
K8S中高级存储之PV和PVC
高级存储 PV和PVC 由于kubernetes支持的存储系统有很多,要求客户全都掌握,显然不现实。为了能够屏蔽底层存储实现的细节,方便用户使用, kubernetes引入PV和PVC两种资源对象。 PV(Persistent Volume) PV是…...
【C语言进阶】- 动态内存管理
动态内存管理 1.1 为什么存在动态内存分配1.2 动态内存函数介绍2.1 malloc函数的使用2.2 free函数的使用2.3 calloc函数的使用2.4 realloc函数的使用3.1 常见的动态内存错误3.2 常见笔试题 1.1 为什么存在动态内存分配 我们已经掌握的内存开辟方式有: int val 20;…...
Python实现基于TD3(Twin Delayed Deep Deterministic Policy Gradient)算法来实时更新路径规划算法
下面是一个使用Python实现基于TD3(Twin Delayed Deep Deterministic Policy Gradient)算法来实时更新路径规划算法的三个参数(sigma0,rho0 和 theta)的示例代码。该算法将依据障碍物环境进行优化。 实现思路 环境定义…...
pytorch实现半监督学习
半监督学习(Semi-Supervised Learning,SSL)结合了有监督学习和无监督学习的特点,通常用于部分数据有标签、部分数据无标签的场景。其主要步骤如下: 1. 数据准备 有标签数据(Labeled Data)&…...
我的毕设之路:(2)系统类型的论文写法
一般先进行毕设的设计与实现,再在现成毕设基础上进行描述形成文档,那么论文也就成形了。 1 需求分析:毕业设计根据开题报告和要求进行需求分析和功能确定,区分贴合主题的主要功能和拓展功能能,删除偏离无关紧要的功能…...
LosslessScaling-学习版[steam价值30元的游戏无损放大/补帧工具]
LosslessScaling 链接:https://pan.xunlei.com/s/VOHc-yZBgwBOoqtdZAv114ZTA1?pwdxiih# 解压后运行"A-绿化-解压后运行我.cmd"...
concurrent.futures.Future对象详解:利用线程池与进程池实现异步操作
concurrent.futures.Future对象详解:利用线程池与进程池实现异步操作 一、前言二、使用线程池三、使用进程池四、注意事项五、结语 一、前言 在现代编程中,异步操作已成为提升程序性能和响应速度的关键手段。Python的concurrent.futures模块为此提供了强…...
StarRocks 安装部署
StarRocks 安装部署 StarRocks端口: 官方《配置检查》有服务端口详细描述: https://docs.starrocks.io/zh/docs/deployment/environment_configurations/ StarRocks架构:https://docs.starrocks.io/zh/docs/introduction/Architecture/ Sta…...
Python Matplotlib库:从入门到精通
Python Matplotlib库:从入门到精通 在数据分析和科学计算领域,可视化是一项至关重要的技能。Matplotlib作为Python中最流行的绘图库之一,为我们提供了强大的绘图功能。本文将带你从Matplotlib的基础开始,逐步掌握其高级用法&…...
线程概念、操作
一、背景知识 1、地址空间进一步理解 在父子进程对同一变量进行修改时发生写时拷贝,这时候拷贝的基本单位是4KB,会将该变量所在的页框全拷贝一份,这是因为修改该变量很有可能会修改其周围的变量(局部性原理)…...
【PySide6拓展】QSoundEffect
文章目录 【PySide6拓展】QSoundEffect 音效播放类**基本概念****什么是 QSoundEffect?****QSoundEffect 的特点****安装 PySide6** **如何使用 QSoundEffect?****1. 播放音效****示例代码:播放音效** **代码解析****QSoundEffect 的高级用法…...
33【脚本解析语言】
脚本语言也叫解析语言 脚本一词,相信很多人都听过,那么什么是脚本语言,我们在开发时有一个调试功能,但是发布版是需要编译执行的,体积比较大,同时这使得我们每次更新都需要重新编译,客户再…...
【Unity】 HTFramework框架(五十九)快速开发编辑器工具(Assembly Viewer + ILSpy)
更新日期:2025年1月23日。 Github源码:[点我获取源码] Gitee源码:[点我获取源码] 索引 开发编辑器工具MouseRayTarget焦点视角Collider线框Assembly Viewer搜索程序集ILSpy反编译程序集搜索GizmosElement类找到Gizmos菜单找到Gizmos窗口分析A…...
如何解决TikTok网络不稳定的问题
TikTok是目前全球最受欢迎的短视频平台之一,凭借其丰富多彩的内容和社交功能吸引了数以亿计的用户。然而,尽管TikTok在世界范围内的使用情况不断增长,但不少用户在使用过程中仍然会遇到网络不稳定的问题。无论是在观看视频时遇到缓冲…...
告别页面刷新!如何使用AJAX和FormData优化Web表单提交
系列文章目录 01-从零开始学 HTML:构建网页的基本框架与技巧 02-HTML常见文本标签解析:从基础到进阶的全面指南 03-HTML从入门到精通:链接与图像标签全解析 04-HTML 列表标签全解析:无序与有序列表的深度应用 05-HTML表格标签全面…...
WireShark4.4.2浏览器网络调试指南:数据统计(八)
概述 Wireshark 是一款功能强大的开源网络协议分析软件,被广泛应用于网络调试和数据分析。随着互联网的发展,以及网络安全问题日益严峻,了解如何使用 Wireshark进行浏览器网络调试显得尤为重要。最新的 Wireshark4.4.2 提供了更加强大的功能…...
Hypium+python鸿蒙原生自动化安装配置
Hypiumpython自动化搭建 文章目录 Python安装pip源配置HDC安装Hypium安装DevEco Testing Hypium插件安装及使用方法插件安装工程创建区域 Python安装 推荐从官网获取3.10版本,其他版本可能出现兼容性问题 Python下载地址 下载64/32bitwindows安装文件&am…...
2025创业思路和方向有哪些?
创业思路和方向是决定创业成功与否的关键因素。以下是一些基于找到的参考内容的创业思路和方向,旨在激发创业灵感: 一、技术创新与融合: 1、智能手机与云电视结合:开发集成智能手机功能的云电视,提供通讯、娱乐一体化体…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...
【Ftrace 专栏】Ftrace 参考博文
ftrace、perf、bcc、bpftrace、ply、simple_perf的使用Ftrace 基本用法Linux 利用 ftrace 分析内核调用如何利用ftrace精确跟踪特定进程调度信息使用 ftrace 进行追踪延迟Linux-培训笔记-ftracehttps://www.kernel.org/doc/html/v4.18/trace/events.htmlhttps://blog.csdn.net/…...
