WebApplicationContextUtils
当 Web 应用集成 Spring 容器后,这个工具类就可以很方便的访问出一些web组件。比如`.
@Nullable public static WebApplicationContext getWebApplicationContext(ServletContext sc) { return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); } //Required这个方法和上面唯一的区别是:它如果返回null 就直接抛出异常了,上面是返回null public static WebApplicationContext getRequiredWebApplicationContext(ServletContext sc) throws IllegalStateException { WebApplicationContext wac = getWebApplicationContext(sc); if (wac == null) { throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?"); } return wac; } // 我在讲解源码的时候:创建容器失败的时候,也会吧异常放进来(我们调用者一般较少使用) public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) { ... } // 这个可以说是上面的加强版。当getWebApplicationContext(sc)没找到时,还会试从ServletContext的属性中查找唯一的一个WebApplicationContext // 如果找到的WebApplicationContext不唯一,则抛出异常声明该情况 public static WebApplicationContext findWebApplicationContext(ServletContext sc) { ... } //向WebApplicationContext使用的BeanFactory注册web有关作用域对象 : public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, @Nullable ServletContext sc) { beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope()); beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope()); if (sc != null) { ServletContextScope appScope = new ServletContextScope(sc); beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // Register as ServletContext attribute, for ContextCleanupListener to detect it. // 此处,还吧ServletContext上下文的Scope,注册到上下文里,方便ContextCleanupListener 进行获取 sc.setAttribute(ServletContextScope.class.getName(), appScope); } // 定义注入规则。当开发人员依赖注入ServletRequest对象时,注入的bean其实是这里的RequestObjectFactory工厂bean beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory()); beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory()); beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory()); // ServletWebRequest 里面既有request,也有response beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory()); if (jsfPresent) { FacesDependencyRegistrar.registerFacesDependencies(beanFactory); } }
接下来看看这个方法registerEnvironmentBeans:
public static void registerEnvironmentBeans(ConfigurableListableBeanFactory bf, @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) { // 把servletContext和servletConfig以Bean的形式,注册到容器里面,这样我们就可以@Autowired了 如下面例子 if (servletContext != null && !bf.containsBean(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME)) { bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext); } if (servletConfig != null && !bf.containsBean(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME)) { bf.registerSingleton(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME, servletConfig); } //这个特别特别重要:我们可以看到Spring在启动的时候,把ServletContext里面所有所有的InitParameter都拿出来了,存到一个Map里面 // 最后把这个Bean注册到容器里面了,Bean名称为:contextParameters // 这就是为什么,后面我们可以非常非常方便拿到initParam的原因~~~ if (!bf.containsBean(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME)) { Map<String, String> parameterMap = new HashMap<>(); if (servletContext != null) { Enumeration<?> paramNameEnum = servletContext.getInitParameterNames(); while (paramNameEnum.hasMoreElements()) { String paramName = (String) paramNameEnum.nextElement(); parameterMap.put(paramName, servletContext.getInitParameter(paramName)); } } if (servletConfig != null) { Enumeration<?> paramNameEnum = servletConfig.getInitParameterNames(); while (paramNameEnum.hasMoreElements()) { String paramName = (String) paramNameEnum.nextElement(); parameterMap.put(paramName, servletConfig.getInitParameter(paramName)); } } bf.registerSingleton(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME, Collections.unmodifiableMap(parameterMap)); } // 原理同上,这里吧ServletContext里面的contextAttributes,都以Bean的形式放进Bean容器里了 if (!bf.containsBean(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME)) { Map<String, Object> attributeMap = new HashMap<>(); if (servletContext != null) { Enumeration<?> attrNameEnum = servletContext.getAttributeNames(); while (attrNameEnum.hasMoreElements()) { String attrName = (String) attrNameEnum.nextElement(); attributeMap.put(attrName, servletContext.getAttribute(attrName)); } } bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME, Collections.unmodifiableMap(attributeMap)); } }
因为可以看到上面已经注册了Bean,因此我们可以这么来使用,直接注入即可:
@Autowired private ServletContext servletContext; @Autowired private ServletConfig servletConfig; @ResponseBody @GetMapping("/hello") public String helloGet() { System.out.println(servletContext); //org.apache.catalina.core.StandardWrapperFacade@1f3768f6 System.out.println(servletConfig); //org.apache.catalina.core.StandardContext$NoPluggabilityServletContext@73ced3c2 return "hello...Get"; }
//将 servletContext、servletConfig 添加到 propertySources public static void initServletPropertySources(MutablePropertySources sources, @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) { ... }
UrlPathHelper
这个帮助类非常的重要了,位于包org.springframework.web.util
内。它帮助Spring MVC处理URL相关的各种难题,先介绍它的几个属性~~~
public class UrlPathHelper { // 是否总是按照全路径 默认是false(一般不改~) private boolean alwaysUseFullPath = false; // 是否对url进行解码(默认都是需要解码的) 解码可以是request.getCharacterEncoding()。若没指定就是下面的defaultEncoding private boolean urlDecode = true; // 设置是否应从请求URI中删除“;”(分号) private boolean removeSemicolonContent = true; // 默认编码是它:ISO-8859-1 private String defaultEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING; ... }
它的API具体如图:
简单使用Demo如下:(我的请求地址为:http://localhost:8080/demo_war_war/api/v1/hello
@ResponseBody @GetMapping("/hello") public String helloGet(HttpServletRequest request) throws Exception { UrlPathHelper urlPathHelper = new UrlPathHelper(); System.out.println(urlPathHelper.getLookupPathForRequest(request)); // /api/v1/hello System.out.println(urlPathHelper.getOriginatingContextPath(request)); // /demo_war_war System.out.println(urlPathHelper.getContextPath(request)); // /demo_war_war System.out.println(urlPathHelper.getServletPath(request)); // /api/v1/hello System.out.println(urlPathHelper.getRequestUri(request)); // /demo_war_war/api/v1/hello return "hello...Get"; }
总之它就是Spring用来处理URL的工具类,若你在你的项目中有类似的需要,也可以参考使用的。同时还有:UriUtils、UriComponents、UriComponentsBuilder等等
总结
Spring-web这个jar包内提供给我们还是有几个比较好用的类的,大家知悉即可。
特别是request的包装类,还是非常好用的~