springmvc 框架学习
什么是 SpringMVC 框架
Spring MVC 是 Spring 框架的核心模块之一,基于 Java Servlet API 构建的 Web 层解决方案。它实现了 MVC 设计模式(Model-View-Controller),专为开发灵活、松耦合的 Web 应用程序而设计。
在控制层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。之所以能做到这一点,是因为 SpringMVC 具备如下显著优势:
- Spring 家族原生产品,与 IOC 容器等基础设施无缝对接。
- 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案。
- 代码清新简洁,大幅度提升开发效率。
- 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可。
- 性能卓著,尤其适合现代大型、超大型互联网项目要求。
核心组件架构
组件 | 功能说明 |
---|---|
DispatcherServlet | 前端控制器,统一处理 HTTP 请求与响应流程(核心调度器) |
HandlerMapping | 映射请求 URL 到具体的控制器(Controller) |
Controller | 业务逻辑处理器,处理请求并返回模型数据 |
ViewResolver | 解析逻辑视图名到具体视图实现(如 JSP、Thymeleaf 等) |
Model | 数据容器,在控制器和视图间传递业务数据 |
SpringMVC 处理请求流程
SpringMVC 请求处理流程可分为以下7个核心步骤,这是企业级应用开发必须掌握的关键机制:
-
HTTP请求到达
用户发起请求后,首先被
DispatcherServlet
(前端控制器)拦截。这是整个流程的入口,类似"总调度中心",负责协调各组件工作。 -
处理器映射定位
HandlerMapping
通过请求 URL 查找对应的Controller
。例如:@Controller @RequestMapping("/user") public class UserController {@GetMapping("/profile") // 映射到/user/profile路径public String getProfile() { ... } }
-
适配器执行处理
HandlerAdapter
根据找到的Controller
信息,通过反射机制调用具体的处理方法。这里会处理:- 参数绑定(
@RequestParam
,@PathVariable
) - 数据验证(
@Valid
) - 内容协商(JSON/XML 格式转换)
- 参数绑定(
-
业务逻辑处理
Controller
方法执行实际业务操作,典型处理包括:@PostMapping("/create") public ModelAndView createUser(@Valid User user) {userService.save(user);return new ModelAndView("success", "user", user); }
-
返回模型视图
处理方法返回
ModelAndView
对象,其中包含:- 视图名称(逻辑视图)
- 模型数据(将传递给视图层的数据)
-
视图解析渲染
ViewResolver
将逻辑视图名解析为具体视图实现(JSP/Thymeleaf 等),例如:spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp
-
响应输出
视图引擎结合模型数据进行渲染,最终生成 HTML/JSON 等响应内容,通过
DispatcherServlet
返回给客户端。
关键增强机制:
- 拦截器链:
HandlerInterceptor
实现 AOP 式处理(权限校验、日志记录)。 - 异常处理:
@ControllerAdvice
统一处理全局异常。 - 内容协商:根据 Accept 头自动选择 JSON/XML 等响应格式。
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 数据,不返回页面,那就不需要视图解析器!所以,视图解析器,相对其他的组件不是必须的![财务]
快速开始
-
创建一个 maven web 项目
- 创建一个 maven 空项目,下载插件
JBLJavaToWeb
把 java 模块工程转化为 web 模块工程。 - 将 maven 空项目转为 web 模块。(需要上面的插件)
- 创建一个 maven 空项目,下载插件
-
导入依赖
<dependencies><!-- springioc相关依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.6</version></dependency><!-- web相关依赖 --><!-- 在 pom.xml 中引入 Jakarta EE Web API 的依赖 --><!--在 Spring Web MVC 6 中,Servlet API 迁移到了 Jakarta EE API,因此在配置 DispatcherServlet 时需要使用Jakarta EE 提供的相应类库和命名空间。错误信息 “‘org.springframework.web.servlet.DispatcherServlet’is not assignable to ‘javax.servlet.Servlet,jakarta.servlet.Servlet’” 表明你使用了旧版本的Servlet API,没有更新到 Jakarta EE 规范。--><dependency><groupId>jakarta.platform</groupId><artifactId>jakarta.jakartaee-web-api</artifactId><version>9.1.0</version><scope>provided</scope></dependency><!-- springwebmvc相关依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>6.0.6</version></dependency>
</dependencies>
- 创建 controller 层
@Controller
public class HelloController {/*** handler就是controller内部的具体方法* @RequestMapping("/hello") 就是用来向handlerMapping中注册的方法注解!* @ResponseBody 代表向浏览器直接返回数据!*/@RequestMapping("/hello")@ResponseBodypublic String hello(){System.out.println("HelloController.hello");return "hello springmvc!!";}
}
-
handler
就是controller
内部的具体方法。 -
@RequestMapping("/hello")
是浏览器访问路径,用来向handlerMapping
中注册的方法注解。 -
@ResponseBody
代表向浏览器直接返回字符串数据,不去走视图解析。
-
创建主配置类,作用:
- 将 controller 层注入到 IoC 容器中。
- 导入
handlerMapping
和handlerAdapter
为容器组件。
@Configuration @ComponentScan("com.yigongsui") public class MyConfig {@Beanpublic HandlerMapping handlerMapping() {return new RequestMappingHandlerMapping();}@Beanpublic HandlerAdapter handlerAdapter() {return new RequestMappingHandlerAdapter();}}
-
配置 web 环境
正常需要编写
web.xml
文件配置 servlet 映射,这里我们使用 java 类去配置:public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {/*** 指定service / mapper层的配置类*/@Overrideprotected Class<?>[] getRootConfigClasses() {return null;}/*** 指定springmvc的配置类* @return*/@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class<?>[] { MyConfig.class };}/*** 设置dispatcherServlet的处理路径!* 一般情况下为 / 代表处理所有请求!*/@Overrideprotected String[] getServletMappings() {return new String[] { "/" };} }
-
配置 tomcat 需要10版本以上
这是项目的访问路径。
- 打开浏览器,访问
localhost:8080/hello
SpringMVC 核心注解
请求映射注解
控制请求到处理方法的映射关系,定义接口的访问路径和 HTTP 方法。
@RequestMapping
作用:通用请求映射,可定义路径、HTTP方法、请求头等。
示例:
@RequestMapping(value = "/books", method = RequestMethod.GET)
public List<Book> listBooks() { ... }
- 快捷注解(基于 HTTP 方法)
-
@GetMapping
:处理 GET 请求@GetMapping("/users/{id}") public User getUser(@PathVariable Long id) { ... }
-
@PostMapping
、@PutMapping
、@DeleteMapping
、@PatchMapping
优势:代码更简洁,避免
method
参数冗余。
参数处理注解
从请求中提取参数并绑定到方法参数。
@RequestParam
作用:获取 URL 参数或表单数据。
参数:
name/value
:参数名required
:是否必传(默认true
)defaultValue
:默认值
示例:
@GetMapping("/search")
public List<Product> search(@RequestParam(name = "keyword", defaultValue = "") String query) { ... }
@PathVariable
作用:获取 URL 路径中的变量(RESTful 风格)。
示例:
@DeleteMapping("/orders/{orderId}")
public void deleteOrder(@PathVariable String orderId) { ... }
@RequestBody
作用:将 HTTP 请求体(如 JSON)反序列化为 Java 对象。
用途:接收 POST/PUT 请求中的复杂数据。
@PostMapping("/employees")
public Employee createEmployee(@RequestBody Employee employee) { ... }
响应处理注解
控制方法返回值的处理方式。
@ResponseBody
作用:将返回值直接写入响应体(而非视图解析)。
组合注解:@RestController
= @Controller
+ @ResponseBody
@RestController
public class ApiController {@GetMapping("/status")public String getStatus() {return "OK";}
}
@ResponseStatus
作用:自定义 HTTP 响应状态码。
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException { ... }
模型与视图注解
处理视图模板渲染和数据传递。
@ModelAttribute
作用:
- 方法级:在控制器方法执行前自动添加数据到模型。
- 参数级:从模型获取已存在的属性。
示例:
@ModelAttribute("categories")
public List<String> loadCategories() {return Arrays.asList("Electronics", "Books");
}
@SessionAttributes
作用:在多个请求间共享模型数据(存储到 Session)。
@Controller
@SessionAttributes("cart")
public class CartController {@ModelAttribute("cart")public Cart initCart() {return new Cart();}
}
配置与扫描注解
定义组件扫描和配置规则。
@Controller
作用:标记类为控制器组件,配合视图解析使用。
@ControllerAdvice
作用:全局控制器增强(统一异常处理、模型数据预处理)。
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public ResponseEntity<String> handleAllExceptions(Exception ex) {return new ResponseEntity<>("Error occurred", HttpStatus.INTERNAL_SERVER_ERROR);}
}
@EnableWebMvc
作用:启用 Spring MVC 默认配置(需在配置类使用)。
-
引入默认配置类
自动导入
DelegatingWebMvcConfiguration
类,该配置类会注册 Spring MVC 的基础组件:- 处理器映射器(
RequestMappingHandlerMapping
) - 处理器适配器(
RequestMappingHandlerAdapter
) - 视图解析器(
InternalResourceViewResolver
) - 消息转换器(如 JSON 处理的
MappingJackson2HttpMessageConverter
) - 数据绑定、类型转换、验证等基础设施。
- 处理器映射器(
-
启用关键功能
- 支持
@Controller
注解的请求处理方法 - 自动注册
@RequestBody
、@ResponseBody
、@Valid
等注解的处理逻辑 - 默认静态资源处理器(如
/resources/**
路径映射)
- 支持
@Configuration
@EnableWebMvc
@ComponentScan("com.yigongsui")
public class WebConfig implements WebMvcConfigurer { ... }
其他重要注解
@CrossOrigin
作用:处理跨域请求(可标注类或方法)。
@CrossOrigin(origins = "https://example.com")
@RestController
public class ApiController { ... }
@InitBinder
作用:自定义请求参数绑定规则。
@InitBinder
public void initBinder(WebDataBinder binder) {binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
重要注解速查
注解 | 典型用途 | 作用范围 |
---|---|---|
@RequestMapping | 定义通用请求映射规则 | 类/方法 |
@GetMapping | 处理 GET 请求 | 方法 |
@RequestParam | 获取 URL 或表单参数 | 方法参数 |
@PathVariable | 获取 URL 路径变量 | 方法参数 |
@RequestBody | 解析请求体到 Java 对象 | 方法参数 |
@ResponseBody | 直接返回数据而非视图 | 方法/类 |
@ModelAttribute | 模型数据预处理 | 方法/参数 |
@ControllerAdvice | 全局异常处理与数据绑定 | 类 |
最佳实践建议
- RESTful 设计:优先使用
@GetMapping
/@PostMapping
等快捷注解。 - 参数校验:结合
@Valid
与 Hibernate Validator 进行数据验证。 - 响应标准化:统一使用
@RestController
返回 JSON 数据。 - 异常处理:通过
@ControllerAdvice
实现全局错误响应。
SpringMVC 接收数据
访问路径设置
使用 @RequestMapping
注解设置访问路径,它的作用就是将请求的 URL 地址和处理请求的方式(handler 方法)关联起来,建立映射关系。
SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的方法来处理这个请求。
-
精确路径匹配
使用具体路径,可以设置多个:
@RequestMapping({"/user/login","/user/login1"})
/user
这个/
可加可不加。 -
模糊路径匹配
/*
:代表一层路径:/user/*
可以是/user/a
、/user/b
。/**
:代表一层或多层路径
-
注解可以放在方法上以及类上
放在类上时,类下的所有方法的路径实际上是方法路径 + 类路径。
@Controller @RequestMapping("/user") public class UserController {@RequestMapping("/login")public void login() {}}
路径就是
/user/login
。方法上必须要有
@RequestMapping
注解,不能省略掉。 -
请求方法设置:
- HTTP 协议定义了八种请求方式,在 SpringMVC 中封装到了下面这个枚举类:
public enum RequestMethod {GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE }
- 默认情况是任意请求方法都可以访问,可使用
@RequestMapping
的method
属性指定具体的请求方法,可以指定多个。
@RequestMapping(value = "/login",method = RequestMethod.GET) @RequestMapping(value = "/login",method = {RequestMethod.GET,RequestMethod.POST})
-
进阶注解
还有 @RequestMapping
的 HTTP 方法特定快捷方式变体,用于指定具体的请求方法:
@GetMapping
等价于@RequestMapping(value = ,method = RequestMethod.GET)
以下同理。@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
这些注解只能作用在方法上,不能放在类上。
param 和 json 参数接收
两者参数比较
在 HTTP 请求中,我们可以选择不同的参数类型,如 param 类型和 json 类型。下面对这两种参数类型进行区别和对比:
-
参数编码:
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 类型的参数传递。
param 参数接收
-
直接接收:只要形参参数的名字和类型与 param 参数的名字和类型相同即可接收。
@RestController public class UserController {@GetMapping("/login")public String login(String name,int age) {System.out.println("name = " + name);System.out.println("age = " + age);return "name ->" + name + ",age ->" + age;}}
如果没有传递相应参数,则接收的参数为 null,不会报错(参数类型为基本数据类型,例如 int,会报错,因为不能为 null)。
-
注解接收:
使用
@RequestParam
注解接收参数,可以指定传递的参数名。@GetMapping("/login") public String login(@RequestParam("name") String name, @RequestParam("age") int age)
默认必须传递参数,否则会报错,可以通过
required
为false
表示可以不接收参数,可以通过defaultValue
属性设置默认值。@GetMapping("/login") public String login(@RequestParam(value = "name",required = false,defaultValue = "zhangsan") String name, @RequestParam("age") int age)
-
接收集合参数
必须使用
@RequestParam
指定参数名称@GetMapping("/login") public String login(@RequestParam("name") List<String> names)
访问
localhost:8080/login?name=zhangsan&name=1111
测试。 -
接收实体类参数
传递参数名必须和实体类属性名相同。
public class User {private String name;private int age;}@GetMapping("/login") public String login(User user) {return user.toString(); }
访问
localhost:8080/login?name=zhangsan&age=18
测试。
动态路径参数接收
开发中,有时参数也会放在路径上,例如 /login/用户名/密码
,这是路径参数。
路径传递参数是一种在 URL 路径中传递参数的方式。在 RESTful 的 Web 应用程序中,经常使用路径传递参数来表示资源的唯一标识符或更复杂的表示方式。
对于这种形式的参数,不能使用 param 参数方式接收,要在路径上加上 {}
代表路径参数,同时使用注解 @PathVariable
接收参数。
@GetMapping("login/{username}/{password}")
public String login(@PathVariable String username, @PathVariable String password) {return username + ":" + password;
}
该注解使用同 @RequestParam
。
浏览器访问 localhost:8080/login/zhangsan/123456
测试。
json 数据接收
前端参数为 json 数据:
{"name":"zhangsan","age":18
}
后端接收参数需要满足以下几个条件:
- 需要用实体类去接收,同时使用
@RequestBody
注解来将 JSON 数据转换为 Java 对象。
@RequestBody
注解表示当前方法参数的值应该从请求体中获取,并且需要指定 value 属性来指示请求体应该映射到哪个参数上。
- 需要引入
jackson
依赖。
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.0</version>
</dependency>
- 需要在
handlerAdpater
配置 json 转化器,只要在配置类上加上注解@EnableWebMvc
即可。
代码示例:
// 实体类
@Data
public class User {private String name;private int age;}// 配置类
@Configuration
@ComponentScan("com.yigongsui")
@EnableWebMvc
public class MyConfig {@Beanpublic HandlerMapping handlerMapping() {return new RequestMappingHandlerMapping();}@Beanpublic HandlerAdapter handlerAdapter() {return new RequestMappingHandlerAdapter();}}// controller
@RestController
public class UserController {@PostMapping("/login")public String login(@RequestBody User user) {return user.toString();}}
前端传递 json 数据通常是 post 请求方式。
测试使用 postman 或 apifox 去测试。
@EnableWebMvc
注解介绍
基本作用
@EnableWebMvc
是 Spring MVC 的注解,用于启用 Spring MVC 的默认配置。它等价于 XML 配置中的 <mvc:annotation-driven/>
,主要功能包括:
- 注册
RequestMappingHandlerMapping
(处理@RequestMapping
注解) - 注册
RequestMappingHandlerAdapter
(支持@RequestBody
、@ResponseBody
等) - 配置默认的 HTTP 消息转换器(如 JSON、XML 转换)
- 启用数据绑定、验证、格式化等基础功能。
有了这个注解,主配置类就不需要注册 HandlerMapping
、HandlerAdapter
为组件了。
核心原理
@EnableWebMvc
通过导入 DelegatingWebMvcConfiguration
类实现功能:
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {}
该类继承自 WebMvcConfigurationSupport
,提供默认的 MVC 配置逻辑。
接收 cookie 和请求头
接收 cookie 参数,在参数上添加注解 @CookieValue("cookieName")
,value 是 cookie 的名字。
接收请求头参数,使用注解 @RequestHeader("Host")
,value 是请求头的名字。
原生 api 对象参数
对于原生的 api 对象,只要在参数直接获取即可,下面是所有的原生 api 对象。
Controller method argument 控制器方法参数 | Description |
---|---|
jakarta.servlet.ServletRequest , jakarta.servlet.ServletResponse | 请求/响应对象 |
jakarta.servlet.http.HttpSession | 强制存在会话。因此,这样的参数永远不会为 null 。 |
java.io.InputStream , java.io.Reader | 用于访问由 Servlet API 公开的原始请求正文。 |
java.io.OutputStream , java.io.Writer | 用于访问由 Servlet API 公开的原始响应正文。 |
@PathVariable | 接收路径参数注解 |
@RequestParam | 用于访问 Servlet 请求参数,包括多部分文件。参数值将转换为声明的方法参数类型。 |
@RequestHeader | 用于访问请求标头。标头值将转换为声明的方法参数类型。 |
@CookieValue | 用于访问Cookie。Cookie 值将转换为声明的方法参数类型。 |
@RequestBody | 用于访问 HTTP 请求正文。正文内容通过使用 HttpMessageConverter 实现转换为声明的方法参数类型。 |
java.util.Map , org.springframework.ui.Model , org.springframework.ui.ModelMap | 共享域对象,并在视图呈现过程中向模板公开。 |
Errors , BindingResult | 验证和数据绑定中的错误信息获取对象! |
示例:
/*** 如果想要获取请求或者响应对象,或者会话等,可以直接在形参列表传入,并且不分先后顺序!* 注意: 接收原生对象,并不影响参数接收!*/
@GetMapping("api")
@ResponseBody
public String api(HttpSession session , HttpServletRequest request,HttpServletResponse response){String method = request.getMethod();System.out.println("method = " + method);return "api";
}
SpringMVC 响应数据
页面跳转控制
返回模版视图
- 返回视图名称(传统模式)
@Controller
@RequestMapping("/demo")
public class DemoController {@GetMapping("/view")public String showView(Model model) {model.addAttribute("message", "Hello Thymeleaf");return "demoPage"; // 对应src/main/resources/templates/demoPage.html}
}
- 配合视图解析器(如 Thymeleaf、JSP)。
- 数据通过 Model 对象传递。
ModelAndView
对象
@Controller
public class MavController {@GetMapping("/mav")public ModelAndView getMAV() {ModelAndView mav = new ModelAndView("viewName");mav.addObject("key", "value");return mav;}
}
- 可同时控制视图和数据。
- 适合需要灵活设置响应头的场景。
转发和重定向
区别
特性 | 转发 (Forward) | 重定向 (Redirect) |
---|---|---|
请求次数 | 1次(服务器内部跳转) | 2次(客户端重新发起请求) |
URL变化 | 不变化 | 变化为新的URL |
数据共享 | 共享原始请求的request 域属性 | 不共享,需通过RedirectAttributes 或Session传递 |
性能 | 更高(无额外网络开销) | 较低(需二次请求) |
适用场景 | 同一应用内跳转 | 跨应用跳转、防表单重复提交 |
实现方式
- 转发(Forward)
-
语法:在控制器方法返回值前添加
forward:
前缀。 -
示例:
@GetMapping("/forwardExample") public String forwardExample() {return "forward:/targetPath"; // 转发到/targetPath }
-
特点:
- 目标路径为应用内相对路径,无需包含上下文路径。
- 共享原始请求的所有参数和属性。
- 重定向(Redirect)
-
语法:在返回值前添加
redirect:
前缀。 -
示例:
@PostMapping("/redirectExample") public String redirectExample(RedirectAttributes attributes) {attributes.addAttribute("param", "value"); // 通过URL传参attributes.addFlashAttribute("flashParam", "tempValue"); // 通过Flash属性传参return "redirect:/targetPath"; // 重定向到/targetPath }
-
特点:
- 目标路径可为绝对路径(如
redirect:http://external.com
)或应用内路径。 - 使用
RedirectAttributes
传递参数:addAttribute()
:参数通过 URL 拼接(暴露在地址栏)。addFlashAttribute()
:参数暂存Session
,仅在下一次请求有效(适合敏感数据)。
- 目标路径可为绝对路径(如
返回 json 数据
需要使用注解 @ResponseBody
避免返回走视图解析。
返回 json 数据只要返回实体类即可。
@GetMapping("/user")
@ResponseBody
public User getUser() {User user = new User();user.setName("zhangsan");user.setAge(18);return user;
}
返回静态资源
需要在 springmvc 配置类配置:
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller") //TODO: 进行controller扫描
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class SpringMvcConfig implements WebMvcConfigurer {//配置jsp对应的视图解析器@Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {//快速配置jsp模板语言对应的registry.jsp("/WEB-INF/views/",".jsp");}//开启静态资源处理 <mvc:default-servlet-handler/>@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();}
}
RESTFul 风格
核心概念
-
REST 定义
REST(Representational State Transfer)由 Roy Fielding 在 2000 年博士论文提出,核心特征:
- 资源为中心:每个 URI 对应唯一资源。
- 统一接口:标准 HTTP 方法操作资源。
- 无状态通信:服务端不保存客户端状态。
- 可缓存性:明确标记响应是否可缓存。
- 分层系统:客户端无需了解直接连接的服务端。
-
资源标识
-
使用 URI 定位资源。示例:
GET /api/v1/books/123
(获取ID=123的图书)DELETE /api/v2/users/456
(删除ID=456的用户) -
避免动词式 URL(如
/getUser?id=1
)
-
HTTP 方法规范
方法 | 幂等性 | 安全 | 语义 | 典型响应状态码 |
---|---|---|---|---|
GET | 是 | 是 | 获取资源 | 200 OK, 404 Not Found |
POST | 否 | 否 | 创建新资源 | 201 Created |
PUT | 是 | 否 | 完整更新资源 | 200 OK, 204 No Content |
PATCH | 否 | 否 | 部分更新资源 | 200 OK |
DELETE | 是 | 否 | 删除资源 | 204 No Content |
状态码标准使用
- 2xx 成功
200 OK
:常规成功。201 Created
:资源创建成功(应包含Location头)。204 No Content
:成功但无返回体。
- 4xx 客户端错误
400 Bad Request
:请求格式错误。401 Unauthorized
:身份验证失败。403 Forbidden
:权限不足。404 Not Found
:资源不存在。
- 5xx 服务端错误
500 Internal Server Error
:未处理的异常。
HATEOAS 约束
HATEOAS(Hypermedia As The Engine Of Application State,超媒体作为应用状态的引擎)是 REST 架构风格的核心约束之一。它要求客户端与服务的交互完全通过动态解析服务端返回的超媒体内容来完成,而无需依赖预先约定的接口文档。
典型实现:
{"id": 123,"name": "示例图书","_links": {"self": { "href": "/books/123" },"publisher": { "href": "/publishers/5" }}
}
设计规范
-
版本控制
- URL 路径中:
/api/v1/resource
- HTTP 头中:
Accept: application/vnd.myapi.v1+json
- URL 路径中:
-
过滤与分页
GET /products?color=red&price_from=100&page=2&size=20
-
响应格式
推荐 JSON 格式,包含标准结构:
{"code": 200,"data": { /* 业务数据 */ },"message": "操作成功","timestamp": 1629091200 }
与传统 RPC 风格对比
维度 | RESTful | RPC 风格 |
---|---|---|
通信协议 | HTTP | 不限 |
核心元素 | 资源 | 操作/方法 |
接口设计 | 基于资源 + HTTP 方法 | 自定义方法名 |
典型 URL | /orders/456 | /getOrder?id=456 |
状态管理 | 无状态 | 可能维护会话状态 |
Spring MVC 实现示例
@RestController
@RequestMapping("/api/v1/books")
public class BookController {@GetMapping("/{id}")public ResponseEntity<Book> getBook(@PathVariable Long id) {Book book = bookService.findById(id);return ResponseEntity.ok().body(book);}@PostMappingpublic ResponseEntity<Void> createBook(@RequestBody Book book) {Book saved = bookService.save(book);URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(saved.getId()).toUri();return ResponseEntity.created(location).build();}@PutMapping("/{id}")public ResponseEntity<Book> updateBook(@PathVariable Long id, @RequestBody Book book) {// 实现更新逻辑return ResponseEntity.ok(updatedBook);}
}
最佳实践
-
URI 设计原则
- 使用名词复数形式:
/users
而非/getUsers
。 - 层级关系:
/departments/{deptId}/employees
。
- 使用名词复数形式:
-
版本管理
建议在 URL 中包含版本号:
/api/v2/resource
。 -
安全规范
- 敏感操作使用 HTTPS。
- 权限控制:结合 JWT 或 OAuth2。
-
文档化
推荐使用 OpenAPI 规范(Swagger):
@Operation(summary = "获取图书详情") @ApiResponse(responseCode = "200", description = "成功获取图书") @GetMapping("/{id}") public Book getBook(@Parameter(description = "图书ID") @PathVariable Long id) {// ... }
常见误区
- 错误使用 HTTP 方法(如用 GET 执行删除)。
- 忽略状态码语义(所有响应都返回 200)。
- 过度设计嵌套资源层级(超过三级)。
- 忽略缓存控制头(Cache-Control,ETag)。
通过遵循 RESTful 规范,可以构建出高度可维护、可扩展且易于理解的 API 系统。实际开发中建议结合 OpenAPI 工具链实现文档自动化。
全局异常处理机制
核心作用
解决分散的异常处理问题,实现:
- 统一异常响应格式(如 JSON 错误报文)。
- 集中管理异常处理逻辑。
- 避免重复的
try-catch
代码。 - 规范 HTTP 状态码返回。
实现方式
@ControllerAdvice
+@ExceptionHandler
(主流方案)
@ControllerAdvice
public class GlobalExceptionHandler {// 处理特定异常@ExceptionHandler(ResourceNotFoundException.class)public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {ErrorResponse error = new ErrorResponse(404, ex.getMessage());return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);}// 兜底处理所有未明确捕获的异常@ExceptionHandler(Exception.class)public ResponseEntity<ErrorResponse> handleAll(Exception ex) {ErrorResponse error = new ErrorResponse(500, "系统内部错误");return ResponseEntity.internalServerError().body(error);}
}
- 实现
HandlerExceptionResolver
接口
@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex) {if (ex instanceof BusinessException) {response.setStatus(400);writeJsonResponse(response, new ErrorResponse(400, ex.getMessage()));}return new ModelAndView(); // 已处理异常,返回空视图}private void writeJsonResponse(HttpServletResponse response, Object body) {// 实现 JSON 序列化输出}
}
关键注解详解
- @ControllerAdvice
- 作用范围:所有带
@Controller
的类。 - 可限定包范围:
@ControllerAdvice(basePackages = "com.example.api")。
- 支持响应体自动转换:配合
@ResponseBody
或使用@RestControllerAdvice。
- 作用范围:所有带
- @ExceptionHandler
- 方法参数可获取:异常对象、请求对象、响应对象等。
- 支持多异常类型:
@ExceptionHandler({NullPointerException.class, IllegalArgumentException.class})
。 - 优先级:具体异常 > 父类异常。
统一错误响应体设计
推荐标准结构(JSON 示例):
{"timestamp": "2023-08-15T10:23:45Z","status": 404,"code": "RESOURCE_NOT_FOUND","message": "请求的图书ID 123不存在","path": "/api/books/123"
}
对应 Java 类:
@Data
@AllArgsConstructor
public class ErrorResponse {private LocalDateTime timestamp;private int status;private String code;private String message;private String path;public ErrorResponse(HttpStatus status, String code, String message, String path) {this.timestamp = LocalDateTime.now();this.status = status.value();this.code = code;this.message = message;this.path = path;}
}
最佳实践
-
异常分类处理
// 业务异常(返回 400) @ExceptionHandler(BusinessException.class) public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex, WebRequest request) {return buildResponse(HttpStatus.BAD_REQUEST, ex.getErrorCode(), ex.getMessage(), request); }// 数据校验异常(返回 422) @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidationExceptions(MethodArgumentNotValidException ex) {String errorMsg = ex.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage).collect(Collectors.joining(", "));return buildResponse(HttpStatus.UNPROCESSABLE_ENTITY, "VALIDATION_FAILED", errorMsg); }
-
日志记录规范
@ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex, WebRequest request) {log.error("全局异常: {}", ex.getMessage());ex.printStackTrace(); // 生产环境应移除return buildResponse(HttpStatus.INTERNAL_SERVER_ERROR, "SERVER_ERROR", "系统繁忙"); }
-
结合 HTTP 状态码
异常类型 推荐状态码 说明 权限不足 403 Forbidden 参数校验失败 422 Unprocessable Entity 认证失败 401 Unauthorized 资源不存在 404 Not Found
常见问题解决方案
-
处理文件上传异常
@ExceptionHandler(MaxUploadSizeExceededException.class) public ResponseEntity<ErrorResponse> handleFileSizeLimitExceeded() {return new ResponseEntity<>(new ErrorResponse(413, "FILE_TOO_LARGE", "文件大小超过限制"),HttpStatus.PAYLOAD_TOO_LARGE); }
-
兼容传统 JSP 视图
@ExceptionHandler(CustomViewException.class) public ModelAndView handleViewException(CustomViewException ex) {ModelAndView mav = new ModelAndView("error/customError");mav.addObject("errorMsg", ex.getMessage());return mav; }
-
处理异步请求异常
@ExceptionHandler(AsyncRequestTimeoutException.class) public ResponseEntity<ErrorResponse> handleAsyncTimeout() {return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(new ErrorResponse(503, "ASYNC_TIMEOUT", "请求超时")); }
扩展技巧
-
自定义异常元注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ErrorMetadata {HttpStatus status() default HttpStatus.BAD_REQUEST;String errorCode(); }@ErrorMetadata(status = HttpStatus.NOT_FOUND, errorCode = "USER_NOT_FOUND") public class UserNotFoundException extends RuntimeException {// ... }
-
自动扫描异常元数据
@ExceptionHandler public ResponseEntity<ErrorResponse> handleAnnotatedException(Exception ex) {ErrorMetadata metadata = ex.getClass().getAnnotation(ErrorMetadata.class);if (metadata != null) {return buildResponse(metadata.status(), metadata.errorCode(), ex.getMessage());}return handleGlobalException(ex); }
通过合理设计全局异常处理机制,可使系统具备:
- 清晰的错误分类体系。
- 统一的客户端响应格式。
- 完善的错误日志追踪。
- 灵活的可扩展性。
拦截器使用
拦截器核心概念
**拦截器(Interceptor)**是 Spring MVC 框架中用于在请求处理的不同阶段插入自定义逻辑的组件。它作用于 Controller
层,可拦截 HTTP 请求并在以下三个关键节点执行操作:
方法名 | 执行时机 | 返回值作用 |
---|---|---|
preHandle | Controller 方法执行前 | true 放行,false 终止流程 |
postHandle | Controller 方法执行后,视图渲染前 | 修改 ModelAndView 对象 |
afterCompletion | 视图渲染完成后 | 资源清理(如关闭流) |
拦截器与过滤器的区别
特性 | 拦截器(Interceptor) | 过滤器(Filter) |
---|---|---|
作用范围 | Spring MVC 框架内 | Servlet 规范,所有 Web 请求 |
依赖关系 | 依赖 Spring 容器 | 不依赖 Spring |
控制粒度 | 针对 Controller 请求 | 所有 HTTP 请求 |
获取上下文 | 可通过 HandlerMethod 获取方法信息 | 仅能获取 Servlet API 对象 |
实现自定义拦截器
步骤1:创建拦截器类
public class AuthInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 示例:检查用户登录状态HttpSession session = request.getSession();if (session.getAttribute("user") == null) {response.sendRedirect("/login");return false; // 拦截请求}return true; // 放行}@Overridepublic void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView) {// 可添加全局模型数据modelAndView.addObject("version", "1.0.0");}@Overridepublic void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler, Exception ex) {// 记录请求完成时间long startTime = (Long) request.getAttribute("startTime");System.out.println("请求耗时:" + (System.currentTimeMillis() - startTime) + "ms");}
}
步骤2:配置拦截器(Java Config方式)
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**") // 拦截所有路径.excludePathPatterns("/login", "/static/**"); // 排除登录页和静态资源registry.addInterceptor(new LogInterceptor()).order(1); // 设置多个拦截器顺序}
}
拦截器执行流程
假设配置了两个拦截器 Interceptor1 和 Interceptor2:
- preHandle 执行顺序:Interceptor1 → Interceptor2
- postHandle 执行顺序:Interceptor2 → Interceptor1
- afterCompletion 执行顺序:Interceptor2 → Interceptor1
典型应用场景
-
身份验证
public boolean preHandle(...) {if (!isAuthenticated(request)) {response.sendError(401, "Unauthorized");return false;}return true; }
-
日志记录
public void afterCompletion(...) {log.info("[{}] {} - {}ms", request.getMethod(),request.getRequestURI(),System.currentTimeMillis() - startTime); }
-
性能监控
public boolean preHandle(...) {request.setAttribute("startTime", System.currentTimeMillis());return true; }
-
全局数据注入
public void postHandle(...) {modelAndView.addObject("currentUser", getCurrentUser()); }
注意事项
-
路径匹配规则
/**
匹配所有路径(含子路径)。/api/*
仅匹配单层路径。/admin/**
匹配/admin下的所有层级。
-
避免循环拦截
不要配置拦截器拦截自身的错误页面(如
/error
)。 -
性能优化
在
preHandle
中优先进行轻量级检查,耗时操作建议异步处理。
通过合理使用拦截器,可以实现横切关注点(Cross-Cutting Concerns)的统一处理,提升代码的可维护性。实际开发中建议结合具体业务需求设计拦截逻辑。
参数校验
添加依赖
使用 Hibernate Validator 实现校验(Bean Validation 规范):
<dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId><version>8.0.0.Final</version>
</dependency>
在实体类定义校验规则
通过注解声明字段约束:
public class User {@NotBlank(message = "用户名不能为空")private String name;@Email(message = "邮箱格式错误")private String email;@Min(value = 18, message = "年龄必须≥18")private Integer age;
}
在Controller触发校验
使用 @Valid
或 @Validated
注解触发校验:
@PostMapping("/register")
public String register(@Valid @RequestBody User user, BindingResult result) {if (result.hasErrors()) {// 处理校验失败逻辑return "error";}// 业务逻辑return "success";
}
处理校验错误
通过 BindingResult
获取错误详情:
if (result.hasErrors()) {List<ObjectError> errors = result.getAllErrors();errors.forEach(error -> System.out.println(error.getDefaultMessage()));
}
常用校验注解
注解 | 作用 |
---|---|
@NotNull | 字段不能为 null |
@NotBlank | 字符串非空且去空格后非空 |
@NotEmpty | 集合 size 不能为0 |
@Size | 长度范围(min/max) |
@Pattern | 正则表达式匹配 |
@Future | 日期必须在未来 |
自定义校验(示例:手机号格式)
- 定义注解
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {String message() default "手机号格式错误";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
- 实现校验逻辑
public class PhoneValidator implements ConstraintValidator<Phone, String> {private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {return value != null && PHONE_PATTERN.matcher(value).matches();}
}
分组校验(场景:区分新增/更新操作)
- 定义分组接口
public interface CreateGroup {}
public interface UpdateGroup {}
- 在实体类指定分组
public class Product {@Null(groups = CreateGroup.class) // 新增时id必须为空@NotNull(groups = UpdateGroup.class) // 更新时id不能为空private Long id;
}
Controller
指定分组
@PostMapping("/create")
public String create(@Validated(CreateGroup.class) @RequestBody Product product) {// ...
}
注意事项
- 嵌套对象校验:对对象内的字段使用
@Valid
递归触发校验。 - 集合校验:在 List 参数前加
@Valid
校验每个元素。 - 性能优化:避免过度复杂的校验逻辑影响性能。
通过以上步骤,Spring MVC 的参数校验能有效拦截非法数据,提升系统健壮性。
相关文章:
springmvc 框架学习
什么是 SpringMVC 框架 Spring MVC 是 Spring 框架的核心模块之一,基于 Java Servlet API 构建的 Web 层解决方案。它实现了 MVC 设计模式(Model-View-Controller),专为开发灵活、松耦合的 Web 应用程序而设计。 在控制层框架历…...
学习threejs,构建THREE.ParametricGeometry参数化函数生成几何体
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.ParametricGeometry1…...
【华为OD-E卷 - 单词接龙 100分(python、java、c++、js、c)】
【华为OD-E卷 - 单词接龙 100分(python、java、c、js、c)】 题目 单词接龙的规则是: 可用于接龙的单词首字母必须要前一个单词的尾字母相同; 当存在多个首字母相同的单词时,取长度最长的单词,如果长度也相…...
美团Leaf分布式ID生成器使用教程:号段模式与Snowflake模式详解
引言 在分布式系统中,生成全局唯一ID是核心需求之一。美团开源的Leaf提供了两种分布式ID生成方案:号段模式(高可用、依赖数据库)和Snowflake模式(高性能、去中心化)。本文将手把手教你如何配置和使用这两种…...
性能测试过程实时监控分析
性能监控 前言一、查看性能测试结果的3大方式1、GUI界面报告插件2、命令行运行 html报告3、后端监听器接入仪表盘 二、influxDB grafana jmeter测试监控大屏1、原理:2、linux环境中influxDB 安装和配置3、jmerer后端监听器连接influxDB4、linux环境总grafana环境搭…...
【工具类】Java的 LocalDate 获取本月第一天和最后一天
博主介绍:✌全网粉丝22W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
Eclipse 创建 Java 类
Eclipse 创建 Java 类 引言 Eclipse 是一款功能强大的集成开发环境(IDE),被广泛用于 Java 开发。本文将详细介绍如何在 Eclipse 中创建 Java 类,包括配置开发环境、创建新项目、添加类以及编写类代码等步骤。 配置 Eclipse 开发环境 1. 安装 Eclipse 首先,您需要在您…...
Centos编译升级libcurl
Centos编译升级libcurl 下载最新版源码包安装编译依赖配置编译选项如果报错:通过 EPEL 仓库安装手动源码编译安装 如果报错:安装Brotli 开发库 如果报错:方法一:安装 libpsl-devel 依赖通过 EPEL 仓库安装重新运行 configure 方…...
蓝桥杯第九天 2022 省赛 第 4 题 最少刷题数
太多坑了,考虑不全只能过50%,有两种特殊情况 public static void main(String[]args) {Scanner scan new Scanner(System.in);int n scan.nextInt();int a[] new int [100005];int b[] new int [100005];for(int i 0;i<n;i)a[i] scan.nextInt()…...
3D点云数据处理中的聚类算法总结
1.欧式聚类: 基于点的空间距离(欧几里得距离)来分割点云,将距离较近的点归为同一簇。 欧式聚类需要的参数:邻域半径R,簇的最小点阈值minPts,最大点数阈值maxPts。 实现效率: O(n * log n) 实现…...
配置本机监控
配置本机监控 1、安装zabbix-agent 2、编辑zabbix-agent配置文件 zabbix-agent工作模式: 主动模式 被动模式 这两行配置都是指定监控服务器的地址 被动模式下,zabbix server的地址 主动模式下,zabbix server的地址 指定被监控端的名称&…...
基于python的Flask模块化设计与蓝图的妙用——打造轻量化Web应用
基于python的Flask模块化设计与蓝图的妙用——打造轻量化Web应用 前言 如果你刚开始学习Flask,可能会遇到这样的困惑:当项目功能越来越多,代码都堆在一个.py文件里,不仅难维护,还容易冲突。别担心!本文将用…...
历年云南大学计算机复试上机真题
历年云南大学计算机复试机试真题 在线评测:传送门:pgcode.cn 喝饮料 题目描述 商店里有 n 中饮料,第 i 种饮料有 mi 毫升,价格为 wi。 小明现在手里有 x 元,他想吃尽量多的饮料,于是向你寻求帮助&#x…...
Python 线程池
Python 线程池 flyfish 线程池的概念 线程池是一种多线程处理形式,它预先创建了一定数量的线程,这些线程会被保存在一个线程池中。当有新的任务提交时,线程池会从池中取出一个空闲的线程来执行该任务;若池中没有空闲线程&#…...
【Linux】Bash是什么?怎么使用?
李升伟 整理 什么是 Bash? Bash(Bourne Again Shell)是一种 命令行解释器(Shell),广泛用于 Unix 和 Linux 操作系统。它是 Bourne Shell(sh) 的增强版,提供了更多的功能…...
蓝桥杯day2:解码异或 后的数组
一、题意 未知 整数数组 arr 由 n 个非负整数组成。 经编码后变为长度为 n - 1 的另一个整数数组 encoded ,其中 encoded[i] arr[i] XOR arr[i 1] 。例如,arr [1,0,2,1] 经编码后得到 encoded [1,2,3] 。 给你编码后的数组 encoded 和原数组 arr …...
R语言软件配置(自用)
①输入R: The R Project for Statistical Computing ②点击进入Cran镜像网页,选择清华大学镜像,选择自己合适的版本下载即可(以我电脑windows为例)。 ③点击base或者install R for the first time,然后选择Download R-4.4.3 for windows&…...
基于deepseek的智能语音客服【第二讲】后端异步接口调用封装
本篇内容主要讲前端请求(不包含)访问后端服务接口,接口通过检索知识库,封装提示词,调用deepseek的,并返回给前端的全过程,非完整代码,不可直接运行。 1.基于servlet封装异步请求 为…...
LEDNet总结
LEDNet:联合低光增强和暗光去模糊 1、暗光增强和去模糊可以单独处理,但是合并效果不理想。 研究问题的背景:光线不足 可见度颜色失真 最小快门速度有限 长时间曝光引起运动模糊 低光运动模糊同时存在 存在问题:暗光增强后运动模…...
线性规划的标准形式
标准形式的定义 目标函数:最大化线性目标函数 其中,x 是决策变量向量,c 是目标系数向量。 约束条件:等式形式约束 A x b, 其中,A 是约束系数矩阵,b 是常数项向量。 变量非负约束: 。 因此…...
xxl-job 执行器端服务器的简单搭建
xxl-job 执行器端服务器的简单搭建 先讲一下我们平时怎么使用 xxl-job 的,再引出背后是如何实现的。 我觉得对于一款成功的框架来说,好用,是非常重要的一个特性。 框架要便于接入,便于使用。对于用户来说,不要有太多…...
数字化企业可能会用到的系统有哪些?
你是否也曾像我一样,对这些问题充满疑问: 在企业数字化转型的浪潮中,究竟会涉及哪些系统? 这些系统又分别在何种情境下被投入使用? 如果你也有这样的疑问,那么这篇文章或许能为你答疑解惑。 为了给你一…...
【Linux】:守护进程化
朋友们、伙计们,我们又见面了,本期来给大家带来守护进程相关的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数据结…...
在 web 部署 YOLOv8目标检测(Django+html)
本文介绍如何将自己训练好的模型在网页上进行应用,使用 Django html 进行部署,能够对视频和图像进行识别,并显示到页面上,下面是一个效果: 上 传 和另外 7 个页面 - 个人 - Microsoft Edge 2025-03-13 21-52-06 下面进…...
程序员学商务英语之Making Business Calls
Dialogue-1 Reaching Somebody By Telephone电话找人 A: What do you think the secrect to success is? 你认为成功的秘诀是什么? B: Hold on to your dreams. 坚持你的梦想。 A: May I speak to your boss, Mr. Wong? 请你的老板,王先生接电话?…...
java项目之基于ssm的少儿编程在线培训系统(源码+文档)
项目简介 少儿编程在线培训系统实现了以下功能: 用户信息管理: 用户信息新增 用户信息修改 教师信息管理: 教师信息添加 教师信息删除 教师信息修改 课程信息管理: 课程信息添加 课程信息修改 课程信息删除 课程类型管理&…...
【初学者】Python语言中有没有指针类型?
李升伟 整理 在Python语言中,没有像C或C那样的显式指针类型。Python的设计哲学强调简洁和易读,因此它隐藏了许多底层的细节,包括指针。 不过,Python中的变量可以被视为对对象的引用。当你创建一个对象并将其赋值给一个变量时&am…...
RG-S3760应用协议配置
RG-S3760应用协议配置 1. dhcp 服务配置 提问:如何在设备上开启dhcp 服务,让不同VLAN 下的电脑获得相应的IP 地址? 回答: 步骤一:配置VLAN 网关IP 地址,及将相关端口划入相应的VLAN 中 S3760#con t S…...
C++基础 [八] - list的使用与模拟实现
目录 list的介绍 List的迭代器失效问题 List中sort的效率测试 list 容器的模拟实现思想 模块分析 作用分析 list_node类设计 list 的迭代器类设计 迭代器类--存在的意义 迭代器类--模拟实现 模板参数 和 成员变量 构造函数 * 运算符的重载 运算符的重载 -- 运…...
skywalking微服务链路追踪
是什么? skywalking是一个优秀的国产开源框架,2015年由个人吴晟(华为开发者)开源 , 分布式链路追踪就是将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示,比如各个服务节点…...
K8S学习之基础三十七:prometheus监控node资源
Prometheus v2.2.1 编写yaml文件,包含创建ns、configmap、deployment、service # 创建monitoring空间 vi prometheus-ns.yaml apiVersion: v1 kind: Namespace metadata:name: monitor-sa# 创建SA并绑定权限 kubectl create serviceaccount monitor -n monito…...
Web 小项目: 网页版图书管理系统
目录 最终效果展示 代码 Gitee 地址 1. 引言 2. 留言板 [热身小练习] 2.1 准备工作 - 配置相关 2.2 创建留言表 2.3 创建 Java 类 2.4 定义 Mapper 接口 2.5 controller 2.6 service 3. 图书管理系统 3.1 准备工作 - 配置相关 3.2 创建数据库表 3.2.1 创建用户表…...
1221. 四平方和 -蓝桥杯真题-哈希函数思想
原题链接:1221. 四平方和 - AcWing题库 四平方和定理,又称为拉格朗日定理: 每个正整数都可以表示为至多 44 个正整数的平方和。 如果把 00 包括进去,就正好可以表示为 44 个数的平方和。 比如: 对于一个给定的正整…...
为什么要学习人工智能(AI)?—— 未来已来,AI引领时代变革
未来已来,AI引领时代变革 在这个日新月异的时代,人工智能(AI)正以不可阻挡之势重塑着我们的世界。从教育的深耕细作到科研的突破创新,从行政的效率提升到管理的智慧化转型,AI技术如同一股强大的潮流&#x…...
Markdig:强大的 .NET Markdown 解析器详解
在现代开发中,Markdown 已经成为了一种广泛使用的轻量级标记语言,特别是在文档、博客和内容管理系统中,Markdown 为开发者提供了快速、简洁的格式化文本方式。而在 .NET 生态中,Markdig 是一款非常强大的 Markdown 解析器…...
云计算迁移革命:企业如何摆脱“单一云”锁定,构建自主云未来?
一场价值690亿美元的行业地震 2023年,博通(Broadcom)以690亿美元完成对VMware的收购,这不仅是企业IT历史上的一次天价并购,更在全球云计算市场掀起了一场深远的地震。VMware长期以来是企业数据中心的核心支柱…...
蓝桥杯篇---按键长按与双击
文章目录 前言1. 新增全局变量和宏定义解释1.1宏定义KEY_EVENT_*DEBOUNCE_TIMEHOLD_TIMEDOUBLE_TIMEMULTI_TIME 1.2全局变量Key_ValKey_OldKey_DownKey_Upsys_tickkey_eventkey_pressedkey_press_startkey_last_releaseclick_cnt 2. 定时器初始化(1ms中断࿰…...
created在vue3 script setup中的写法
在 Vue 2 里,created 是一个生命周期钩子函数,会在实例已经创建完成之后被调用,主要用于在实例初始化之后、数据观测和 event/watcher 事件配置之前执行代码。而在 Vue 3 的 <script setup> 语法糖里,不再有像 Vue 2 那样直…...
基于springboot的房屋租赁系统(008)
摘 要 社会的发展和科学技术的进步,互联网技术越来越受欢迎。网络计算机的生活方式逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。互联网具有便利性,速度快,效率高,成本低等优点。 因此,构建符…...
Linux上的`i2c-tools`工具集的编译构建和安装
源码复制到Ubuntu系统中并解压 的i2c-tools工具集的源码百度网盘下载链接: https://pan.baidu.com/s/1XNuMuT1auT1dMzYo3LAFmw?pwdi6xe 终端进入源码目录 cd /home/book/mybuild/i2c-tools-4.2执行编译构建命令 运行下面的命令进行编译构建 make CC${CROSS_COM…...
java项目之基于ssm的社区流浪动物救助领养系统
项目简介 社区流浪动物救助领养系统实现了以下功能: 本社区流浪动物救助领养系统分为管理员还有用户两个权限,管理员可以管理用户的基本信息内容,可以管理回访信息以及回访的租赁信息,能够与用户进行相互交流等操作,…...
网络空间安全(34)安全防御体系
前言 安全防御体系是一个多层次、多维度的系统,旨在保护组织或个人的信息资产免受各种网络攻击和威胁。 一、技术层面 网络边界防御 防火墙:部署在网络边界,通过设定规则允许或阻止特定流量的进出,保护内部网络不受外部攻击。入侵…...
《Linux 网络架构:基于 TCP 协议的多人聊天系统搭建详解》
一、系统概述 本系统是一个基于 TCP 协议的多人聊天系统,由一个服务器和多个客户端组成。客户端可以连接到服务器,向服务器发送消息,服务器接收到消息后将其转发给其他客户端,实现多人之间的实时聊天。系统使用 C 语言编写&#x…...
知识蒸馏:让大模型“瘦身”的魔法
知识蒸馏:让大模型“瘦身”的魔法 什么是蒸馏模型?AI界的“知识浓缩术”核心定义传统训练 vs 知识蒸馏关键优势 DeepSeek的蒸馏“三步魔法”骨架提取——搭建“迷你版大脑”知识灌注——模仿教师的“思考过程”微调优化——针对场景“查漏补缺” DeepSee…...
MySQL数据库精研之旅第一期:开启数据管理新旅程
专栏:MySQL数据库成长记 个人主页:手握风云 目录 一、数据库简介 1.1. 数据库的概念 1.2. 数据库和数据结构的关系 1.3. 主流数据库 1.3.1. 关系型数据库 1.3.2. 非关系型数据库 1.4. 关系型数据库的概念 二、MySQL配置 2.1. mysqld服务端程序 …...
Linux复习——基础IO,认识文件描述符、软硬件链接
1.复习C文件接口 1.1 fopen FILE *fopen(const char *path, const char *mode); path:带路径的文件名称(待打开的文件) mode: r:以可读方式打开,不可写,文件不存在,则报错 r&…...
【Java集合夜话】第1篇:拨开迷雾,探寻集合框架的精妙设计
欢迎来到Java集合框架系列的第一篇文章!🌹 本系列文章将以通俗易懂的语言,结合实际开发经验,带您深入理解Java集合框架的设计智慧。🌹 若文章中有任何不准确或需要改进的地方,欢迎大家指出,让我…...
Prometheus使用
介绍:Prometheus 是一个开源的 监控与告警系统,主要用于采集和存储时间序列数据(Time Series Data) Prometheus的自定义查询语言PromQL Metric类型 为了能够帮助用户理解和区分这些不同监控指标之间的差异,Prometheu…...
Java学习打卡-Day19-Set、HashSet、LinkedHashSet
Set 接口 无序(添加和取出顺序不一致)(但取出顺序固定)。没有索引。不允许重复,所以最多一个null。遍历方式 迭代器增强for循环不能使用普通for循环索引方式。 HashSet 实现了Set接口,具有相应特征。底…...
冯・诺依曼架构深度解析
一、历史溯源:计算机科学的革命性突破 1.1 前冯・诺依曼时代 在 1940 年代之前,计算机领域呈现 "百家争鸣" 的格局: 哈佛 Mark I(1944):采用分离的指令存储与数据存储ENIAC(1946&a…...