聊聊 SpringMVC 是如何工作的?

SpringMVC原理(不使用注解) 本篇博客写写springMVC的工作原理及回顾MVC 新手开车,请系好安全带 1.来上官方文档 老版本的文档:搓搓这里 2.回顾MVC 职责分析: 2.1 Controller:控制器 取得表单数据 调用业务逻辑 转向指定的页面 2.2 Model:模型 业务逻辑 保存数据的状态 2.3 View:视图 显示页面 3.SpringMVC小案例 spring mvc本质上是servlet 围绕DispatcherServlet 3.1 在web.xml配置Dispatcher <. 阅读详情

文章会比较长,建议收藏,或关注公众号:Hoeller

SpringMVC的作用毋庸置疑,虽然我们现在都是用SpringBoot,但是SpringBoot中仍然是在使用SpringMVC来处理请求。

我们在使用SpringMVC时,传统的方式是通过定义web.xml,比如:

<web-app>

	<servlet>
		<servlet-name>app</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>app</servlet-name>
		<url-pattern>/app/*</url-pattern>
	</servlet-mapping>

</web-app>
复制代码

我们只要定义这样的一个web.xml,然后启动Tomcat,那么我们就能正常使用SpringMVC了。

SpringMVC中,最为核心的就是DispatcherServlet,在启动Tomcat的过程中:

  1. Tomcat会先创建DispatcherServlet对象
  2. 然后调用DispatcherServlet对象的init()

而在init()方法中,会创建一个Spring容器,并且添加一个ContextRefreshListener监听器,该监听器会监听ContextRefreshedEvent事件(Spring容器启动完成后就会发布这个事件),也就是说Spring容器启动完成后,就会执行ContextRefreshListener中的onApplicationEvent()方法,从而最终会执行DispatcherServlet中的initStrategies(),这个方法中会初始化更多内容:

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
	initLocaleResolver(context);
	initThemeResolver(context);

	initHandlerMappings(context);
	initHandlerAdapters(context);

	initHandlerExceptionResolvers(context);
	initRequestToViewNameTranslator(context);
	initViewResolvers(context);
	initFlashMapManager(context);
}
复制代码

其中最为核心的就是HandlerMapping和HandlerAdapter。

什么是Handler?

Handler表示请求处理器,在SpringMVC中有四种Handler:

  1. 实现了Controller接口的Bean对象
  2. 实现了HttpRequestHandler接口的Bean对象
  3. 添加了@RequestMapping注解的方法
  4. 一个HandlerFunction对象

比如实现了Controller接口的Bean对象:

@Component("/test")
public class HoellerBeanNameController implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		System.out.println("Hoeller");
		return new ModelAndView();
	}
}
复制代码

实现了HttpRequestHandler接口的Bean对象:

@Component("/test")
public class HoellerBeanNameController implements HttpRequestHandler {

	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("Hoeller");
	}
}
复制代码

添加了@RequestMapping注解的方法:

@RequestMapping
@Component
public class HoellerController {

	@Autowired
	private HoellerService hoellerService;

	@RequestMapping(method = RequestMethod.GET, path = "/test")
	@ResponseBody
	public String test(String username) {
		return "Hoeller";
	}

}
复制代码

一个HandlerFunction对象(以下代码中有两个):

@ComponentScan("com.hoeller")
@Configuration
public class AppConfig {

	@Bean
	public RouterFunction<ServerResponse> person() {
		return route()
				.GET("/app/person", request -> ServerResponse.status(HttpStatus.OK).body("Hello GET"))
				.POST("/app/person", request -> ServerResponse.status(HttpStatus.OK).body("Hello POST"))
				.build();
	}
    
}
复制代码

什么是HandlerMapping?

HandlerMapping负责去寻找Handler,并且保存路径和Handler之间的映射关系。

因为有不同类型的Handler,所以在SpringMVC中会由不同的HandlerMapping来负责寻找Handler,比如:

  1. BeanNameUrlHandlerMapping:负责Controller接口和HttpRequestHandler接口
  2. RequestMappingHandlerMapping:负责@RequestMapping的方法
  3. RouterFunctionMapping:负责RouterFunction以及其中的HandlerFunction

BeanNameUrlHandlerMapping的寻找流程:

  1. 找出Spring容器中所有的beanName
  2. 判断beanName是不是以“/”开头
  3. 如果是,则把它当作一个Handler,并把beanName作为key,bean对象作为value存入handlerMap中
  4. handlerMap就是一个Map

RequestMappingHandlerMapping的寻找流程:

  1. 找出Spring容器中所有beanType
  2. 判断beanType是不是有@Controller注解,或者是不是有@RequestMapping注解
  3. 判断成功则继续找beanType中加了@RequestMapping的Method
  4. 并解析@RequestMapping中的内容,比如method、path,封装为一个RequestMappingInfo对象
  5. 最后把RequestMappingInfo对象做为key,Method对象封装为HandlerMethod对象后作为value,存入registry中
  6. registry就是一个Map

RouterFunctionMapping的寻找流程会有些区别,但是大体是差不多的,相当于是一个path对应一个HandlerFunction。

各个HandlerMapping除开负责寻找Handler并记录映射关系之外,自然还需要根据请求路径找到对应的Handler,在源码中这三个HandlerMapping有一个共同的父类AbstractHandlerMapping 

AbstractHandlerMapping实现了HandlerMapping接口,并实现了getHandler(HttpServletRequest request)方法。

AbstractHandlerMapping会负责调用子类的getHandlerInternal(HttpServletRequest request)方法从而找到请求对应的Handler,然后AbstractHandlerMapping负责将Handler和应用中所配置的HandlerInterceptor整合成为一个HandlerExecutionChain对象。

所以寻找Handler的源码实现在各个HandlerMapping子类中的getHandlerInternal()中,根据请求路径找到Handler的过程并不复杂,因为路径和Handler的映射关系已经存在Map中了。

比较困难的点在于,当DispatcherServlet接收到一个请求时,该利用哪个HandlerMapping来寻找Handler呢?看源码:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}
复制代码

很简单,就是遍历,找到就返回,默认顺序为: 

所以BeanNameUrlHandlerMapping的优先级最高,比如:

@Component("/test")
public class HoellerBeanNameController implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		System.out.println("Hello Hoeller");
		return new ModelAndView();
	}
}
复制代码
@RequestMapping(method = RequestMethod.GET, path = "/test")
@ResponseBody
public String test(String username) {
	return "Hi Hoeller";
}
复制代码

请求路径都是/test,但是最终是Controller接口的会生效。

什么是HandlerAdapter?

找到了Handler之后,接下来就该去执行了,比如执行下面这个test()

@RequestMapping(method = RequestMethod.GET, path = "/test")
@ResponseBody
public String test(String username) {
	return "Hoeller";
}
复制代码

但是由于有不同种类的Handler,所以执行方式是不一样的,再来总结一下Handler的类型:

  1. 实现了Controller接口的Bean对象,执行的是Bean对象中的handleRequest()
  2. 实现了HttpRequestHandler接口的Bean对象,执行的是Bean对象中的handleRequest()
  3. 添加了@RequestMapping注解的方法,具体为一个HandlerMethod,执行的就是当前加了注解的方法
  4. 一个HandlerFunction对象,执行的是HandlerFunction对象中的handle()

所以,按逻辑来说,找到Handler之后,我们得判断它的类型,比如代码可能是这样的:

Object handler = mappedHandler.getHandler();
if (handler instanceof Controller) {
    ((Controller)handler).handleRequest(request, response);
} else if (handler instanceof HttpRequestHandler) {
    ((HttpRequestHandler)handler).handleRequest(request, response);
} else if (handler instanceof HandlerMethod) {
    ((HandlerMethod)handler).getMethod().invoke(...);
} else if (handler instanceof HandlerFunction) {
    ((HandlerFunction)handler).handle(...);
}
复制代码

但是SpringMVC并不是这么写的,还是采用的适配模式,把不同种类的Handler适配成一个HandlerAdapter,后续再执行HandlerAdapter的handle()方法就能执行不同种类Hanlder对应的方法。

针对不同的Handler,会有不同的适配器:

  1. HttpRequestHandlerAdapter
  2. SimpleControllerHandlerAdapter
  3. RequestMappingHandlerAdapter
  4. HandlerFunctionAdapter

适配逻辑为:

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
                               "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
复制代码

传入handler,遍历上面四个Adapter,谁支持就返回谁,比如判断的代码依次为:

public boolean supports(Object handler) {
    return (handler instanceof HttpRequestHandler);
}

public boolean supports(Object handler) {
    return (handler instanceof Controller);
}

public final boolean supports(Object handler) {
    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

public boolean supports(Object handler) {
    return handler instanceof HandlerFunction;
}
复制代码

根据Handler适配出了对应的HandlerAdapter后,就执行具体HandlerAdapter对象的handle()方法了,比如:

HttpRequestHandlerAdapter的handle():

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	((HttpRequestHandler) handler).handleRequest(request, response);
	return null;
}
复制代码

SimpleControllerHandlerAdapter的handle():

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	return ((Controller) handler).handleRequest(request, response);
}
复制代码

HandlerFunctionAdapter的handle():

HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;
serverResponse = handlerFunction.handle(serverRequest);
复制代码

因为这三个接收的直接就是Requeset对象,不用SpringMVC做额外的解析,所以比较简单,比较复杂的是RequestMappingHandlerAdapter,它执行的是加了@RequestMapping的方法,而这种方法的写法可以是多种多样,SpringMVC需要根据方法的定义去解析Request对象,从请求中获取出对应的数据然后传递给方法,并执行。

@RequestMapping方法参数解析

当SpringMVC接收到请求,并找到了对应的Method之后,就要执行该方法了,不过在执行之前需要根据方法定义的参数信息,从请求中获取出对应的数据,然后将数据传给方法并执行。

一个HttpServletRequest通常有:

  1. request parameter
  2. request attribute
  3. request session
  4. reqeust header
  5. reqeust body

比如如下几个方法:

public String test(String username) {
    return "Hoeller";
}
复制代码

表示要从request parameter中获取key为username的value

public String test(@RequestParam("uname") String username) {
    return "Hoeller";
}
复制代码

表示要从request parameter中获取key为uname的value

public String test(@RequestAttribute String username) {
    return "Hoeller";
}
复制代码

表示要从request attribute中获取key为username的value

public String test(@SessionAttribute String username) {
    return "Hoeller";
}
复制代码

表示要从request session中获取key为username的value

public String test(@RequestHeader String username) {
    return "Hoeller";
}
复制代码

表示要从request header中获取key为username的value

public String test(@RequestBody String username) {
    return "Hoeller";
}
复制代码

表示获取整个请求体

所以,我们发现SpringMVC要去解析方法参数,看该参数到底是要获取请求中的哪些信息。

而这个过程,源码中是通过HandlerMethodArgumentResolver来实现的,比如:

  1. RequestParamMethodArgumentResolver:负责处理@RequestParam
  2. RequestHeaderMethodArgumentResolver:负责处理@RequestHeader
  3. SessionAttributeMethodArgumentResolver:负责处理@SessionAttribute
  4. RequestAttributeMethodArgumentResolver:负责处理@RequestAttribute
  5. RequestResponseBodyMethodProcessor:负责处理@RequestBody
  6. 还有很多其他的...

而在判断某个参数该由哪个HandlerMethodArgumentResolver处理时,也是很粗暴:

private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    
    HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
	if (result == null) {
    	for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
        	if (resolver.supportsParameter(parameter)) {
            	result = resolver;
            	this.argumentResolverCache.put(parameter, result);
            	break;
        	}
    	}
	}
	return result;

}
复制代码

就是遍历所有的HandlerMethodArgumentResolver,哪个能支持处理当前这个参数就由哪个处理。

比如:

@RequestMapping(method = RequestMethod.GET, path = "/test")
@ResponseBody
public String test(@RequestParam @SessionAttribute String username) {
	System.out.println(username);
	return "Hoeller";
}
复制代码

以上代码的username将对应RequestParam中的username,而不是session中的,因为在源码中RequestParamMethodArgumentResolver更靠前。

当然HandlerMethodArgumentResolver也会负责从request中获取对应的数据,对应的是resolveArgument()方法。

比如RequestParamMethodArgumentResolver:

protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
    HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);

    if (servletRequest != null) {
        Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
        if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
            return mpArg;
        }
    }

    Object arg = null;
    MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
    if (multipartRequest != null) {
        List<MultipartFile> files = multipartRequest.getFiles(name);
        if (!files.isEmpty()) {
            arg = (files.size() == 1 ? files.get(0) : files);
        }
    }
    if (arg == null) {
        String[] paramValues = request.getParameterValues(name);
        if (paramValues != null) {
            arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
        }
    }
    return arg;
}

复制代码

核心是:

if (arg == null) {
    String[] paramValues = request.getParameterValues(name);
    if (paramValues != null) {
        arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
    }
}
复制代码

按同样的思路,可以找到方法中每个参数所要求的值,从而执行方法,得到方法的返回值。

@RequestMapping方法返回值解析

而方法返回值,也会分为不同的情况。比如有没有加@ResponseBody注解,如果方法返回一个String:

  1. 加了@ResponseBody注解:表示直接将这个String返回给浏览器
  2. 没有加@ResponseBody注解:表示应该根据这个String找到对应的页面,把页面返回给浏览器

在SpringMVC中,会利用HandlerMethodReturnValueHandler来处理返回值:

  1. RequestResponseBodyMethodProcessor:处理加了@ResponseBody注解的情况
  2. ViewNameMethodReturnValueHandler:处理没有加@ResponseBody注解并且返回值类型为String的情况
  3. ModelMethodProcessor:处理返回值是Model类型的情况
  4. 还有很多其他的...

我们这里只讲RequestResponseBodyMethodProcessor,因为它会处理加了@ResponseBody注解的情况,也是目前我们用得最多的情况。

RequestResponseBodyMethodProcessor相当于会把方法返回的对象直接响应给浏览器,如果返回的是一个字符串,那么好说,直接把字符串响应给浏览器,那如果返回的是一个Map呢?是一个User对象呢?该怎么把这些复杂对象响应给浏览器呢?

处理这块,SpringMVC会利用HttpMessageConverter来处理,比如默认情况下,SpringMVC会有4个HttpMessageConverter:

  1. ByteArrayHttpMessageConverter:处理返回值为字节数组的情况,把字节数组返回给浏览器
  2. StringHttpMessageConverter:处理返回值为字符串的情况,把字符串按指定的编码序列号后返回给浏览器
  3. SourceHttpMessageConverter:处理返回值为XML对象的情况,比如把DOMSource对象返回给浏览器
  4. AllEncompassingFormHttpMessageConverter:处理返回值为MultiValueMap对象的情况

StringHttpMessageConverter的源码也比较简单:

protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
    HttpHeaders headers = outputMessage.getHeaders();
    if (this.writeAcceptCharset && headers.get(HttpHeaders.ACCEPT_CHARSET) == null) {
        headers.setAcceptCharset(getAcceptedCharsets());
    }
    Charset charset = getContentTypeCharset(headers.getContentType());
    StreamUtils.copy(str, charset, outputMessage.getBody());
}
复制代码

先看有没有设置Content-Type,如果没有设置则取默认的,默认为ISO-8859-1,所以默认情况下返回中文会乱码,可以通过以下来中方式来解决:

@RequestMapping(method = RequestMethod.GET, path = "/test", produces = {"application/json;charset=UTF-8"})
@ResponseBody
public String test() {
	return "公众号 Hoeller";
}
复制代码
@ComponentScan("com.hoeller")
@Configuration
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		StringHttpMessageConverter messageConverter = new StringHttpMessageConverter();
		messageConverter.setDefaultCharset(StandardCharsets.UTF_8);
		converters.add(messageConverter);
	}
}
复制代码

不过以上四个Converter是不能处理Map对象或User对象的,所以如果返回的是Map或User对象,那么得单独配置一个Converter,比如MappingJackson2HttpMessageConverter,这个Converter比较强大,能把String、Map、User对象等等都能转化成JSON格式。

@ComponentScan("com.hoeller")
@Configuration
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
		messageConverter.setDefaultCharset(StandardCharsets.UTF_8);
		converters.add(messageConverter);
	}
}
复制代码

具体转化的逻辑就是Jackson2的转化逻辑。

总结

以上就是整个SpringMVC从启动到处理请求,从接收请求到执行方法的整体流程,如果大家喜欢,麻烦点赞转发一下,后续我就分享更多细节内容。

zedboard(5)spi轮询和中断 一个SPI可以有几个从设备 在程序中使用 s32 XSpiPs_SetSlaveSelect(XSpiPs *InstancePtr, u8 SlaveSel) 选择。其实就是吧对应设备的ss拉低。 备注:只选一个ss,可以不用指定。(感觉,还没测试) 这是xspips.c中定义的函数,发送和接收有 XSpiPs_Transfer 和 XSpiPs_PolledTransfer 两个函数,分别采用中断和轮询模式。    一、轮询模式 米联客参考代码,SpiPs_Init中部分和官方例程流程一样,Spi 阅读详情

相关推荐

STM32基于软件模拟IIC进行AHT21B温湿度采集

通过学习软件IIC来进行实操AHT21B采集温湿度。

Liu-FE的博客 3700

SpringMVC篇(二)“聊聊SpringMVC吧”

1.什么是springmvc? springmvc是spring Framework的一部分,是基于java实现MVC的轻量级框架。 2.springmvc的特点:(1)轻量级,简单易学 (2)高效 , 基于请求响应的MVC框架 (3)与Spring兼容性好,无缝结合 (4)约定优于配置 (5)功能强大:RESTful、数据验证、格式化、本地化、主题等 (6)简洁灵活 Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。 DispatcherServlet的作用

小倪喜欢吃蛋糕的博客 208

SpringBoot 指标监控——Actuator

1、 访问:localhost:8000/actuator 设置健康监控显示具体情况 metrics http://localhost:8000/actuator/metrics/jvm.gc.live.data.size 定制化health信息 //利用构造器,在注册中心中添加cityService.saveCity.count指标 public CityServiceImpl(MeterRegistry meter...

weixin_44302046的博客 4627

聊聊什么是Spring以及其中的工作机制

                              突然想复习下spring相关的笔记  许久没有用到Spring,聊之前呢,说说spring在javaee三层高架构里面起的作用,或者说可以起替代的作用,javaee中web层service层dao层分别对应springMvc,spring的ioc,spring的jdbcTemplate.  1.Spring是一个开源的轻量级框架,他的核心...

qsxbzch的博客 4270

如何编译RustDesk(Unbuntu 和Android版本)

备注:官方文档上,一边都是基于sciter,这个在后面已经不建议使用了,但是依然可以编译刚开始的时候看官方的文档,涉及的东西比较多,也搞的一头雾水,通过B站上一个视频,可以通过CI/CD来编译,以及act本地试试(最终放弃,大概需要下载大几十G的容器下来)。最终总算明确了方向,可以用自动化流水线来编译。直接看CI/CD的脚本文件文件在.github/workflows目录下,重点研究 bridge.yml 和flutter-build.yml 这两个文件。

lvronglee的专栏 2547

利用Openlayers4实现地图遮罩效果(二)

之前实现的遮罩效果,在深色背景的底图上,对要突出的区域采用半透明遮罩,以此来突出该区域。但是有时底图颜色偏白,这时候不再适合对要突出的区域采用遮罩,而是要对突出区域之外进行遮罩处理。两种效果的对比入下图: ...

此爱如少年 6397

聊聊 springmvc 异常处理

在做WEB项目中,无论是接口服务还是前后分离的web项目,对于RunTimeException异常和业务异常的处理是很重要的一部分,若不处理,业务异常抛出会给用户不友好的访问体验,DAO层的异常会暴露数据库的一些信息从而使得服务不安全等等,幸运的是JAVA依赖于强大的spring生态,springmvc 已经为我们准备了成熟的解决方案。      springMVC提供的异常处理主要有两种方式,

tanyunlong_nice的专栏 501

ComfyUI 本地部署指南:概念、部署过程、生成图片、共享 WebUI 模型

ComfyUI 是一个基于节点的 Stable Diffusion 图形化用户界面。您可以通过将不同的节点连接在一起来构建生成图像的工作流程。一些常用的节点包括加载检查点模型(Load Checkpoint)、输入提示词(CLIP Text Encode)、指定采样器(KSampler)等。ComfyUI 将工作流程分解为可重新排列的元素,以便您可以轻松创建自己的元素。

水滴的博客 5032

聊聊SpringMVC(2)---SpringMVC之请求过程

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34082854的博客 389

slew dreate,slew threshold与transition计算

​只看rise情况下,from pin取slew threshold10%-90%的区间,slew derate为1,计算得到transition为1.002e-10,to pin的slew threshold 为30%-70%,slew derate 0.5,从波形列表上取相近的值3.75e-10和8.75e-10,计算得到transition为(8.75e-10-3.75e-10)/0.5=1e-9,考虑精度和取值区间问题,基本符合工具计算的值,如下:​。如下示例,在.lib库中有定义以下内容。

m0_61544122的博客 792

爬虫进阶必备:深入理解requests.Session(),提升爬虫效率与稳定性

前两天,有个朋友跟我吐槽,说自己写了个爬虫爬取某个电商网站的商品信息,刚开始跑得好好的,爬了大概几百页之后,突然就开始报错了。HTTP状态码一会儿429,一会儿403,最离谱的是有些页面明明登录了却显示未登录状态。他排查了半天也没找到原因,最后把代码发给我看。 我扫了一眼代码,发现一个典型问题:他每次请求都新建一个requests.Session(),甚至有些请求直接用了requests.get()。这就好比每次进超市都要重新注册会员,每次都重新跟服务器“握手”,不翻车才怪。 其实,这就是我们今天要聊的

2201_76125261的博客 1228

面试官:来聊聊springmvc执行原理

Java面试笔试面经、Java技术每天学习一点公众号Java面试关注我不迷路作者:学海无涯—远航来源:https://www.cnblogs.com/yang-guang-zhang/p...

java面试笔试 373

MT4/MT5 第三代移动平均线(MetaTrader 指标)

第三代移动平均线(3G-MA)是传统MA指标的升级版本,通过"时滞压缩"算法将信号滞后降至理论极限(λ=2)。该指标在保留平滑性的同时,信号速度比EMA快1.5-2.3倍,适用于MT4/MT5平台。核心参数包括计算周期(默认34)、滞后压缩系数(2-10)和应用价位选择,支持斜率变色功能。安装简单,无需外部依赖,通过多周期共振可提升12-18%胜率。指标代码包含完整的MT4/MT5实现方案,采用双缓冲计算结构,通过相位前移算法抵消群延迟。风险提示:需配合其他技术指标和严格风控(≤2%账户

JanLEE 579

SpringMVC工作流程

hhhh

qq_39839075的博客 212

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

面试官:今天要不来聊聊SpringMVC吧?

面试官:今天要不来聊聊SpringMVC吧? 候选者:我先简单说下我对SpringMVC的理解哈 候选者:SpringMVC我觉得它是对Servlet的封装,屏蔽掉Servlet很多的细节 候选者:举几个例子 候选者:可能我们刚学Servlet的时候,要获取参数需要不断的getParameter 候选者:现在只要在SpringMVC方法定义对应的JavaBean,只要属性名与参数名一致,SpringMVC就可以帮我们实现「将参数封装到JavaBean」上了 候选者:又比如,以前使用Servlet

分享Java技术知识,共同成长进步! 221

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

springMVC,什么是Spring MVC? Spring MVC的主要组件? springMVC工作原理/流程 MVC框架

Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把模型-视图-控制器分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。Spring MVC的优点(1)可以支持各种视图技术,而不仅仅局限于JSP;(2)与Spring框架集成(如IoC容器、AOP等);

weixin_44797327的博客 1293

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

面试官:聊聊SpringMVC的执行流程?

提起Spring MVC,你的第一印象是什么? 一个简化Web开发的轻量级框架? 实际上,现代开发过程中,开发流程与开发效率的不断提高,同时伴随着Restful与Json相结合的方式的兴起,使得多个设备跨平台的相互调用与访问变得简单了许多。 所以Spring MVC简化Web开发的使命也自然而然的变为了简化服务端开发。 那么今天我们就抛开繁杂的代码,从宏观的角度来看一看Spring MVC对于处理请求,简化服务端开发的解决方案是如何实现的。 1、曾经的王者——Servlet 在笔者刚接触到使用J

m0_50180963的博客 221

springmvc工作流程_一篇文章搞懂SpringMVC核心执行原理

对Java程序员来讲,做web开发最熟悉的框架莫过于SpringMVC了。之所以它能一统江湖,不是自己太优秀,而是对手太坑了,不知道大家还记不记得2017年左右Struts2爆出了一个大漏洞,自此之后,Web开发领域的就是SpringMVC的天下了。但是鉴于这么优秀的框架,很多程序员还只是停留在会用的状态,对底层的原理却不甚了解,所以今天咱么就来聊聊SpringMVC的工作原理。三层架构在开始介绍...

weixin_39935257的博客 111

我靠着这篇SpringMVC,拿到了各大厂的offer

不小心就拿了这么多offer

3y 6478

从Servlet 到 springmvc,简单聊聊

总结:先聊聊 servlet 其实是一套规范具体实现都是交给容器,如 tomcat,jetty 具体实现, 接口如下: public interface Servlet { void init(ServletConfig var1) throws ServletException; ServletConfig getServletConfig(...

weixin_30474613的博客 175

萌新学习SpringMVC很难吗?来一篇文章让你搞懂

前言 这篇SpringMVC被催了很久了,这阵子由于做整合系统的事,所以非常非常地忙。这周末早早就回了公司肝这篇文章了。 如果关注三歪的同学会发现,三歪最近写的很多文章都是结合了现有的系统去写的。这些问题都是真实开发场景会遇到的、用的上的,这些案例对未工作的同学帮助应该还是蛮大的。 不多BB了,还是进入今天的正题吧「SpringMVC」 先简单聊聊SpringMVC 如果你们玩知乎,很可能会看到我的身影。我经常会去知乎水回答。在知乎有很多初学者都会问的一个问题:「我学习SpringMVC需要...

weixin_46784898的博客 2510

聊聊Spring

文章目录1. 使用Spring框架的好处是什么?2. 什么是 Spring IOC 容器?3. 什么是依赖注入?可以通过多少种方式完成依赖注入?4. 区分 BeanFactory 和 ApplicationContext?5. 区分构造函数注入和 setter 注入6. spring 提供了哪些配置方式?7. Spring 中的 bean 的作用域有哪些?8. 如何理解IoC和DI?9. 将一个类声明为Spring的 bean 的注解有哪些?10. spring 支持几种 bean scope?11. Sp

mqq2502513332的博客 305

SpringMVC——通俗易懂讲讲Ajax~

聊聊Ajax一、什么是Ajax二、iframe标签简单伪造Ajax三、Ajax的实现1. 基本概念的了解Ajax的核心是什么?XMLHttpRequest是什么?Ajax数据传输的数据格式是什么?2. 原生JS实现1. 创建XHR对象2. 打开与服务器的连接3. 发送请求4. 接收服务器响应3. jQuery实现1. 了解jQuery中Ajax的常用方法$.ajax()$.get()$.post()2. 模仿浏览器的失去焦点事件1. 新建一个SpringMVC项目2. 下载jQuery3. IDEA中引入.

欢迎来到 Baret-H 的博客 2371

SpringMVC返回null是什么意思?| SpringMVC系列第9篇

大家好,我是【路人甲 Java】号主路人,本文如果对你有帮助,点个在看,顺便忙转发一下,非常需要大家的支持,对 java 有兴趣的朋友欢迎加我微信 itsoku 交流。1、回顾一下目前为止...

路人甲Java 1441

一篇文章搞懂SpringMVC核心执行原理

对Java程序员来讲,做web开发最熟悉的框架莫过于SpringMVC了。之所以它能一统江湖,不是自己太优秀,而是对手太坑了,不知道大家还记不记得2017年左右Struts2爆出了一个大漏洞,自此之后,Web开发领域的就是SpringMVC的天下了。 但是鉴于这么优秀的框架,很多程序员还只是停留在会用的状态,对底层的原理却不甚了解,所以今天咱么就来聊聊SpringMVC的工作原理。 三层架构 在开始介绍SpringMVC之前,咱么要先来了解一下web开发的历史。我们的开发架构一般都是...

AI课工场 422
上一篇: 面试官:什么是自旋锁?自旋的好处和后果是什么呢?
下一篇: 如何破越发展 to B 市场亏损越多问题?
Java_LingFeng
博客等级 码龄4年 505粉丝 259原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值