Spring MVC常见面试题
Spring MVC简介
Spring MVC框架是以请求为驱动,围绕Servlet设计,将请求发给控制器,然后通过模型对象,分派器来展示请求结果视图。简单来说,Spring MVC整合了前端请求的处理及响应。
Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
Spring MVC优缺点
Spring MVC具有以下优点:
(1) 可以支持各种视图技术,而不仅仅局限于JSP。
(2) 可以和 Spring 框架无缝集成,这是其它 Web 框架所不具备的。
(3) 清晰的角色分配:前端控制器(DispatcherServlet),请求处理器映射(HandlerMapping),处理器适配器(HandlerAdapter),视图解析器(ViewResolver)。
(4) 支持各种请求资源的映射策略,支持RESTful 编程风格的请求。
(5) 采用了灵活的配置方法,可以通过XML配置或注解的方式实现。
(6) Spring MVC中的Controller类是POJO(纯Java对象),它们的测试很容易,可以用JUnit等测试框架进行测试。
(7) 可以与其他框架集成,如OpenAPI(Swagger),可以为API文档和开发者交互提供支持。
Spring MVC也存在以下缺点:
(1) Spring MVC 与 Servlet API 耦合严重,难以脱离容器独立运行。
(2) 与其他框架相比,Spring MVC的学习曲线相对较陡峭,需要花费一定的时间学习和理解其工作原理和机制。
Spring MVC执行流程简介
Spring MVC执行流程如下:
(1) 用户通过浏览器将HTTP请求发送到前端控制器 DispatcherServlet;
(2) DispatcherServlet 收到请求后,调用处理器映射器HandlerMapping。HandlerMapping根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器),并返回给DispatcherServlet。也就是说,uri和controller的映射是统一放在HandlerMapping中。
(3) DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter。
(4) HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作。Spring 中的处理器的实现多变,比如用户的处理器可以实现 Controller 接口或者 HttpRequestHandler 接口,也可以用 @RequestMapping 注解将方法作为一个处理器等,这就导致 Spring MVC 无法直接执行这个处理器。所以这里需要一个处理器适配器,由它去执行处理器。简言之,因为Handler格式不固定的,所以在处理请求时需要HandlerAdapter做适配。然后,HandlerAdapter调用Handler。需要说明的是,这里的Handler就是Controller。
(5) HandlerAdapter回去Handler执行结果并返回ModelAndView给DispatcherServlet。
(6) DispatcherServlet将ModelAndView传给ViewReslover视图解析器。ViewReslover解析后返回具体View
(7) DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
(8) View向浏览器返回HTTP响应。
DisPatcherServlet 前端控制器
Spring MVC核心组件。用户在浏览器输入url发起请求后,首先会到达DisPatcherServlet,由它来调用其他组件来配合工作的完成。DisPatcherServlet的存在大大降低了组件之间的耦合性。
HandlerMapping 处理器映射器
记录url与Handler的映射,方式有注解、XML配置等。
HandlerAdapter 处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
HandLer 处理器
也称控制器(就是日常开发的Controller,也即业务代码)。对用户的请求进行处理。Spring用一个非常抽象的方式实现了一个控制层,允许用户创建多种用途的控制器。
注意,Handler是单例模式,所以在多线程访问的时候,可能存在线程安全问题。注意,不建议使用多例模式,因为随着请求的增加,会频繁的创建对象。对于可能存在的多线程安全问题,尽量在设计的时候,将控制器定义成无状态的。如果确实需要维持状态,推荐使用ThreadLocal隔离不同线程。
ViewResolver 视图解析器
ViewResolver负责解析view视图,并进行渲染(将Model数据填充到View),将处理结果通过页面展示给用户看。
View 视图
View是一个接口,实现类支持不同的View类型(JSP、Freemarker等)。一般情况下需要通过页面标签或者页面模板技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
过滤器(Filter)
Spring Boot中过滤器是基于 Servlet 过滤器实现。Servlet 过滤器是可用于 Servlet 编程的 Java 类,有以下目的:
(1) 在客户端的请求访问后端资源之前,拦截这些请求。
(2) 在服务器的响应发送回客户端之前,处理这些响应。
Filter是在Servlet 2.3之后增加的新功能。过滤器是以一种组件的形式绑定到Web应用程序当中,当存在多个过滤器时,过滤器采用了“链式”方式处理。
Spring Boot中使用过滤器
过滤器一般用于完成通用的操作,如:登录验证、统一编码处理、敏感字符的过滤等。
(1) 实现Filter接口
/*** @Author: courage007*/
public class CustomFilter implements Filter {private String url;/*** 可以初始化Filter在web.xml里面配置的初始化参数* filter对象只会创建一次,init方法也只会执行一次。* @param filterConfig* @throws ServletException*/@Overridepublic void init(FilterConfig filterConfig) throws ServletException {this.url = filterConfig.getInitParameter("URL");System.out.println("init() method. URL is: " + this.url);}/*** 每一次请求资源时,url匹配后会执行。* 主要的业务代码编写方法* @param servletRequest* @param servletResponse* @param filterChain* @throws IOException* @throws ServletException*/@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("before doFilter() method");filterChain.doFilter(servletRequest, servletResponse);System.out.println("after doFilter() method");}/*** 在销毁Filter时自动调用 * 如果服务器是正常关闭,则会执行destroy方法。只执行一次。 * 注意,不是方法调用完毕后执行*/@Overridepublic void destroy() {System.out.println("destroy() method" );}
}
(2) 注册过滤器到Spring容器
完成过滤器的定义后,接下来就是将过滤器自动注入到Spring容器中。
两种实现方式:(a) 使用@WebFilter注解+@ServletComponentScan注解;(b)实例化FilterRegistrationBean。
- (a) 使用@WebFilter注解 + @ServletComponentScan注解
首先使用@WebFilter注解标注过滤器实现。其中urlPatterns用于指明过滤器针对的url。如果一个url上存在多个过滤器,还需使用指定过滤器的优先级(使用@Order注解、实现Ordered接口、配置文件指定优先级等)
/*** @Author: courage007*/
@Order(1)
@WebFilter(filterName = "customFilter",urlPatterns = "/*" ,initParams = { @WebInitParam(name = "URL", value = "http://localhost:8080")})
public class CustomFilter implements Filter {// 实现
}
然后,添加@ServletComponentScan注解。这样在启动的过程中,会自动扫描使用@WebFiter标注的类到Spring容器。
@SpringBootApplication
@ServletComponentScan
public class SpringDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringDemoApplication.class, args);}
}
- (b) 实例化FilterRegistrationBean
FilterRegistrationBean 是Spring Boot提供的接口。推荐使用这种方式使用过滤器。相比第一种方式,这种方式将过滤器的使用与过滤器的定义分离,有利于更好复用过滤器。
/*** @Author: courage007*/
@Configuration
public class WebConfig {//Register Filter@Beanpublic FilterRegistrationBean<CustomFilterRegisteredBySpringBootBean> registerCustomFilter() {FilterRegistrationBean<CustomFilterRegisteredBySpringBootBean> filterRegBean = new FilterRegistrationBean<>();filterRegBean.setFilter(new CustomFilterRegisteredBySpringBootBean());// 指定匹配urlfilterRegBean.addUrlPatterns("/*");// 指定顺序filterRegBean.setOrder(2);return filterRegBean;}
}
使用过滤器处理CORS问题
过滤器支持处理CORS(Cross-Origin Resource Sharing,跨源资源共享)问题,示例代码如下:
@Component
public class CORSFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletResponse res = (HttpServletResponse) response;res.addHeader("Access-Control-Allow-Credentials", "true");res.addHeader("Access-Control-Allow-Origin", "*");res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH");res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {response.getWriter().println("ok");return;}chain.doFilter(request, response);}@Override public void destroy() {}@Override public void init(FilterConfig filterConfig) throws ServletException {}
}
需要说明的是,过滤器只是处理跨域访问问题的一种方式,Spring MVC也提供了@CrossOrigin注解等方式,还需根据自己的业务场景合理选择。
拦截器(Interceptor)
拦截器依赖于Spring MVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。一般简单的功能又是通用的,且每个请求都要去处理的,比如判断token是否失效可以使用Spring MVC的HandlerInterceptor。对于复杂的,比如缓存,需要高度自定义的就用Spring AOP方式处理。对于Service层更多用Spring AOP,controller层有必要用到request和response时,可以用拦截器。
拦截器(Interceptor)和过滤器(Filter)都是AOP编程思想的实现,主要的不同有以下几点:
(1) 实现原理不同。
Interceptor是基于java的反射机制的,而Filter是基于函数回调。
(2) 使用规范不同。
Filter是Servlet规范规定的,是Servlet容器支持的。而Interceptor是Spring框架规范的,是Spring容器支持的。
(3) 作用范围不同。
Interceptor只能对Controller请求起作用,而Filter则可以对几乎所有的请求起作用。如对其他的一些比如直接访问静态资源的请求,则没办法进行拦截处理。Interceptor可以访问Controller上下文、值栈里的对象,而Filter不能访问。在Controller的生命周期中,Interceptor可以多次被调用,而Filter只能在容器初始化时被调用一次。
(4) 使用的资源不同。
Interceptor也是一个Spring组件,归Spring管理,因此能使用Spring里的任何资源、对象,如Service对象、数据源、事务管理等。而Filter则不能。
(5) 使用深度不同。
Filter只在Servlet前后起作用。而Interceptor能够深入到方法前后、抛出异常前后等。
Spring中开发优先使用拦截器。如果拦截器无法满足需求(如非Controller场景下方法调用),则再尝试使用过滤器。
Spring MVC中拦截器的使用
Spring MVC中的Interceptor拦截请求是通过HandlerInterceptor来实现的。在Spring MVC中定义一个拦截器主要有两种方式,第一种方式是要实现HandlerInterceptor接口,或者是其它实现了HandlerInterceptor接口的类,比如HandlerInterceptorAdapter。第二种方式是实现WebRequestInterceptor接口,或者其它实现了WebRequestInterceptor的类。这里以HandlerInterceptor接口为例,介绍如下实现拦截器。
(1) 实现Interceptor接口
示例代码如下:
/*** 自定义拦截器** @Author: courage007*/
public class CustomInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("previous handle");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("post handle");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception {System.out.println("after Completion");}
}
自定义拦截器实现了HandlerInterceptor接口。该接口声明了三个方法:
(a) preHandle:预处理回调方法,该方法会在控制器方法前执行。其返回值表示是否中断后续操作。当其返回值为true时,表示继续向下执行(如调用下一个拦截器或处理器);当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等),此时需要通过response来产生响应。
(b) postHandle:后处理回调方法,该方法会在控制器方法调用之后。可以通过此方法对请求域中的模型和视图做出进一步的修改。在该阶段可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
© afterCompletion:该方法会在整个请求完成,即视图渲染结束之后执行。整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
(2) 注册已实现Interceptor接口
示例代码如下:
/*** 实现WebMvcConfigurer接口** @Author: courage007*/
@Configuration
public class CustomInterceptorConfig implements WebMvcConfigurer { /*** 重写添加拦截器方法** @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new CustomInterceptor()).addPathPatterns("/**").order(1);//指定执行顺序,数值越小越优先}
}
多个拦截器的处理
Spring MVC支持在一个uri中定义多个拦截器。多个拦截器使用使用order接口设置优先级。多个拦截器的执行顺序基于"职责链模式"执行。以有两个拦截器为例,拦截器中方法的先后执行顺序如下:
监听器(Listener)
监听器就是一个实现特定接口的程序,这个程序专门用于监听一个对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。
监听器使用
在Spring Boot 应用中,监听器既可以使用Servlet容器的,也可以Spring的。
Servlet提供监听器使用
Servlet中监听器是在application,session,request三个对象创建、销毁或往其中添加修改删除属性时自动执行代码的功能组件。其中application对象相关的有ServletContextListener和ServletContextAttributeListener,session对象相关的有HttpSessionListener和HttpSessionAttributeListener,request对象相关的有ServletRequestListener和ServletRequestAttributeListener。这里以ServletContextListener为例,说明下Servlet监听器的使用。
- (1) 实现ServletContextListener接口
除了实现ServletContextListener接口外,还需使用@WebListener标注类。
/*** @Author: courage007*/
@WebListener
public class CustomServletRequestListener implements ServletRequestListener {@Overridepublic void requestInitialized(ServletRequestEvent servletRequestEvent) {System.out.println("---------------------------->请求创建");}@Overridepublic void requestDestroyed(ServletRequestEvent servletRequestEvent) {System.out.println("---------------------------->请求销毁");}
}
- (2) 使用@ServletComponentScan注解
在Spring Boot启动使用或在一个配置类上添加@ServletComponentScan注解,这样就可以将@WebListener的Bean自动添加到Spring容器中。
Spring 提供监听器使用
Spring Boot事件监听的流程如下:(1) 自定义事件,一般是继承ApplicationEvent抽象类;(2)定义事件监听器,一般是实现ApplicationListener接口;(3) 注册监听器,启动的时候,需要把监听器加入到spring容器中;(4)发布事件。
- (1) 自定义事件
创建一个自定义事件时,只需要继承ApplicationEvent抽象类。
/*** @Author: courage007*/
public class CustomSpringApplicationEvent extends ApplicationEvent {public CustomSpringApplicationEvent(Object source) {super(source);}
}
- (2) 定义事件监听器并指定事件
定义事件监听器用于响应绑定的事件。自定义事件监听器实现ApplicationListener。
/*** @Author: courage007*/
public class CustomSpringApplicationListener implements ApplicationListener<CustomSpringApplicationEvent> {@Overridepublic void onApplicationEvent(CustomSpringApplicationEvent customSpringApplicationEvent) {System.out.println("======spring监听自定义的事件======");System.out.println(customSpringApplicationEvent.getClass());}
}
- (3) 注册事件监听器
如果需要事件监听器生效,还需将事件监听器注册到Spring中。常见的事件监听器的注册方法有四种:(a) SpringApplication.addListeners 添加监听器;(b) 把监听器纳入到spring容器中管理;© 使用context.listener.classes配置项配置;(d) 使用@EventListener注解。
(a) SpringApplication.addListeners 添加监听器
@SpringBootApplication
@ServletComponentScan
public class SpringDemoApplication {public static void main(String[] args) {SpringApplication application = new SpringApplication(SpringDemoApplication.class);// 配置事件监听器application.addListeners(new CustomSpringApplicationListener());ConfigurableApplicationContext context = application.run(args);}
}
(b) 把监听器纳入到Spring容器中管理
如使用@Component注解将监听器注册到Spring容器中。
@Component
public class CustomSpringApplicationListener implements ApplicationListener<CustomSpringApplicationEvent> {@Overridepublic void onApplicationEvent(CustomSpringApplicationEvent customSpringApplicationEvent) {System.out.println("======spring监听自定义的事件======");System.out.println(customSpringApplicationEvent.getClass());}
}
© 使用context.listener.classes配置项
在配置文件(application.properties)中添加自定义事件监听器。
context.listener.classes=com.github.courage007.springdemo.listener.CustomSpringApplicationListener
(d) 使用@EventListener注解
还可以在方法上面加入@EventListener注解,且该类需要纳入到spring容器中管理。
/*** @Author: courage007*/
@Component
public class AnnotationEventListener {@EventListenerpublic void registerCustomSpringApplicationEvent(CustomSpringApplicationEvent customSpringApplicationEvent) {System.out.println(customSpringApplicationEvent.getClass());}
}
- (4) 发布事件
发布事件时,既可直接使用ConfigurableApplicationContext实例发布,也可以使用ApplicationContext实例或ApplicationEventPublisher实例发布。
@SpringBootApplication
@ServletComponentScan
public class SpringDemoApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(SpringDemoApplication.class, args);// 发布事件context.publishEvent(new CustomSpringApplicationEvent(new Object()));}
}
多个监听器执行顺序
一个事件上可能包含多个监听器,有时需要保证这些监听器的执行顺序。可以使用 @Order注解来标记事件的监听执行顺序,对于异步的监听器,只保证按顺序将监听器丢入进线程池。
监听器异步执行
默认情况,监听器是同步的,也就是说只有当监听器的处理方法执行完成后,才会执行剩下的步骤。对于耗时很长且不影响后续业务的方法(如:将事件记录到数据库中),可以使用异步的方式处理事件。
@Async
@EventListener
public void ApiEventListener(ApiEvent event){System.out.println("收到Api调用事件,内容 {} ", event.getContent());
}
使用 @Async 标记事件处理器为异步方法。默认情况下,Spring没有开启Async,使用 @EnableAsync 注解使 @Async 有效。如果默认的线程策略不能满足需求,还需指定线程池。
Spring MVC使用
Spring MVC的控制器(Handler)是不是单例模式?
是单例模式,所以在多线程访问的时候,可能存在线程安全问题。注意,不建议使用多例模式,因为随着请求的增加,会频繁的创建对象。对于可能存在的多线程安全问题,尽量在设计的时候,将控制器定义成无状态的。如果确实需要维持状态,推荐使用ThreadLocal隔离不同线程。
Spring MVC常用的注解有哪些?
@Controller和@RestController
在Spring MVC 中可以使用@Controller标记一个类的方式,完成Controller的定义。此外,为了简化使用,还可以使用@RestController注解。@RestController注解相当于@ResponseBody + @Controller合在一起的作用。
Controller注解下,Controller中的方法可以返回JSP、html、JSON、XML等各种类型的数据,使用@ResponseBody注解后,无法返回JSP、HTML等视图相关的数据,只能返回JSON、XML等视图无关的数据。
简单来说,如果需要返回JSON、XML等视图无关的数据,如果使用@Controller注解,还需额外补充@ResponseBody注解,如果使用@RestController注解,则无需额外的操作。
@RestController注解定义如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {@AliasFor(annotation = Controller.class)String value() default "";
}
可以看到@RestController是一个组合注解,组合了@Controller注解和@ResponseBody注解。
@RequestMapping 和 @GetMapping和@PostMapping和@PutMapping和@DeleteMapping和@PatchMapping
@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性,下面分成三类进行说明:
(1) value, method
value:指定请求的实际地址,指定的地址可以是URI Template 模式。
method:指定请求的method类型,GET、POST、PUT、DELETE等。
(2) consumes,produces
consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html。
produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。
(3) params,headers
params:指定request中必须包含某些参数值,才让该方法处理该请求。
headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping 都是在 @RequestMapping 中使用 method 属性来声明 HTTP 请求所使用的方法类型。对应关系如下:
在日常的开发中,推荐使用@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping等注解,除非无法满足需要,再使用@RequestMapping注解。
@PathVariable和@RequestParam
@PathVariable用于将URL中的值绑定到参数上。具体来说,首先在@RequestMapping的value中使用URI template({变量名}),然后在@RequestMapping注解方法的需要绑定的参数前,使用@PathVariable指定变量名(如果变量名和参数名一致也可以不指定),这样URL中的值就绑定到参数上。使用示例如下:
@RestController
@RequestMapping("/testPathVariable")
public class TestPathVariable {/** URI模板指定了一个变量名为id的变量,当控制器处理请求时会将 id 替换为正确的值** 若请求为 testPathVariable/user/29,则uid=29,输出29** */@GetMapping("/user/{id}")public void testPathVariable(@PathVariable("id") String userId) {System.out.println(userId);return;}
}
@RequestParam注解用于将指定的请求参数赋值给方法中的形参。有三个属性:
(1) value:请求参数名
(2) required:是否必需,默认为 true,即 请求中必须包含该参数,如果没有包含,将会抛出异常(可选配置)
(3) defaultValue:默认值,如果设置了该值,required 将自动设为 false,即使required设置为true(可选配置)
使用示例如下:
@RestController
@RequestMapping("/testRequestParam")
public class TestRequestParam {@GetMapping("/user")public void testRequestParam(@RequestParam(value="name") String userName) {System.out.println(username);return;}
}
这个时候,如果请求"/testRequestParam/user?name=foo",就可将请求参数赋值给方法中的形参。
@ResponseBody
@ResponseBody 注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
注意,这里返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
@ControllerAdvice和@ExceptionHandler
Spring 提供了使用@ControllerAdvice处理异常的方法。开发者可以通过实现一个 ControlerAdvice 类,来处理控制器类抛出的所有异常。其中@ExceptionHandler用来指定具体的异常类型。使用示例如下:
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public ModelAndView customException(Exception e) {ModelAndView mv = new ModelAndView();mv.addObject("message", e.getMessage());mv.setViewName("myerror");return mv;}
}
参考
https://docs.spring.io/spring-framework/docs/4.2.4.RELEASE/spring-framework-reference/html/mvc.html Spring Web MVC framework
https://www.w3schools.cn/springmvc/index.html Spring MVC 教程
https://docs.spring.io/spring-framework/reference/web/webmvc.html Spring Web MVC
https://blog.csdn.net/thinkwon/article/details/104397427 Spring MVC面试题
https://www.w3cschool.cn/servlet/servlet-intro.html Servlet学习网站
https://blog.csdn.net/weixin_65950231/article/details/130499706 深入了解SpringMVC框架,探究其优缺点、作用以及使用方法
https://blog.csdn.net/weixin_43888891/article/details/108479214 什么是SpringMVC,SpringMVC有什么优缺点
https://blog.csdn.net/fuzhongmin05/article/details/81585672 从MVC到前后端分离
https://www.jianshu.com/p/8a20c547e245 SpringMVC执行流程及工作原理
https://www.cnblogs.com/lifullmoon/p/14137467.html Spring MVC 源码分析 - HandlerAdapter 组件(一)之 HandlerAdapter
https://www.cnblogs.com/shuaifing/p/8119664.html @Controller和@RestController的区别?
https://zhuanlan.zhihu.com/p/168017369 说说Spring中的 @RestController 和 @Controller
https://blog.csdn.net/demo_yo/article/details/123608034 @RequestMapping 注解使用技巧(完整详解)
https://www.cnblogs.com/FFFFF/p/4624140.html SpringMVC(三)@PathVariable
https://www.cnblogs.com/tomingto/p/11377138.html @RequestParam注解的详细介绍
https://blog.csdn.net/qq_44543508/article/details/101026720 @RequestParam注解详细使用
https://www.jianshu.com/p/2dbb585ffb1c Spring Boot使用过滤器Filter
https://www.jdon.com/springboot/spring-filter.html
https://www.cnblogs.com/jobbible/p/17546547.html SpringBoot 如何处理 CORS 跨域?
https://www.jianshu.com/p/2dbb585ffb1c Spring Boot使用过滤器Filter
https://blog.csdn.net/heweimingming/article/details/79993591 spring boot 过滤器、拦截器的区别与使用
https://blog.csdn.net/cold___play/article/details/103295685 SpringMVC–拦截器的两种实现方式(HandlerInterceptor、WebRequestInterceptor)及拦截器的执行流程(单个、多个)
https://my.oschina.net/centychen/blog/3018007 SpringBoot 入坑指南之六:使用过滤器或拦截器
http://www.51gjie.com/javaweb/872.html Servlet Listener监听器详解(原理)
https://www.jianshu.com/p/5f57f2aa5e2c Springboot事件监听
https://blog.csdn.net/m0_38075425/article/details/81164501 springboot的监听器Listener
https://www.jianshu.com/p/5f57f2aa5e2c Springboot事件监听
https://blog.csdn.net/weixin_41490593/article/details/97132317 springboot中监听器使用
https://www.jianshu.com/p/dcd956169910 Spring事件监听
https://blog.csdn.net/qq_30211955/article/details/86709873 Spring Boot监听事件同步和异步使用
https://my.oschina.net/u/3245438/blog/2961234 SpringBoot > 启动异步事件监听机制
相关文章:

Spring MVC常见面试题
Spring MVC简介 Spring MVC框架是以请求为驱动,围绕Servlet设计,将请求发给控制器,然后通过模型对象,分派器来展示请求结果视图。简单来说,Spring MVC整合了前端请求的处理及响应。 Servlet 是运行在 Web 服务器或应用…...

Java基础面试题精选:深入探讨哈希表、链表和接口等
目录 1.ArrayList和LinkedList有什么区别?🔒 2.ArrayList和Vector有什么区别?🔒 3.抽象类和普通类有什么区别?🔒 4.抽象类和接口有什么区别?🔒 5.HashMap和Hashtable有什么区别&…...

Spark计算框架
Spark计算框架 一、Spark概述二、Spark的安装部署(安装部署Spark的Cluster Manager-资源调度管理器的)1、Spark的安装模式1.1、Spark(单节点)本地安装1.2 Spark的Standalone部署模式的伪分布式安装1.3Spark的YARN部署模式1.4Spark…...

mybatis缓存源码分析
mybatis缓存源码分析 背景 在java程序与数据库交互的过程中永远存在着性能瓶颈,所以需要一直进行优化.而我们大部分会直接将目标放到数据库优化,其实我们应该先从宏观上去解决问题进而再去解决微观上的问题.性能瓶颈体现在什么地方呢?第一网络通信开销,网络数据传输通信.…...

机房小探索
现在连不了NJU-WLAN,怀疑是没有插网线,可以考虑买个USB转网卡的接口,但是我的电脑只有两个USB插口,还不知道版本是什么,之后还想连鼠标跟键盘外设呢。只能连NJU_SWI_WLAN,合理怀疑是Software Internet的缩写…...

PHP8的类与对象的基本操作之成员变量-PHP8知识详解
成员变量是指在类中定义的变量。在类中可以声明多个变量,所以对象中可以存在多个成员变量,每个变量将存储不同的对象属性信息。 例如以下定义: public class Goods { 关键字 $name; //类的成员变量 }成员属性必须使用关键词进行修饰…...

phpstudy2016 RCE漏洞验证
文章目录 漏洞描述漏洞验证 漏洞描述 PHPStudyRCE(Remote Code Execution),也称为phpstudy_backdoor漏洞,是指PHPStudy软件中存在的一个远程代码执行漏洞。 漏洞验证 打开phpstudy2016,用bp自带的浏览器访问www目录下…...

【QT】QT事件Event大全
很高兴在雪易的CSDN遇见你 ,给你糖糖 欢迎大家加入雪易社区-CSDN社区云 前言 本文分享QT中的事件Event技术,主要从QT事件流程和常用QT事件方法等方面展开,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞关注,小易…...

华为云云耀云服务器L实例评测|华为云上安装etcd
文章目录 华为云云耀云服务器L实例评测|华为云上安装etcd一、什么是etcd官方硬件建议 二、华为云主机准备三、etcd安装1. 安装预构建的二进制文件2. 从源代码构建 四、etcd服务注册与发现1. 配置etcd2. 使用systemctl 管理启动etcd服务3. 注册服务4. 发现服务 五、其…...

RDLC动态设置整个表格是否显示
最近有个新的需求:使用RDLC打印,当数据库中能查出数据时,显示表格。没有数据时,不显示整个表格。 1.首先在RDLC中选中表格的任意一列,右键Tablix属性 2.Tablix属性中选中可见性》选中基于表达式显示或隐藏(E)并点开右…...

xp 系统 安装 python 2.7 ide pip
1 下载python http://www.python.org/ftp/python/ python-2.7.2.msi 安装完需要设置环境变量 2 下载 setuptools setuptools-0.6c11.win32-py2.7.exe https://pypi.tuna.tsinghua.edu.cn/simple/setuptools/ 3 下载 pip ,python 2.7 最高支持 pip 20.3.4 https:…...

RabbitMQ生产故障问题分析
1. 问题引发 由某个服务BI-collector-xx队列出现阻塞,影响很整个rabbitMQ集群服务不可用,多个应用MQ生产者服务出现假死状态,系统影响面较广,业务影响很大。当时为了应急处理,恢复系统可用,运维相对粗暴的把…...

12大常用自动化测试工具,请记得转发收藏!
常用自动化测试工具 1、Appium AppUI自动化测试 Appium 是一个移动端自动化测试开源工具,支持iOS 和Android 平台,支持Python、Java 等语言,即同一套Java 或Python 脚本可以同时运行在iOS 和Android平台,Appium 是一个C/S 架构&…...

Android Studio 的aapt2.exe在哪个目录下
一般在:C:\Users\admin\AppData\Local\Android\Sdk\build-tools\30.0.2(不一定是30.0.2,这个得看你的版本) 怎么找: 1.打开Android studio...

【pytest】conftest.py使用
1. 创建test_project 目录 test_project/sub/test_sub.py def test_baidu(test_url):print(fsub {test_url}) test_project/conftest.py 设置钩子函数 只对当前目录 和子目录起作用 import pytest #设置测试钩子函数 pytest.fixture() def test_url():return "http…...

SpringBoot集成Prometheus实现监控
SpringBoot配置Prometheus pom.xml 引入监控以及prometheus依赖 <dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId></dependency><dependency><groupId>org.springfram…...

【操作系统笔记十】缓存一致性
CPU 核心之间数据如何传播 高速缓存中的值被修改了,那么怎么同步到内存中呢? ① 写直达(Write-Through)② 写回(Write-Back) 写直达(Write-Through) 简单,但是很慢&am…...

lS1028 + 六网口TSN 硬交换+QNX/Linux实时系统解决方案在轨道交通系统的应用
lS1028 六网口TSN 硬交换QNX/Linux实时系统解决方案在轨道交通系统的应用 以下是在轨道交通应用的实物: CPUNXP LS1028A架构双核Cortex-A72主频1.5GHzRAM2GB DDR4ROM8GB eMMCOSUbuntu20.04供电DC 12V工作温度-40℃~ 80℃ 功能数量参数Display Port≤1路支持DP1.3…...

实现字符串反转函数
实现字符串反转 #include <stdio.h> #include <string.h>void reverse(char *str) {int len = strlen(str);...

抽检监测实施
声明 本文是学习GB-T 42893-2023 电子商务交易产品质量监测实施指南. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件提供了开展电子商务交易的有形产品质量监测的总则,监测准备、监测实施、监测效果评价 与反馈等过程指导…...

C++中的静态库与动态库
文章目录 静态库构建静态库 动态库构建动态库 它们的不同参考文章 单独提这个 库,我想我们在coding过程中,可能也会知道一两个词,如 标准库、xx库等。库作为一组已编写好、组织好的、可复用的资源接口,可以被用于其他程序。很不…...

UGUI 绘制线段
描述 点击鼠标左键在屏幕上绘制线段 准备 VertexHelper 网格绘制工具类向量、叉乘RectTransformUtility.ScreenPointToLocalPointInRectangleSetVerticesDirtyOnPopulateMesh 思路 鼠标按下,记录线段起点;鼠标持续按下,记录鼠标当前帧的…...

详细学习Mybatis(2)
详细学习Mybatis(2) 一、Mybatis核心配置文件详细解释1.1 environment(环境)1.2 事务管理器(transactionManager)1.3、dataSource(数据源)1.4、properties1.5、mapper 一、Mybatis核…...

LinkedList与链表
目录 一、Arraylist的缺陷 二、链表 2.1 链表的概念和结构 2.2 链表的实现 三、链表面试题 3.1 删除链表中所有值为val的节点 3.2 反转一个单链表 3.3 链表的中间节点 3.4 将有序链表合并 3.5 输出倒数第k个节点 3.6 链表分割 3.7 链表的回文结构 3.8 找两个链表的公共节…...

纳米软件芯片自动化测试系统测试电源芯片稳压反馈的方法
在一些电源芯片或稳压芯片中,通常内部都会有稳压反馈电路,这些电路可以将输入电压通过内部调整后输出一个稳定的输出电压,以满足电路中的稳定电源需求。也就是说芯片的稳压反馈就是内部稳压反馈电路中的电压。 芯片稳压反馈原理介绍 稳压反馈…...

微信小程序之项目基本结构、页面的基础及宿主环境
文章目录 前言一、基本组成结构基本组成小程序页面的组成部分JSON配置文件作用 二、页面基础pagesWXML和HTML的区别WXSS和CSS的区别小程序中js文件分类 三、小程序宿主环境总结 前言 微信小程序的项目基本结构、页面的基础及宿主环境 一、基本组成结构 基本组成 新建一个微信…...

C/C++鸡尾酒疗法 2023年5月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析
目录 C/C鸡尾酒疗法 一、题目要求 1、编程实现 2、输入输出 二、解题思路 1、案例分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 C/C鸡尾酒疗法 2020年6月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 鸡尾酒疗法,原指“高效抗…...

人工智能及大模型简介
一、人工智能介绍 人工智能(Artificial Intelligence),英文缩写为AI。它试图赋予机器智能的能力,使它们能够像人类一样思考、学习和做出决策。它的核心要素是数据、模型和算力。 数据是人工智能的基础,数据的质量和…...

基于springboot消防员招录系统
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...

手把手教你制作登录、注册界面 SpringBoot+Vue.js(cookie的灵活运用,验证码功能)
一、用户登录界面 实现思路:用户在界面输入用户名和密码传入变量。用post方法传输到后端,后端接收整个实体对象。将用户名提取出。在dao层方法中通过select注解查询,返回数据库对应的数据对象。如果返回为空则return false。不为空则通过比对…...