一: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. Codeforces.566F.Clique in the Divisibility Graph(DP)

    题目链接 \(Description\) 给定集合\(S=\{a_1,a_2,\ldots,a_n\}\),集合中两点之间有边当且仅当\(a_i|a_j\)或\(a_j|a_i\). 求\(S\)最大 ...

  2. 【BZOJ-1493】项链工厂 Splay

    1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1440  Solved: 626[Submit][Status] ...

  3. 简单单层bp神经网络

    单层bp神经网络是解决线性可回归问题的. 该代码是论文:https://medium.com/technology-invention-and-more/how-to-build-a-simple-n ...

  4. RabbitMQ 延时消息队列

    消息延时在日常随处可见: 1.订单创建10min之后不发起支付,自动取消. 2.30min定时推送一次邮件信息. 最常用到方式后台定时任务轮训,量小的时候可以使用,量大会出现数据读取会性能问题.Rab ...

  5. centos 7下安装MySQL5.7 的安装和配置

    原文链接:  http://blog.csdn.net/xyang81/article/details/51759200 安装环境:CentOS7 64位 MINI版,安装MySQL5.7 1.配置Y ...

  6. 使用 IntraWeb (11) - 基本控件之 TIWButton

    所在单元及继承链: IWCompButton.TIWButton < TIWCustomControl < TIWBaseHTMLControl < TIWBaseControl & ...

  7. request.getRequestDispatcher("").forward()中文乱码

    即使jsp页面的编码已设为“UTF-8”,有中文的地方还是会出现乱码,但是用response.sendRedirect不会出现此问题. 解决方案一: 不使用PrintWriter out=respon ...

  8. wifidog交叉编译

    本文主要记录在linux平台下.交叉编译wifidog并在openwrt平台上执行的过程.主要是针对wifidog源代码被改动后. 不得不亲自进行交叉编译移植的时候,所碰到的一些问题. (1)下载源代 ...

  9. 给第三方dll强签名

    假若我们要对第三方控件或者是其他的没有源代码的DLL文件想做类似的处理,增加强名称签名,怎么处理,是很多人都会面对的问题.     步骤: 1.首先采用反汇编工具ildasm生成中间语言. ildas ...

  10. 基于设备树的TQ2440的中断(2)

    下面以按键中断为例看看基于设备数的中断的用法: 设备树: tq2440_key { compatible = "tq2440,key"; interrupt-parent = &l ...