SpringMVC静态资源配置过程详解

目录
  • springmvc静态资源配置
  • 1. 在java配置文件中配置DefaultServletHttpRequestHandler来进行处理
  • 2. 在java配置文件中配置ResourceHttpRequestHandler来进行处理
  • 3.  web.xml配置servlet映射
  • 最后
  • 补充

springmvc静态资源配置

  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <async-supported>false</async-supported>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

在javaweb项目中配置了DispatcherServlet的情况下,如果不进行额外配置的话,几乎所有的请求都会走这个servlet来处理,默认静态资源按路径是访问不到的会报404错误,下面讲一讲如何配置才能访问到静态资源,本文将介绍三种方法

1. 在java配置文件中配置DefaultServletHttpRequestHandler来进行处理

@Configuration
@EnableWebMvc
public class MyMvcConfigurer implements WebMvcConfigurer {

  @Override
  public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    // tomcat默认处理静态资源的servlet名称为default,不指定也可以DefaultServletHttpRequestHandler.setServletContext会自动获取
//    configurer.enable("default");
    configurer.enable();
  }
}

上述配置完成后org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#defaultServletHandlerMapping 方法会生成一个类名为SimpleUrlHandlerMapping的bean,当其他handlerMapping无法处理请求时会接着调用SimpleUrlHandlerMapping对象进行处理

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#defaultServletHandlerMapping
/**
 * Return a handler mapping ordered at Integer.MAX_VALUE with a mapped
 * default servlet handler. To configure "default" Servlet handling,
 * override {@link #configureDefaultServletHandling}.
 */
@Bean
public HandlerMapping defaultServletHandlerMapping() {
  Assert.state(this.servletContext != null, "No ServletContext set");
  DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
  configureDefaultServletHandling(configurer);

  HandlerMapping handlerMapping = configurer.buildHandlerMapping();
  return (handlerMapping != null ? handlerMapping : new EmptyHandlerMapping());
}

org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer#buildHandlerMapping
@Nullable
protected SimpleUrlHandlerMapping buildHandlerMapping() {
  if (this.handler == null) {
    return null;
  }

  SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
  handlerMapping.setUrlMap(Collections.singletonMap("/**", this.handler));
  handlerMapping.setOrder(Integer.MAX_VALUE);
  return handlerMapping;
}

SimpleUrlHandlerMapping中有一个urlMap属性,key为请求路径匹配模式串,'/**'能匹配所有的路径, value为handler匹配完成后会调用handler处理请求

下面这个方法主要用来匹配获取handler

org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#getHandlerInternal

 	@Override
	@Nullable
	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		// 请求静态资源 path=/zxq/static/login.png
		// 处理完lookupPath=/static/login.png
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		Object handler = lookupHandler(lookupPath, request);
		if (handler == null) {
			// We need to care for the default handler directly, since we need to
			// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
			Object rawHandler = null;
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				// Bean name or resolved handler?
				if (rawHandler instanceof String) {
					String handlerName = (String) rawHandler;
					rawHandler = obtainApplicationContext().getBean(handlerName);
				}
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
			}
		}
		if (handler != null && logger.isDebugEnabled()) {
			logger.debug("Mapping [" + lookupPath + "] to " + handler);
		}
		else if (handler == null && logger.isTraceEnabled()) {
			logger.trace("No handler mapping found for [" + lookupPath + "]");
		}
		return handler;
	}

org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#lookupHandler

 	/**
	 * Look up a handler instance for the given URL path.
	 * <p>Supports direct matches, e.g. a registered "/test" matches "/test",
	 * and various Ant-style pattern matches, e.g. a registered "/t*" matches
	 * both "/test" and "/team". For details, see the AntPathMatcher class.
	 * <p>Looks for the most exact pattern, where most exact is defined as
	 * the longest path pattern.
	 * @param urlPath the URL the bean is mapped to
	 * @param request current HTTP request (to expose the path within the mapping to)
	 * @return the associated handler instance, or {@code null} if not found
	 * @see #exposePathWithinMapping
	 * @see org.springframework.util.AntPathMatcher
	 */
	@Nullable
	protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// Direct match?
		// 精确匹配,是否有符合的handler
		// urlPath = /static/login.png
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = obtainApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}

		// Pattern match?
		// 路径匹配
		List<String> matchingPatterns = new ArrayList<>();
		for (String registeredPattern : this.handlerMap.keySet()) {
			if (getPathMatcher().match(registeredPattern, urlPath)) {
				matchingPatterns.add(registeredPattern);
			}
			else if (useTrailingSlashMatch()) {
				if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
					matchingPatterns.add(registeredPattern + "/");
				}
			}
		}

		String bestMatch = null;
		Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
		if (!matchingPatterns.isEmpty()) {
			matchingPatterns.sort(patternComparator);
			if (logger.isDebugEnabled()) {
				logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
			}
			bestMatch = matchingPatterns.get(0);
		}
		// bestMatch = /static/**
		if (bestMatch != null) {
			handler = this.handlerMap.get(bestMatch);
			if (handler == null) {
				if (bestMatch.endsWith("/")) {
					handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
				}
				if (handler == null) {
					throw new IllegalStateException(
							"Could not find handler for best pattern match [" + bestMatch + "]");
				}
			}
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = obtainApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			// login.png
			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);

			// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
			// for all of them
			Map<String, String> uriTemplateVariables = new LinkedHashMap<>();
			for (String matchingPattern : matchingPatterns) {
				if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
					Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
					Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
					uriTemplateVariables.putAll(decodedVars);
				}
			}
			if (logger.isDebugEnabled()) {
				logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
			}
			// /static/**   login.png
			return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
		}

		// No handler found...
		return null;
	}

接着调用DefaultServletHttpRequestHandler的handleRequest方法处理请求,逻辑比较简单,获取请求转发器进行请求转发交给tomcat默认的servlet来进行处理

	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		Assert.state(this.servletContext != null, "No ServletContext set");
		RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
		if (rd == null) {
			throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" +
					this.defaultServletName + "'");
		}
		rd.forward(request, response);
	}

2. 在java配置文件中配置ResourceHttpRequestHandler来进行处理

@Configuration
@EnableWebMvc
public class MyMvcConfigurer implements WebMvcConfigurer {

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/static/**").addResourceLocations("/static/");
  }
}

和第一种配置几乎一样,其实只是换了一个handler类型来处理请求罢了

上述配置完成后org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#resourceHandlerMapping 方法会生成一个类名为SimpleUrlHandlerMapping的bean,当其他handlerMapping无法处理请求时会接着调用SimpleUrlHandlerMapping对象进行处理

ResourceHttpRequestHandler比DefaultServletHttpRequestHandler的构建稍微复杂一点

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#resourceHandlerMapping
/**
 * Return a handler mapping ordered at Integer.MAX_VALUE-1 with mapped
 * resource handlers. To configure resource handling, override
 * {@link #addResourceHandlers}.
 */
@Bean
public HandlerMapping resourceHandlerMapping() {
  Assert.state(this.applicationContext != null, "No ApplicationContext set");
  Assert.state(this.servletContext != null, "No ServletContext set");

  ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
      this.servletContext, mvcContentNegotiationManager(), mvcUrlPathHelper());
  addResourceHandlers(registry);

  AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
  if (handlerMapping != null) {
    handlerMapping.setPathMatcher(mvcPathMatcher());
    handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
    handlerMapping.setInterceptors(getInterceptors());
    handlerMapping.setCorsConfigurations(getCorsConfigurations());
  }
  else {
    handlerMapping = new EmptyHandlerMapping();
  }
  return handlerMapping;
}

org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry#getHandlerMapping
/**
 * Return a handler mapping with the mapped resource handlers; or {@code null} in case
 * of no registrations.
 */
@Nullable
protected AbstractHandlerMapping getHandlerMapping() {
  if (this.registrations.isEmpty()) {
    return null;
  }

  Map<String, HttpRequestHandler> urlMap = new LinkedHashMap<>();
  for (ResourceHandlerRegistration registration : this.registrations) {
    for (String pathPattern : registration.getPathPatterns()) {
      ResourceHttpRequestHandler handler = registration.getRequestHandler();
      if (this.pathHelper != null) {
        handler.setUrlPathHelper(this.pathHelper);
      }
      if (this.contentNegotiationManager != null) {
        handler.setContentNegotiationManager(this.contentNegotiationManager);
      }
      handler.setServletContext(this.servletContext);
      handler.setApplicationContext(this.applicationContext);
      try {
        handler.afterPropertiesSet();
      }
      catch (Throwable ex) {
        throw new BeanInitializationException("Failed to init ResourceHttpRequestHandler", ex);
      }
      urlMap.put(pathPattern, handler);
    }
  }

  SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
  handlerMapping.setOrder(order);
  handlerMapping.setUrlMap(urlMap);
  return handlerMapping;
}

之后也是调用SimpleUrlHandlerMapping相同的逻辑先根据请求路径匹配找到对应处理的handler,这里对应的是ResourceHttpRequestHandler之后调用handleRequest方法,原理是先根据请求的路径找到对应的资源文件,再获取资源文件的输入流写入到response响应中,源码如下:

org.springframework.web.servlet.resource.ResourceHttpRequestHandler#handleRequest

 /**
 * Processes a resource request.
 * <p>Checks for the existence of the requested resource in the configured list of locations.
 * If the resource does not exist, a {@code 404} response will be returned to the client.
 * If the resource exists, the request will be checked for the presence of the
 * {@code Last-Modified} header, and its value will be compared against the last-modified
 * timestamp of the given resource, returning a {@code 304} status code if the
 * {@code Last-Modified} value  is greater. If the resource is newer than the
 * {@code Last-Modified} value, or the header is not present, the content resource
 * of the resource will be written to the response with caching headers
 * set to expire one year in the future.
 */
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

  // For very general mappings (e.g. "/") we need to check 404 first
  // 根据请求的文件路径找到对应的资源文件
  Resource resource = getResource(request);
  if (resource == null) {
    logger.trace("No matching resource found - returning 404");
    response.sendError(HttpServletResponse.SC_NOT_FOUND);
    return;
  }

  if (HttpMethod.OPTIONS.matches(request.getMethod())) {
    response.setHeader("Allow", getAllowHeader());
    return;
  }

  // Supported methods and required session
  // 校验支持的方法GET和HEAD 以及验证session是否必须
  checkRequest(request);

  // Header phase
  if (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {
    logger.trace("Resource not modified - returning 304");
    return;
  }

  // Apply cache settings, if any
  // 可以根据设置的秒数设置缓存时间 cache-control:max-age=xxx
  prepareResponse(response);

  // Check the media type for the resource
  // 根据文件后缀去寻找 png -> image/png
  MediaType mediaType = getMediaType(request, resource);
  if (mediaType != null) {
    if (logger.isTraceEnabled()) {
      logger.trace("Determined media type '" + mediaType + "' for " + resource);
    }
  }
  else {
    if (logger.isTraceEnabled()) {
      logger.trace("No media type found for " + resource + " - not sending a content-type header");
    }
  }

  // Content phase
  if (METHOD_HEAD.equals(request.getMethod())) {
    setHeaders(response, resource, mediaType);
    logger.trace("HEAD request - skipping content");
    return;
  }

  ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
  if (request.getHeader(HttpHeaders.RANGE) == null) {
    Assert.state(this.resourceHttpMessageConverter != null, "Not initialized");
    // 设置content-type、content-length等响应头
    setHeaders(response, resource, mediaType);
    // 将文件流写入到response响应中
    this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
  }
  else {
    Assert.state(this.resourceRegionHttpMessageConverter != null, "Not initialized");
    response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
    ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
    try {
      List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
      response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
      this.resourceRegionHttpMessageConverter.write(
          HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
    }
    catch (IllegalArgumentException ex) {
      response.setHeader("Content-Range", "bytes */" + resource.contentLength());
      response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
    }
  }
}

3.  web.xml配置servlet映射

原理可以参考上一篇文章

  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
  </servlet-mapping>

将带有/static/xxx 路径的请求直接交给tomcat默认的servlet去进行处理

最后

完成上述的一种配置后就能访问到我们的静态资源了,请求路径http://localhost:8082/zxq/static/login.png

补充

若配置了拦截器且使用第二种方法,拦截器也会对静态资源进行拦截,若不需要拦截还需要进行额外的配置去除比较麻烦

第一种方法用dispatcherServlet拦截所有的请求再将请求交给tomcat默认的servlet处理,性能上有所消耗,拦截器不过滤

第二种方法拦截器会进行过滤若需要过滤的路径较多配置麻烦

第三种方法直接用tomcat默认的servlet进行处理,但静态资源路径有多个时配置也比较麻烦

综上所述,根据自己项目的情况选择哪一种方法~

@Configuration
@EnableWebMvc
public class MyMvcConfigurer implements WebMvcConfigurer {

  @Resource
  private CustomInterceptor customInterceptor;

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(customInterceptor)
        .addPathPatterns("/**")
        .excludePathPatterns("/static/**");
  }

//  @Override
//  public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
//    // tomcat默认处理静态资源的servlet名称为default,不指定也可以DefaultServletHttpRequestHandler.setServletContext会自动获取
////    configurer.enable("default");
//    configurer.enable();
//  }

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/static/**").addResourceLocations("/static/");
  }
}

以上就是SpringMVC静态资源配置过程详解的详细内容,更多关于SpringMVC静态资源配置的资料请关注我们其它相关文章!

(0)

相关推荐

  • springmvc流程图以及配置解析

    springmvc:是完成数据的封装和跳转的功能 流程图如下: springmvc的配置流程 1.导入jar包 2.配置servlet文件 init-param的作用是在启动servlet启动时规定其地地址及名称去搜寻其springmvc配置文件 3.配置springmvc配置文件 进行handlermapping的配置,不进行配置时BeanNameUrlHandlerMapping, handlermapping的三种方式 1.默认方式BeanNameUrlHandlerMapping,根据b

  • SpringMVC配置与使用详细介绍

    目录 一.SpringMVC的使用 1.MVC模式 2.具体的坐标如下 3.配置DispatcheServlet 4.编写springmvc.xml的配置文件 二.SpringMVC原理 1.SpringMVC中心控制器 2.入门案例的执行流程 一.SpringMVC的使用 1.MVC模式 Spring mvc是基于Spring的一个模块,专门做web开发,可以理解为是Servlet的升级 在Spring MVC框架当中,Controller替代Servlet担负控制器的职能, **M:**指m

  • springmvc注解配置实现解析

    springmvc大大减少了对xml的配置,减少了配置量,以及可以在一个controller类中进行多个请求配置 一.springmvc配置 context:component-scan 开启包扫描,对指定的包进行注解扫描 mvc:annotation-driven开启注解功能 二.controller配置 在类上加上@Controller 在指定的方法上@RequestMapping("/t请求名") 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们.

  • 使用springmvc配置视图解析器和重定向方式

    目录 springmvc配置视图解析器和重定向 为什么需要配置视图解析器 配置步骤 解决配置视图解析器带来的问题 重定向 配置多个视图解析器 springmvc controller springmvc配置视图解析器和重定向 为什么需要配置视图解析器 看图 配置步骤 第一步:需要在springmvc.xml配置 <!-- 配置SpringMVC的视图解析器: 配置前缀和后缀 --> <bean class="org.springframework.web.servlet.vie

  • 基于springMVC web.xml中的配置加载顺序

    目录 springMVC web.xml中的配置加载顺序 1.Spring上下文环境的配置文件 2.SpringMVC配置文件 加载顺序是 web.xml加载顺序及Spring包扫描注意 1.web.xml文件中配置文件加载顺序 2.SpringMVC配置事务管理时 springMVC web.xml中的配置加载顺序 在这里就不详细说web.xml的文件中的具体配置,就简单说明一下其中配置信息的加载顺序: 在web.xml文件中元素的加载顺序与它们在 web.xml 文件中的先后顺序无关. 加载

  • 使用注解开发SpringMVC详细配置教程

    1.使用注解开发SpringMVC 1.新建一个普通的maven项目,添加web支持 2.在pom.xml中导入相关依赖 SpringMVC相关 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.8.RELEASE</version> </dependency&

  • SpringMVC静态资源配置过程详解

    目录 springmvc静态资源配置 1. 在java配置文件中配置DefaultServletHttpRequestHandler来进行处理 2. 在java配置文件中配置ResourceHttpRequestHandler来进行处理 3.  web.xml配置servlet映射 最后 补充 springmvc静态资源配置 <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>or

  • SpringMVC实现Validation校验过程详解

    这篇文章主要介绍了SpringMVC实现Validation校验过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.概述 对前端的校验大多数通过js在页面校验,这种方法比较简单,如果对安全性考虑,还要在后台校验. springmvc使用JSR-303(javaEE6规范的一部分)校验规范,springmvc使用的是Hibernate Validator(和Hibernate的ORM) 二.步骤 2.1 引入 Hibernate Vali

  • springmvc处理模型数据ModelAndView过程详解

    这篇文章主要介绍了springmvc处理模型数据ModelAndView过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 springmvc提供了以下几种途径来输出模型数据: (1)ModelAndView:处理方法返回值类型为ModelAndView时,方法体即可通过该对象添加模型数据. (2)Map及Model:入参为org.springframework.ui.Model.org.springframework.ui.ModelMa

  • springboot整合netty过程详解

    这篇文章主要介绍了springboot整合netty过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前言 上一篇讲了netty的一个入门的demo:项目上我也把数据处理做好了,就要开始存数据库了:我用的mybatis框架,如果单独使用还是觉得比较麻烦,所以就用了springboot+mybatis+netty:本篇主要讲netty与springboot的整合,以及我在这个过程中遇到的问题,又是怎么去解决的: 正文 我在做springbo

  • mybatis分页绝对路径写法过程详解

    这篇文章主要介绍了mybatis分页绝对路径写法过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 共四步, 1.下载jar包,maven的坐标为 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.0.4</version&

  • JavaScript代码异常监控实现过程详解

    这篇文章主要介绍了JavaScript代码异常监控实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 JavaScript异常一般有两方面:语法错误和运行时错误.两种错误的捕获和处理方式不同,从而影响具体的方案选型.通常来说,处理JS异常的方案有两种:try...catch捕获 和 window.onerror捕获.以下就两种方案分别分析各自的优劣. 虽然语法错误本应该在开发构建阶段使用测试工具避免,但难免会有马失前蹄部署到线上的时候.

  • Spring JDK动态代理实现过程详解

    这篇文章主要介绍了Spring JDK动态代理实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1. 创建项目 在 MyEclipse 中创建一个名称为 springDemo03 的 Web 项目,将 Spring 支持和依赖的 JAR 包复制到 Web 项目的 WEB-INF/lib 目录中,并发布到类路径下. 2. 创建接口 CustomerDao 在项目的 src 目录下创建一个名为 com.mengma.dao 的包,在该包下

  • 基于nginx设置浏览器协商缓存过程详解

    这篇文章主要介绍了基于nginx设置浏览器协商缓存过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 强缓存与协商缓存的区别 强缓存:浏览器不与服务端协商直接取浏览器缓存 协商缓存:浏览器会先向服务器确认资源的有效性后才决定是从缓存中取资源还是重新获取资源 协商缓存运作原理 现在有一个这样的业务情景:后端的静态资源会不定时地发生更新,而因为浏览器默认使用强缓存,会默认从浏览器缓存中取到过时的资源. 现在我们希望浏览器每次获取资源的时候都向后

  • SpringBoot2 整合FreeMarker实现页面静态化示例详解

    一.页面静态化 1.动静态页面 静态页面 即静态网页,指已经装载好内容HTML页面,无需经过请求服务器数据和编译过程,直接加载到客户浏览器上显示出来.通俗的说就是生成独立的HTML页面,且不与服务器进行数据交互. 优缺点描述: 静态网页的内容稳定,页面加载速度极快: 不与服务器交互,提升安全性: 静态网页的交互性差,数据实时性很低: 维度成本高,生成很多HTML页面: 动态页面 指跟静态网页相对的一种网页编程技术,页面的内容需要请求服务器获取,在不考虑缓存的情况下,服务接口的数据变化,页面加载的

  • Spring IoC学习之ApplicationContext中refresh过程详解

    refresh() 该方法是 Spring Bean 加载的核心,它是 ClassPathXmlApplicationContext 的父类 AbstractApplicationContext 的一个方法 , 顾名思义,用于刷新整个Spring 上下文信息,定义了整个 Spring 上下文加载的流程. public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShu

随机推荐