一:Spring Boot提供自动配置

通过查看WebMvcAutoConfiguration及WebMvcProperties的源码,可以发现Spring Boot为我们提供了如下的自动配置。

1,自动配置的ViewResolver

1)ContentNegotiatingViewResolver

这是Spring MVC提供的一个特殊的ViewResolver,ContentNegotiatingViewResolver不是自己处理View,而是代理给不同的ViewResolver来处理不同的View,所以它有最高的优先级。

2)BeanNameViewResolver

在控制器(@Controller)中的一个方法的返回值的字符串(视图名)会根据 BeanNameViewResolver去查找Bean的名称为返回字符串的View来渲染视图,下面举个例子

定义BeanNameViewResolver的Bean

  1. @Bean
  2. public BeanNameViewResolver beanNameViewResolver(){
  3. BeanNameViewResolver resolver= new BeanNameViewResolver();
  4. return resolver
  5. }

定义一个View的Bean,名称为jsonView

  1. @Bean
  2. public MappingJackson2JsonView jsonView(){
  3. MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
  4. return jsonView;
  5. }

在控制器中,返回值为字符串jsonView,它会找Bean的名称为jsonView的视图来渲染:

  1. @RequestMapping(value = "json",produces = {MediaType.APPLICATION_JSON_VALUE})
  2. public String json(Model model){
  3. Person single = new Person("aa",11);
  4. model.addAttribute("single",single);
  5. return "jsonView";
  6. }

3)InternalResourceViewResolver

这是一个常用的ViewResolver,主要通过设置前缀,后缀,以及控制器中方法来返回视图名的字符串,以得到实际页面,Spring Boot的源码如下:

  1. @Bean
  2. @ConditionalOnMissingBean
  3. public InternalResourceViewResolver defaultViewResolver() {
  4. InternalResourceViewResolver resolver = new InternalResourceViewResolver();
  5. resolver.setPrefix(this.mvcProperties.getView().getPrefix());
  6. resolver.setSuffix(this.mvcProperties.getView().getSuffix());
  7. return resolver;
  8. }

下面是WebMvcAutoConfiguration的源代码:

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package org.springframework.boot.autoconfigure.web;
  6. import java.util.Collection;
  7. import java.util.Collections;
  8. import java.util.Date;
  9. import java.util.Iterator;
  10. import java.util.List;
  11. import java.util.ListIterator;
  12. import java.util.Map;
  13. import java.util.Map.Entry;
  14. import javax.servlet.Servlet;
  15. import javax.servlet.http.HttpServletRequest;
  16. import org.apache.commons.logging.Log;
  17. import org.apache.commons.logging.LogFactory;
  18. import org.springframework.beans.factory.BeanFactory;
  19. import org.springframework.beans.factory.ListableBeanFactory;
  20. import org.springframework.beans.factory.NoSuchBeanDefinitionException;
  21. import org.springframework.beans.factory.ObjectProvider;
  22. import org.springframework.beans.factory.annotation.Autowired;
  23. import org.springframework.boot.autoconfigure.AutoConfigureAfter;
  24. import org.springframework.boot.autoconfigure.AutoConfigureOrder;
  25. import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
  26. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  27. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  28. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  29. import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
  30. import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
  31. import org.springframework.boot.autoconfigure.web.ResourceProperties.Chain;
  32. import org.springframework.boot.autoconfigure.web.ResourceProperties.Strategy;
  33. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  34. import org.springframework.boot.web.filter.OrderedHiddenHttpMethodFilter;
  35. import org.springframework.boot.web.filter.OrderedHttpPutFormContentFilter;
  36. import org.springframework.boot.web.filter.OrderedRequestContextFilter;
  37. import org.springframework.context.annotation.Bean;
  38. import org.springframework.context.annotation.Configuration;
  39. import org.springframework.context.annotation.Import;
  40. import org.springframework.context.annotation.Lazy;
  41. import org.springframework.context.annotation.Primary;
  42. import org.springframework.core.convert.converter.Converter;
  43. import org.springframework.core.convert.converter.GenericConverter;
  44. import org.springframework.core.io.Resource;
  45. import org.springframework.format.Formatter;
  46. import org.springframework.format.FormatterRegistry;
  47. import org.springframework.format.datetime.DateFormatter;
  48. import org.springframework.http.MediaType;
  49. import org.springframework.http.converter.HttpMessageConverter;
  50. import org.springframework.util.ClassUtils;
  51. import org.springframework.util.StringUtils;
  52. import org.springframework.validation.DefaultMessageCodesResolver;
  53. import org.springframework.validation.MessageCodesResolver;
  54. import org.springframework.validation.Validator;
  55. import org.springframework.web.HttpMediaTypeNotAcceptableException;
  56. import org.springframework.web.accept.ContentNegotiationManager;
  57. import org.springframework.web.accept.ContentNegotiationStrategy;
  58. import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
  59. import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
  60. import org.springframework.web.context.request.NativeWebRequest;
  61. import org.springframework.web.context.request.RequestContextListener;
  62. import org.springframework.web.filter.HiddenHttpMethodFilter;
  63. import org.springframework.web.filter.HttpPutFormContentFilter;
  64. import org.springframework.web.filter.RequestContextFilter;
  65. import org.springframework.web.servlet.DispatcherServlet;
  66. import org.springframework.web.servlet.HandlerExceptionResolver;
  67. import org.springframework.web.servlet.LocaleResolver;
  68. import org.springframework.web.servlet.View;
  69. import org.springframework.web.servlet.ViewResolver;
  70. import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
  71. import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
  72. import org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration;
  73. import org.springframework.web.servlet.config.annotation.ResourceChainRegistration;
  74. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration;
  75. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  76. import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
  77. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  78. import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
  79. import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
  80. import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
  81. import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
  82. import org.springframework.web.servlet.i18n.FixedLocaleResolver;
  83. import org.springframework.web.servlet.mvc.ParameterizableViewController;
  84. import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
  85. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
  86. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
  87. import org.springframework.web.servlet.resource.AppCacheManifestTransformer;
  88. import org.springframework.web.servlet.resource.GzipResourceResolver;
  89. import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
  90. import org.springframework.web.servlet.resource.ResourceResolver;
  91. import org.springframework.web.servlet.resource.VersionResourceResolver;
  92. import org.springframework.web.servlet.view.BeanNameViewResolver;
  93. import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
  94. import org.springframework.web.servlet.view.InternalResourceViewResolver;
  95. @Configuration
  96. @ConditionalOnWebApplication
  97. @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class})
  98. @ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
  99. @AutoConfigureOrder(-2147483638)
  100. @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})
  101. public class WebMvcAutoConfiguration {
  102. public static final String DEFAULT_PREFIX = "";
  103. public static final String DEFAULT_SUFFIX = "";
  104. public WebMvcAutoConfiguration() {
  105. }
  106. @Bean
  107. @ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
  108. public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
  109. return new OrderedHiddenHttpMethodFilter();
  110. }
  111. @Bean
  112. @ConditionalOnMissingBean({HttpPutFormContentFilter.class})
  113. @ConditionalOnProperty(
  114. prefix = "spring.mvc.formcontent.putfilter",
  115. name = {"enabled"},
  116. matchIfMissing = true
  117. )
  118. public OrderedHttpPutFormContentFilter httpPutFormContentFilter() {
  119. return new OrderedHttpPutFormContentFilter();
  120. }
  121. static class OptionalPathExtensionContentNegotiationStrategy implements ContentNegotiationStrategy {
  122. private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class.getName() + ".SKIP";
  123. private final ContentNegotiationStrategy delegate;
  124. OptionalPathExtensionContentNegotiationStrategy(ContentNegotiationStrategy delegate) {
  125. this.delegate = delegate;
  126. }
  127. public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {
  128. Object skip = webRequest.getAttribute(SKIP_ATTRIBUTE, 0);
  129. return skip != null && Boolean.parseBoolean(skip.toString()) ? Collections.emptyList() : this.delegate.resolveMediaTypes(webRequest);
  130. }
  131. }
  132. static final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping {
  133. private static final Log logger = LogFactory.getLog(WebMvcAutoConfiguration.WelcomePageHandlerMapping.class);
  134. private WelcomePageHandlerMapping(Resource welcomePage, String staticPathPattern) {
  135. if (welcomePage != null && "/**".equals(staticPathPattern)) {
  136. logger.info("Adding welcome page: " + welcomePage);
  137. ParameterizableViewController controller = new ParameterizableViewController();
  138. controller.setViewName("forward:index.html");
  139. this.setRootHandler(controller);
  140. this.setOrder(0);
  141. }
  142. }
  143. public Object getHandlerInternal(HttpServletRequest request) throws Exception {
  144. Iterator var2 = this.getAcceptedMediaTypes(request).iterator();
  145. MediaType mediaType;
  146. do {
  147. if (!var2.hasNext()) {
  148. return null;
  149. }
  150. mediaType = (MediaType)var2.next();
  151. } while(!mediaType.includes(MediaType.TEXT_HTML));
  152. return super.getHandlerInternal(request);
  153. }
  154. private List<MediaType> getAcceptedMediaTypes(HttpServletRequest request) {
  155. String acceptHeader = request.getHeader("Accept");
  156. return MediaType.parseMediaTypes(StringUtils.hasText(acceptHeader) ? acceptHeader : "*/*");
  157. }
  158. }
  159. private static class ResourceChainResourceHandlerRegistrationCustomizer implements WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer {
  160. @Autowired
  161. private ResourceProperties resourceProperties;
  162. private ResourceChainResourceHandlerRegistrationCustomizer() {
  163. this.resourceProperties = new ResourceProperties();
  164. }
  165. public void customize(ResourceHandlerRegistration registration) {
  166. Chain properties = this.resourceProperties.getChain();
  167. this.configureResourceChain(properties, registration.resourceChain(properties.isCache()));
  168. }
  169. private void configureResourceChain(Chain properties, ResourceChainRegistration chain) {
  170. Strategy strategy = properties.getStrategy();
  171. if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {
  172. chain.addResolver(this.getVersionResourceResolver(strategy));
  173. }
  174. if (properties.isGzipped()) {
  175. chain.addResolver(new GzipResourceResolver());
  176. }
  177. if (properties.isHtmlApplicationCache()) {
  178. chain.addTransformer(new AppCacheManifestTransformer());
  179. }
  180. }
  181. private ResourceResolver getVersionResourceResolver(Strategy properties) {
  182. VersionResourceResolver resolver = new VersionResourceResolver();
  183. if (properties.getFixed().isEnabled()) {
  184. String version = properties.getFixed().getVersion();
  185. String[] paths = properties.getFixed().getPaths();
  186. resolver.addFixedVersionStrategy(version, paths);
  187. }
  188. if (properties.getContent().isEnabled()) {
  189. String[] paths = properties.getContent().getPaths();
  190. resolver.addContentVersionStrategy(paths);
  191. }
  192. return resolver;
  193. }
  194. }
  195. interface ResourceHandlerRegistrationCustomizer {
  196. void customize(ResourceHandlerRegistration var1);
  197. }
  198. @Configuration
  199. @ConditionalOnEnabledResourceChain
  200. static class ResourceChainCustomizerConfiguration {
  201. ResourceChainCustomizerConfiguration() {
  202. }
  203. @Bean
  204. public WebMvcAutoConfiguration.ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer() {
  205. return new WebMvcAutoConfiguration.ResourceChainResourceHandlerRegistrationCustomizer();
  206. }
  207. }
  208. @Configuration
  209. public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
  210. private final WebMvcProperties mvcProperties;
  211. private final ListableBeanFactory beanFactory;
  212. private final WebMvcRegistrations mvcRegistrations;
  213. public EnableWebMvcConfiguration(ObjectProvider<WebMvcProperties> mvcPropertiesProvider, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
  214. this.mvcProperties = (WebMvcProperties)mvcPropertiesProvider.getIfAvailable();
  215. this.mvcRegistrations = (WebMvcRegistrations)mvcRegistrationsProvider.getIfUnique();
  216. this.beanFactory = beanFactory;
  217. }
  218. @Bean
  219. public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
  220. RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
  221. adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null ? true : this.mvcProperties.isIgnoreDefaultModelOnRedirect());
  222. return adapter;
  223. }
  224. protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
  225. return this.mvcRegistrations != null && this.mvcRegistrations.getRequestMappingHandlerAdapter() != null ? this.mvcRegistrations.getRequestMappingHandlerAdapter() : super.createRequestMappingHandlerAdapter();
  226. }
  227. @Bean
  228. @Primary
  229. public RequestMappingHandlerMapping requestMappingHandlerMapping() {
  230. return super.requestMappingHandlerMapping();
  231. }
  232. @Bean
  233. public Validator mvcValidator() {
  234. return !ClassUtils.isPresent("javax.validation.Validator", this.getClass().getClassLoader()) ? super.mvcValidator() : WebMvcValidator.get(this.getApplicationContext(), this.getValidator());
  235. }
  236. protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
  237. return this.mvcRegistrations != null && this.mvcRegistrations.getRequestMappingHandlerMapping() != null ? this.mvcRegistrations.getRequestMappingHandlerMapping() : super.createRequestMappingHandlerMapping();
  238. }
  239. protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
  240. try {
  241. return (ConfigurableWebBindingInitializer)this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
  242. } catch (NoSuchBeanDefinitionException var2) {
  243. return super.getConfigurableWebBindingInitializer();
  244. }
  245. }
  246. protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {
  247. return this.mvcRegistrations != null && this.mvcRegistrations.getExceptionHandlerExceptionResolver() != null ? this.mvcRegistrations.getExceptionHandlerExceptionResolver() : super.createExceptionHandlerExceptionResolver();
  248. }
  249. protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
  250. super.configureHandlerExceptionResolvers(exceptionResolvers);
  251. if (exceptionResolvers.isEmpty()) {
  252. this.addDefaultHandlerExceptionResolvers(exceptionResolvers);
  253. }
  254. if (this.mvcProperties.isLogResolvedException()) {
  255. Iterator var2 = exceptionResolvers.iterator();
  256. while(var2.hasNext()) {
  257. HandlerExceptionResolver resolver = (HandlerExceptionResolver)var2.next();
  258. if (resolver instanceof AbstractHandlerExceptionResolver) {
  259. ((AbstractHandlerExceptionResolver)resolver).setWarnLogCategory(resolver.getClass().getName());
  260. }
  261. }
  262. }
  263. }
  264. @Bean
  265. public ContentNegotiationManager mvcContentNegotiationManager() {
  266. ContentNegotiationManager manager = super.mvcContentNegotiationManager();
  267. List<ContentNegotiationStrategy> strategies = manager.getStrategies();
  268. ListIterator iterator = strategies.listIterator();
  269. while(iterator.hasNext()) {
  270. ContentNegotiationStrategy strategy = (ContentNegotiationStrategy)iterator.next();
  271. if (strategy instanceof PathExtensionContentNegotiationStrategy) {
  272. iterator.set(new WebMvcAutoConfiguration.OptionalPathExtensionContentNegotiationStrategy(strategy));
  273. }
  274. }
  275. return manager;
  276. }
  277. }
  278. @Configuration
  279. @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
  280. @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
  281. public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
  282. private static final Log logger = LogFactory.getLog(WebMvcConfigurerAdapter.class);
  283. private final ResourceProperties resourceProperties;
  284. private final WebMvcProperties mvcProperties;
  285. private final ListableBeanFactory beanFactory;
  286. private final HttpMessageConverters messageConverters;
  287. final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
  288. public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, @Lazy HttpMessageConverters messageConverters, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {
  289. this.resourceProperties = resourceProperties;
  290. this.mvcProperties = mvcProperties;
  291. this.beanFactory = beanFactory;
  292. this.messageConverters = messageConverters;
  293. this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
  294. }
  295. public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
  296. converters.addAll(this.messageConverters.getConverters());
  297. }
  298. public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
  299. Long timeout = this.mvcProperties.getAsync().getRequestTimeout();
  300. if (timeout != null) {
  301. configurer.setDefaultTimeout(timeout.longValue());
  302. }
  303. }
  304. public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
  305. Map<String, MediaType> mediaTypes = this.mvcProperties.getMediaTypes();
  306. Iterator var3 = mediaTypes.entrySet().iterator();
  307. while(var3.hasNext()) {
  308. Entry<String, MediaType> mediaType = (Entry)var3.next();
  309. configurer.mediaType((String)mediaType.getKey(), (MediaType)mediaType.getValue());
  310. }
  311. }
  312. @Bean
  313. @ConditionalOnMissingBean
  314. public InternalResourceViewResolver defaultViewResolver() {
  315. InternalResourceViewResolver resolver = new InternalResourceViewResolver();
  316. resolver.setPrefix(this.mvcProperties.getView().getPrefix());
  317. resolver.setSuffix(this.mvcProperties.getView().getSuffix());
  318. return resolver;
  319. }
  320. @Bean
  321. @ConditionalOnBean({View.class})
  322. @ConditionalOnMissingBean
  323. public BeanNameViewResolver beanNameViewResolver() {
  324. BeanNameViewResolver resolver = new BeanNameViewResolver();
  325. resolver.setOrder(2147483637);
  326. return resolver;
  327. }
  328. @Bean
  329. @ConditionalOnBean({ViewResolver.class})
  330. @ConditionalOnMissingBean(
  331. name = {"viewResolver"},
  332. value = {ContentNegotiatingViewResolver.class}
  333. )
  334. public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
  335. ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
  336. resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
  337. resolver.setOrder(-2147483648);
  338. return resolver;
  339. }
  340. @Bean
  341. @ConditionalOnMissingBean
  342. @ConditionalOnProperty(
  343. prefix = "spring.mvc",
  344. name = {"locale"}
  345. )
  346. public LocaleResolver localeResolver() {
  347. if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.WebMvcProperties.LocaleResolver.FIXED) {
  348. return new FixedLocaleResolver(this.mvcProperties.getLocale());
  349. } else {
  350. AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
  351. localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
  352. return localeResolver;
  353. }
  354. }
  355. @Bean
  356. @ConditionalOnProperty(
  357. prefix = "spring.mvc",
  358. name = {"date-format"}
  359. )
  360. public Formatter<Date> dateFormatter() {
  361. return new DateFormatter(this.mvcProperties.getDateFormat());
  362. }
  363. public MessageCodesResolver getMessageCodesResolver() {
  364. if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
  365. DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
  366. resolver.setMessageCodeFormatter(this.mvcProperties.getMessageCodesResolverFormat());
  367. return resolver;
  368. } else {
  369. return null;
  370. }
  371. }
  372. public void addFormatters(FormatterRegistry registry) {
  373. Iterator var2 = this.getBeansOfType(Converter.class).iterator();
  374. while(var2.hasNext()) {
  375. Converter<?, ?> converter = (Converter)var2.next();
  376. registry.addConverter(converter);
  377. }
  378. var2 = this.getBeansOfType(GenericConverter.class).iterator();
  379. while(var2.hasNext()) {
  380. GenericConverter converter = (GenericConverter)var2.next();
  381. registry.addConverter(converter);
  382. }
  383. var2 = this.getBeansOfType(Formatter.class).iterator();
  384. while(var2.hasNext()) {
  385. Formatter<?> formatter = (Formatter)var2.next();
  386. registry.addFormatter(formatter);
  387. }
  388. }
  389. private <T> Collection<T> getBeansOfType(Class<T> type) {
  390. return this.beanFactory.getBeansOfType(type).values();
  391. }
  392. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  393. if (!this.resourceProperties.isAddMappings()) {
  394. logger.debug("Default resource handling disabled");
  395. } else {
  396. Integer cachePeriod = this.resourceProperties.getCachePeriod();
  397. if (!registry.hasMappingForPattern("/webjars/**")) {
  398. this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(cachePeriod));
  399. }
  400. String staticPathPattern = this.mvcProperties.getStaticPathPattern();
  401. if (!registry.hasMappingForPattern(staticPathPattern)) {
  402. this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(this.resourceProperties.getStaticLocations()).setCachePeriod(cachePeriod));
  403. }
  404. }
  405. }
  406. @Bean
  407. public WebMvcAutoConfiguration.WelcomePageHandlerMapping welcomePageHandlerMapping(ResourceProperties resourceProperties) {
  408. return new WebMvcAutoConfiguration.WelcomePageHandlerMapping(resourceProperties.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
  409. }
  410. private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
  411. if (this.resourceHandlerRegistrationCustomizer != null) {
  412. this.resourceHandlerRegistrationCustomizer.customize(registration);
  413. }
  414. }
  415. @Bean
  416. @ConditionalOnMissingBean({RequestContextListener.class, RequestContextFilter.class})
  417. public static RequestContextFilter requestContextFilter() {
  418. return new OrderedRequestContextFilter();
  419. }
  420. @Configuration
  421. @ConditionalOnProperty(
  422. value = {"spring.mvc.favicon.enabled"},
  423. matchIfMissing = true
  424. )
  425. public static class FaviconConfiguration {
  426. private final ResourceProperties resourceProperties;
  427. public FaviconConfiguration(ResourceProperties resourceProperties) {
  428. this.resourceProperties = resourceProperties;
  429. }
  430. @Bean
  431. public SimpleUrlHandlerMapping faviconHandlerMapping() {
  432. SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
  433. mapping.setOrder(-2147483647);
  434. mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", this.faviconRequestHandler()));
  435. return mapping;
  436. }
  437. @Bean
  438. public ResourceHttpRequestHandler faviconRequestHandler() {
  439. ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
  440. requestHandler.setLocations(this.resourceProperties.getFaviconLocations());
  441. return requestHandler;
  442. }
  443. }
  444. }
  445. }

WebMvcProperties的源码如下:

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package org.springframework.boot.autoconfigure.web;
  6. import java.util.LinkedHashMap;
  7. import java.util.Locale;
  8. import java.util.Map;
  9. import org.springframework.boot.context.properties.ConfigurationProperties;
  10. import org.springframework.http.MediaType;
  11. import org.springframework.validation.DefaultMessageCodesResolver.Format;
  12. @ConfigurationProperties(
  13. prefix = "spring.mvc"
  14. )
  15. public class WebMvcProperties {
  16. private Format messageCodesResolverFormat;
  17. private Locale locale;
  18. private WebMvcProperties.LocaleResolver localeResolver;
  19. private String dateFormat;
  20. private boolean dispatchTraceRequest;
  21. private boolean dispatchOptionsRequest;
  22. private boolean ignoreDefaultModelOnRedirect;
  23. private boolean throwExceptionIfNoHandlerFound;
  24. private boolean logResolvedException;
  25. private Map<String, MediaType> mediaTypes;
  26. private String staticPathPattern;
  27. private final WebMvcProperties.Async async;
  28. private final WebMvcProperties.Servlet servlet;
  29. private final WebMvcProperties.View view;
  30. public WebMvcProperties() {
  31. this.localeResolver = WebMvcProperties.LocaleResolver.ACCEPT_HEADER;
  32. this.dispatchTraceRequest = false;
  33. this.dispatchOptionsRequest = true;
  34. this.ignoreDefaultModelOnRedirect = true;
  35. this.throwExceptionIfNoHandlerFound = false;
  36. this.logResolvedException = false;
  37. this.mediaTypes = new LinkedHashMap();
  38. this.staticPathPattern = "/**";
  39. this.async = new WebMvcProperties.Async();
  40. this.servlet = new WebMvcProperties.Servlet();
  41. this.view = new WebMvcProperties.View();
  42. }
  43. public Format getMessageCodesResolverFormat() {
  44. return this.messageCodesResolverFormat;
  45. }
  46. public void setMessageCodesResolverFormat(Format messageCodesResolverFormat) {
  47. this.messageCodesResolverFormat = messageCodesResolverFormat;
  48. }
  49. public Locale getLocale() {
  50. return this.locale;
  51. }
  52. public void setLocale(Locale locale) {
  53. this.locale = locale;
  54. }
  55. public WebMvcProperties.LocaleResolver getLocaleResolver() {
  56. return this.localeResolver;
  57. }
  58. public void setLocaleResolver(WebMvcProperties.LocaleResolver localeResolver) {
  59. this.localeResolver = localeResolver;
  60. }
  61. public String getDateFormat() {
  62. return this.dateFormat;
  63. }
  64. public void setDateFormat(String dateFormat) {
  65. this.dateFormat = dateFormat;
  66. }
  67. public boolean isIgnoreDefaultModelOnRedirect() {
  68. return this.ignoreDefaultModelOnRedirect;
  69. }
  70. public void setIgnoreDefaultModelOnRedirect(boolean ignoreDefaultModelOnRedirect) {
  71. this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect;
  72. }
  73. public boolean isThrowExceptionIfNoHandlerFound() {
  74. return this.throwExceptionIfNoHandlerFound;
  75. }
  76. public void setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound) {
  77. this.throwExceptionIfNoHandlerFound = throwExceptionIfNoHandlerFound;
  78. }
  79. public boolean isLogResolvedException() {
  80. return this.logResolvedException;
  81. }
  82. public void setLogResolvedException(boolean logResolvedException) {
  83. this.logResolvedException = logResolvedException;
  84. }
  85. public Map<String, MediaType> getMediaTypes() {
  86. return this.mediaTypes;
  87. }
  88. public void setMediaTypes(Map<String, MediaType> mediaTypes) {
  89. this.mediaTypes = mediaTypes;
  90. }
  91. public boolean isDispatchOptionsRequest() {
  92. return this.dispatchOptionsRequest;
  93. }
  94. public void setDispatchOptionsRequest(boolean dispatchOptionsRequest) {
  95. this.dispatchOptionsRequest = dispatchOptionsRequest;
  96. }
  97. public boolean isDispatchTraceRequest() {
  98. return this.dispatchTraceRequest;
  99. }
  100. public void setDispatchTraceRequest(boolean dispatchTraceRequest) {
  101. this.dispatchTraceRequest = dispatchTraceRequest;
  102. }
  103. public String getStaticPathPattern() {
  104. return this.staticPathPattern;
  105. }
  106. public void setStaticPathPattern(String staticPathPattern) {
  107. this.staticPathPattern = staticPathPattern;
  108. }
  109. public WebMvcProperties.Async getAsync() {
  110. return this.async;
  111. }
  112. public WebMvcProperties.Servlet getServlet() {
  113. return this.servlet;
  114. }
  115. public WebMvcProperties.View getView() {
  116. return this.view;
  117. }
  118. public static enum LocaleResolver {
  119. FIXED,
  120. ACCEPT_HEADER;
  121. private LocaleResolver() {
  122. }
  123. }
  124. public static class View {
  125. private String prefix;
  126. private String suffix;
  127. public View() {
  128. }
  129. public String getPrefix() {
  130. return this.prefix;
  131. }
  132. public void setPrefix(String prefix) {
  133. this.prefix = prefix;
  134. }
  135. public String getSuffix() {
  136. return this.suffix;
  137. }
  138. public void setSuffix(String suffix) {
  139. this.suffix = suffix;
  140. }
  141. }
  142. public static class Servlet {
  143. private int loadOnStartup = -1;
  144. public Servlet() {
  145. }
  146. public int getLoadOnStartup() {
  147. return this.loadOnStartup;
  148. }
  149. public void setLoadOnStartup(int loadOnStartup) {
  150. this.loadOnStartup = loadOnStartup;
  151. }
  152. }
  153. public static class Async {
  154. private Long requestTimeout;
  155. public Async() {
  156. }
  157. public Long getRequestTimeout() {
  158. return this.requestTimeout;
  159. }
  160. public void setRequestTimeout(Long requestTimeout) {
  161. this.requestTimeout = requestTimeout;
  162. }
  163. }
  164. }

2,自动配置的静态资源

在自动配置类的addResourceHandlers方法中定义了以下静态资源的自动配置。

1)类路径文件

把类路径下的/static,/public,/resources和/META-INF/resources文件夹下的静态文件直接映射为/**,可以通过http://localhost:8080/**来访问。

2)webjar

何谓webjar,webjar就是将是我们常用的脚本框架封装在jar包中的jar包,更多关于webjar的内容请访问http://www.webjars.org网站

把webjar的/META-INF/resources/webjars/下的静态文件映射为/webjar/**,可以通过http://localhost:8080/webjar/**来访问

3,自动配置的Formatter和Converter

关于自动配置的Formatter和Converter,我们可以看一下WebMvcAutoConfiguration类中的定义:

  1. public void addFormatters(FormatterRegistry registry) {
  2. Iterator var2 = this.getBeansOfType(Converter.class).iterator();
  3. while(var2.hasNext()) {
  4. Converter<?, ?> converter = (Converter)var2.next();
  5. registry.addConverter(converter);
  6. }
  7. var2 = this.getBeansOfType(GenericConverter.class).iterator();
  8. while(var2.hasNext()) {
  9. GenericConverter converter = (GenericConverter)var2.next();
  10. registry.addConverter(converter);
  11. }
  12. var2 = this.getBeansOfType(Formatter.class).iterator();
  13. while(var2.hasNext()) {
  14. Formatter<?> formatter = (Formatter)var2.next();
  15. registry.addFormatter(formatter);
  16. }
  17. }

从代码中可以看出,只要我们定义了Converter,GenericConverter和Formatter接口的事项类的Bean,这些Bean就会自动注册到Spring MVC中。

4,自动配置的HttpMessageConverters

在WebMvcAutoConfiguration中,我们注册了messageConverters,代码如下:

  1. @Configuration
  2. @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
  3. @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
  4. public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
  5. private static final Log logger = LogFactory.getLog(WebMvcConfigurerAdapter.class);
  6. private final ResourceProperties resourceProperties;
  7. private final WebMvcProperties mvcProperties;
  8. private final ListableBeanFactory beanFactory;
  9. private final HttpMessageConverters messageConverters;
  10. final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
  11. public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, @Lazy HttpMessageConverters messageConverters, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {
  12. this.resourceProperties = resourceProperties;
  13. this.mvcProperties = mvcProperties;
  14. this.beanFactory = beanFactory;
  15. this.messageConverters = messageConverters;
  16. this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
  17. }
  18. public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
  19. converters.addAll(this.messageConverters.getConverters());
  20. }
  21. public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
  22. Long timeout = this.mvcProperties.getAsync().getRequestTimeout();
  23. if (timeout != null) {
  24. configurer.setDefaultTimeout(timeout.longValue());
  25. }
  26. }

在这里直接注入了HttpMessageConverters的Bean,而这个Bean是在HttpMessageConvertersAutoConfiguration类中定义的,我们自动扫描注册的HttpMessage Converter除了Spring MVC默认的ByteArrayHttpMessageConverter,StringHttpMessage Converter,Resource HttpMessageConverter等外,还自动配置文件里引入了JacksonHttpMessageConverters Configuration和GsonHttpMessage ConverterConfiguration,使我们获得了额外的HttpMessageConverter:

若jackson的jar包在路径上,则Spring Boot通过JacksonHttpMessage Converters Configuration增加了MappingJackson2HttpMessage Converter和Mapping Jackson2XmlHttpMessageConverter

若gson的jar包在路径上,则Spring Boot通过GsonHttpMessageConverterConfiguration增加GsonHttpMessageConverter

在Spring Boot中如果要新增自定义的HttpMessageConverter,则只需定义一个你自己的HttpMessageConverters的Bean,然后在此Bean中注册自定义的HttpMessageConverter即可,如下:

  1. @Bean
  2. public HttpMessageConverters customConverters(){
  3. HttpMessageConverter<?> customConverter1 = new CustomConverter1();
  4. HttpMessageConverter<?> customConverter2 = new CustomConverter2();
  5. return new HttpMessageConverters(customConverter1,customConverter2)
  6. }

5,静态首页的支持

把静态index.html文件放置在如下目录

classpath:/META-INF/resources/index.html

classpath:/resources/index.html

classpath:/static/index.html

classpath:/public/index.html

当我们访问应用根目录http://localhost:8080/时,会直接映射

二:接管Spring Boot的Web配置

如果Spring Boot提供的Spring MVC默认配置不符合需求,则可以通过一个配置类(注解有@Configuration的类)加上@EnableWebMvc注解来实现完全自己控制的MVC配置。

通常情况下,Spring Boot的自动配置是符合我们大多数需求的。在你既需要保留Spring Boot提供的便利,又需要增加自己额外的配置的时候,可以定义一个配置类并继承WebMvcConfigurerAdapter,无须使用@EnableWebMvc,例如:

  1. package jack.springmvc.config;
  2. import jack.springmvc.interceptor.DemoInterceptor;
  3. import jack.springmvc.messageconverter.MyMessageConverter;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.ComponentScan;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.http.converter.HttpMessageConverter;
  8. import org.springframework.scheduling.annotation.EnableScheduling;
  9. import org.springframework.web.multipart.MultipartResolver;
  10. import org.springframework.web.multipart.commons.CommonsMultipartResolver;
  11. import org.springframework.web.servlet.config.annotation.*;
  12. import org.springframework.web.servlet.view.InternalResourceViewResolver;
  13. import org.springframework.web.servlet.view.JstlView;
  14. import java.util.List;
  15. /**
  16. * Created by jack on 2017/7/16.
  17. */
  18. @Configuration
  19. @EnableWebMvc   //开启Spring MVC支持,若无此句,重写WebMvcConfigurerAdapter方法无效
  20. @ComponentScan("jack.springmvc")
  21. @EnableScheduling   //开启计划任务的支持
  22. //继承WebMvcConfigurerAdapter类,重写其方法可对Spring MVC进行配置
  23. public class MyMvcConfig extends WebMvcConfigurerAdapter{
  24. /**
  25. * 配置拦截器的Bean
  26. * @return
  27. */
  28. @Bean
  29. public DemoInterceptor demoInterceptor(){
  30. return new DemoInterceptor();
  31. }
  32. /**
  33. * 配置文件上传Bean
  34. * @return
  35. */
  36. @Bean
  37. public MultipartResolver multipartResolver(){
  38. CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
  39. multipartResolver.setMaxUploadSize(1000000);
  40. return multipartResolver;
  41. }
  42. /**
  43. * c重写addInterceptors方法,注册拦截器
  44. * @param registry
  45. */
  46. @Override
  47. public void addInterceptors(InterceptorRegistry registry) {
  48. //super.addInterceptors(registry);
  49. registry.addInterceptor(demoInterceptor());
  50. }
  51. @Bean
  52. public InternalResourceViewResolver viewResolver(){
  53. InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
  54. //viewResolver.setPrefix("/WEB-INF/classes/views/");
  55. viewResolver.setPrefix("/WEB-INF/classes/views/");
  56. viewResolver.setSuffix(".jsp");
  57. viewResolver.setViewClass(JstlView.class);
  58. return  viewResolver;
  59. }
  60. @Override
  61. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  62. //super.addResourceHandlers(registry);
  63. //addResourceLocations指的是文件放置的目录,addResourceHandler指的是对外暴露的访问路径
  64. registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");
  65. }
  66. /**
  67. * 统一处理没啥业务逻辑处理的controller请求,实现代码的简洁
  68. * @param registry
  69. */
  70. @Override
  71. public void addViewControllers(ViewControllerRegistry registry) {
  72. //super.addViewControllers(registry);
  73. registry.addViewController("/index").setViewName("/index");
  74. registry.addViewController("/toUpload").setViewName("upload");
  75. registry.addViewController("/converter").setViewName("/converter");
  76. registry.addViewController("/sse").setViewName("/sse");
  77. registry.addViewController("/async").setViewName("/async");
  78. }
  79. @Override
  80. public void configurePathMatch(PathMatchConfigurer configurer) {
  81. //super.configurePathMatch(configurer);
  82. configurer.setUseSuffixPatternMatch(false);
  83. }
  84. /**
  85. * 配置自定义的HttpMessageConverter的bean,在spring mvc里注册HttpMessageConverter有两个方法:
  86. * configureMessageConverters:重载会覆盖掉Spring MVC默认注册的多个HttpMessageConverter
  87. * extendMessageConverters:仅添加一个自定义的HttpMessageConverter,不覆盖默认注册的HttpMessageConverter
  88. * @param converters
  89. */
  90. @Override
  91. public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
  92. //super.extendMessageConverters(converters);
  93. converters.add(converter());
  94. }
  95. @Bean
  96. public MyMessageConverter converter(){
  97. return new MyMessageConverter();
  98. }
  99. }

上注意,上面重写了了addViewController方法,并不会覆盖WebMvcAutoConfiguration中的addViewController(在此方法中Spring Boot将“/”映射至index.html),这也就意味着我们自己的配置和Spring Boot的自动配置同时有效,这也是推荐添加自己的MVC配置的方式。

三:接注册Servlet,Filter,Listener

当使用嵌入式的Servlet容器时,我们通过将Servlet,Filter和Listener声明为Spring Bean而达到注册的效果;或者注册ServletRegistrationBean,FilterRegistrationBean和ServletListenerRegistrationBean的Bean。

1)直接注册Bean示例,代码如下:

  1. @Bean
  2. public XxServlet xxServlet(){
  3. return new XxServlet();
  4. }
  5. @Bean
  6. public YyFilter yyFilter(){
  7. return new YyFilter();
  8. }
  9. @Bean
  10. public ZzListener zzListener(){
  11. return new ZzListener()
  12. }

2)通过RegistrationBean

    1. @Bean
    2. public ServeletRegistrationBean serveletRegistrationBean(){
    3. return new ServeletRegistrationBean(new Xxservlet(),"/xx/*");
    4. }
    5. @Bean
    6. public FilterRegistrationBean filterRegistrationBean(){
    7. FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    8. registrationBean.setFilter(new YyFilter());
    9. registrationBean.setOrder(2);
    10. return registrationBean;
    11. }
    12. @Bean
    13. public ServletListenerRegistrationBean<ZzListener> zzListenerServletListenerRegistrationBean(){
    14. return new ServletListenerRegistrationBean<ZzListener>(new ZzListener())

springboot的Web开发-Web相关配置的更多相关文章

  1. SpringBoot学习(七)-->SpringBoot在web开发中的配置

    SpringBoot在web开发中的配置 Web开发的自动配置类:在Maven Dependencies-->spring-boot-1.5.2.RELEASE.jar-->org.spr ...

  2. 工具的更新换代 总是要折腾一下Windows10下Java Web 开发环境的配置

    Windows10下Java Web 开发环境的配置 由于经常性遗忘,所以整理一下 Java Web 开发环境的搭建与配置,利人利己 主要分为以下几步,需要可以挑着看 Windows下 JDK 的下载 ...

  3. IT兄弟连 Java Web教程 Web开发的相关知识

    Web基本概念 Web,是环球信息网的缩写,也称作“WWW.W3”,英文全称为World Wide Web,中文名成为万维网,常简称为Web.Web分为Web客户端和Web服务器程序.Web可以让We ...

  4. WEB开发的相关知识(Tomcat)

    Internet上供外界访问的Web资源分为 静态web资源(如html 页面):指web页面中供人们浏览的数据始终是不变. 动态web资源:指web页面中供人们浏览的数据是由程序产生的,不同时间点访 ...

  5. web开发之环境配置和文件系统

    web开发中有jsp,html,css,java,pictures等文件和程序,怎么组织他们,使其正确加载,是一个比较大的问题,就像一团乱麻,解不开啊.IDE是个大管家,要对它非常熟悉才可以,跟顺利地 ...

  6. Django Web开发基础环境配置流程

    创建虚拟环境 mkvirtualenv django_py3_1.11 -p python3 注意需要联网 安装Django 使用django 1.11.11版本,注意需要联网 pip install ...

  7. 9 Web开发——springmvc自动配置原理

    官方文档目录: https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-sp ...

  8. Web开发——Tomcat的配置

    1.选择Tomcat 1.Apache官网http://apache.org/ 2.Tomcat官网http://tomcat.apache.org/ 3.Tomcat下载地址http://tomca ...

  9. python的web开发环境Django配置

    我的系统的windows10: 第一步,安装python3.5 第二步,配置django,如图所示,在python的安装目录下的Scripts里面执行:pip install Django,我这儿提示 ...

随机推荐

  1. c# dapper mysql like 参数化

    //拼接sql语句: if (!string.IsNullOrEmpty(model.Email)) { where += " and a.email like @email "; ...

  2. Slickflow.NET 开源工作流引擎高级开发(二) -- 流程快速测试增值服务工具介绍

    前言:流程是由若干个任务节点组成,流转过程就是从一个节点转移到下一个节点,通常需要不断切换用户身份来完成流程的测试,这样使得测试效率比较低下,本文从实战出发,介绍常见的两种快速测试方法,用于提升流程测 ...

  3. STM32 USB FS Core and USB OTG Core

    STM32 USB-FS-Device development kit Compatible with the STM32F102xx and STM32F103xx series, STM32 L1 ...

  4. C# webrequest 抓取数据时,多个域Cookie的问题

    最近研究了下如何抓取为知笔记的内容,在抓取笔记里的图片内容时,老是提示403错误,用Chorme的开发者工具看了下: 这里的Cookie来自两个域,估计为知那边是验证了token(登录后才能获取到to ...

  5. Spring Boot 2.0 + zipkin 分布式跟踪系统快速入门

    原文:https://www.jianshu.com/p/9bfe103418e2 注意 Spring Boot 2.0之后,使用EnableZipkinServer创建自定义的zipkin服务器已经 ...

  6. rest api上传和下载文件

    rest api上传和下载文件 function FileToString(AFileName: string): string; var LMemoryStream: TMemoryStream; ...

  7. Odoo8出现Internal Server Error的解决办法之一

    转载地址:http://blog.sina.com.cn/s/blog_7cb52fa80102vaf3.html     问题: 不知怎么回事,我的Odoo8出错了,重装也一样出错信息如下 Inte ...

  8. 根据Request ID找到对应的Session信息

    2018年3月15日 13:04 /* Formatted on 2018/3/15 13:04:45 (QP5 v5.256.13226.35538) */ --根据Request ID找到对应的S ...

  9. Linux tar包相关命令

    tar [-j|-z][cv][-f 新建的文件名] filename... <==打包与压缩 tar [-j|-z][tv][-f 新建的文件名]   <==查看文件名 tar [-j| ...

  10. 使用 Crash 工具分析 Linux dump 文件

    转自:http://blog.csdn.net/commsea/article/details/11804897 简介: Linux 内核由于其复杂性,使得对内核出现的各种异常的追踪变得异常困难.本文 ...