Iv. Web development

1, the introduction of

Use SpringBoot;

1) Create the SpringBoot application and select the module we need;

2) SpringBoot has configured these scenarios by default and only needs to specify a few configurations in the configuration file to run

3) Write business code by myself;

How does automatic configuration work?

What does SpringBoot configure for us in this scenario? Can you change it? What configurations can be modified? Can it be extended? xxx

XxxxAutoConfiguration: help us auto-configure the components in the container; XxxxProperties: configuration class to encapsulate the contents of configuration files;Copy the code

2. SpringBoot mapping rules for static resources;

@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties implements ResourceLoaderAware {
  // You can set parameters related to static resources, cache time, etc
Copy the code
WebMvcAuotConfiguration:@Override
		public void addResourceHandlers(ResourceHandlerRegistry registry) {
			if (!this.resourceProperties.isAddMappings()) {
				logger.debug("Default resource handling disabled");
				return;
			}
			Integer cachePeriod = this.resourceProperties.getCachePeriod();
			if(! registry.hasMappingForPattern("/webjars/**")) {
				customizeResourceHandlerRegistration(
						registry.addResourceHandler("/webjars/**")
								.addResourceLocations(
										"classpath:/META-INF/resources/webjars/")
						.setCachePeriod(cachePeriod));
			}
			String staticPathPattern = this.mvcProperties.getStaticPathPattern();
          	// Static resource folder mapping
			if(! registry.hasMappingForPattern(staticPathPattern)) { customizeResourceHandlerRegistration( registry.addResourceHandler(staticPathPattern) .addResourceLocations(this.resourceProperties.getStaticLocations()) .setCachePeriod(cachePeriod)); }}// Configure the welcome page mapping
		@Bean
		public WelcomePageHandlerMapping welcomePageHandlerMapping( ResourceProperties resourceProperties) {
			return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(),
					this.mvcProperties.getStaticPathPattern());
		}

       // Configure a favorite icon
		@Configuration
		@ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)
		public static class FaviconConfiguration {

			private final ResourceProperties resourceProperties;

			public FaviconConfiguration(ResourceProperties resourceProperties) {
				this.resourceProperties = resourceProperties;
			}

			@Bean
			public SimpleUrlHandlerMapping faviconHandlerMapping(a) {
				SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
				mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
              	* * / / / all the favicon. Ico
				mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
						faviconRequestHandler()));
				return mapping;
			}

			@Bean
			public ResourceHttpRequestHandler faviconRequestHandler(a) {
				ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
				requestHandler
						.setLocations(this.resourceProperties.getFaviconLocations());
				returnrequestHandler; }}Copy the code

Classpath :/ meta-INF /resources/webjars/

localhost:8080/webjars/jquery/3.51./jquery.js
Copy the code

<! - introduction of jquery - webjar -- -- >Just write the name of the resource under WebJars when accessing it<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>jquery</artifactId>
			<version>3.3.1</version>
		</dependency>
Copy the code

2), “/**” to access any resources of the current project, go to (static resources folder) to find the mapping

"Classpath :/ meta-INF /resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" "/" : root path of the current projectCopy the code

  • Localhost :8080/ ABC === go to static resources (lasspath:/resources/) folder and find ABC

3) Welcome page; All index.html pages in the static resources folder; Mapped by “/**”;

Localhost :8080/ Find the index page

4) all **/favicon.ico are found under static resource files;

For example, set to replace the default home page and icon

  • Note: The default static resource path is the resource under the project. You can also modify the default static resource configuration to specify other folders as the default static resource configuration.
  • Under the application. Properties of the project, separate multiple classpath with a colon
spring.resource.static-location=classpath:/hello/,classPath:/xdr630/
Copy the code

Template engines

JSP, Velocity, Freemarker, Thymeleaf

Thymeleaf recommended by SpringBoot;

Simpler syntax and more power;

1. Introduce Thymeleaf;

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
Copy the code
  • You can see the version in the dependency:

  • Switch the thymeleaf version and import thymeleaf 2.1.6 by default. The version is too low and can be imported in POM.xml
<properties>
		<thymeleaf.version>3.0.9. RELEASE</thymeleaf.version>
		<! Support program for layout function Thymeleaf3 main program Layout2 or later -->
		<! -- thymeleaf2 layout1-->
		<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
Copy the code

2. Use Thymeleaf

@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {

	private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");

	private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");

	public static final String DEFAULT_PREFIX = "classpath:/templates/";

	public static final String DEFAULT_SUFFIX = ".html";
  	//
Copy the code
  • As long as we put the HTML page inclasspath:/templates/, Thymeleaf will render automatically;

Use:

1. Import the thymeleaf namespace, or do not import it.

<html lang="en" xmlns:th="http://www.thymeleaf.org">
Copy the code

2. Use thymeleaf syntax.

<! DOCTYPEhtml>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>Success!</h1>
    <! --th:text Sets the text content inside the div to -->
    <div th:text="${hello}">This is a welcome message</div>
</body>
</html>
Copy the code

3. Grammar rules

1), th:text; Change the text content of the current element.

Th:Any HTML attribute; To replace the value of the native property

2), expression?

Simple expressions () Variable expressions: ${... } : get the variable value; OGNL;1), get the properties of the object, and call methods2# CTX: The context object. # Vars: the context variables. #locale: the context locale. (only in Web Contexts) the HttpServletRequest object. #response : (only in Web Contexts) the HttpServletResponse object. #session : (only in Web Contexts) the HttpSession object. #servletContext : (only in Web Contexts) the ServletContext object. ${session.foo}3ExecInfo: information about the template being processed. # Messages: MethodsforObtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{... } syntax. #uris : methodsfor escaping parts of URLs/URIs
#conversions : methods for executing the configured conversion service (if any).
#dates : methods for java.util.Date objects: formatting, component extraction, etc.
#calendars : analogous to #dates , but for java.util.Calendar objects.
#numbers : methods for formatting numeric objects.
#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
#objects : methods for objects in general.
#bools : methods for boolean evaluation.
#arrays : methods for arrays.
#lists : methods for lists.
#sets : methods for sets.
#maps : methods for maps.
#aggregates : methods for creating aggregates on arrays or collections.
#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).

    Selection Variable Expressions: *{... } : select expression: and ${} function is the same; Add: match th:object="${session. User} : < div th: object ="${session.user}"> 

Name:

*{firstName}">Sebastian.

Surname:

*{lastName}">Pepper.

Nationality:

*{nationality}">Saturn.

Message Expressions: #{... } : How do I get the URL? } : Define URL; @{/order/process(execId=${execId},execType='FAST')} Fragment Expressions: ~{... } : fragment reference expression
~{commons :: main}">... Literals Text Literals: 'One Text', 'Another one! ',... Number literals: 0, 34, 3.0, 12.3... Boolean literals: true, false Null literal: Null literal tokens: one, someText, main... Text Operations (Text Manipulation) String concatenation: + Literal substitutions: | | The name is ${name} Arithmetic operations (math) Binary operators: +, -, *, /, % Minus sign (unary operator) : -boolean operators: and, or Boolean negation (unary operator):! Word order: >, <= (gt, lt, GE, le) Equality operators: ==,! = (eq, ne) Conditional Operators: Conditional operators if-then: (If)? (then) If-then-else: (if) ? (then) : (else) Default: (value) ? : (defaultvalue) Special tokens: No-Operation: _Copy the code

4. SpringMVC automatic configuration

Docs. Spring. IO/spring – the boot…

1. Spring MVC auto-configuration

Spring Boot automatically configures SpringMVC

Here is the default SpringBoot configuration for SpringMVC: (WebMvcAutoConfiguration)

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

    • The ViewResolver is automatically configured (the View resolver: based on the method’s return value to the View object, the View object decides how to render (forward? Redirect?) )
    • ContentNegotiatingViewResolver: combination of all the views of the parser;
    • How to customize: We can add a view parser to the container ourselves; Automatically combine them in;
  • Support for serving static resources, including support for WebJars (see below). Static resource folder path, Webjars

  • Static index.html support

  • Custom Favicon support (see below). favicon.ico

  • Automatically registers of Converter, GenericConverter, Formatter beans.

    • To Converter D. Public String hello(User User) : Type conversion using Converter
    • FormatterFormatter; 2017.12.17 = = = the Date;
		@Bean
		@ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")// Configure the date formatting rules in the file
		public Formatter<Date> dateFormatter(a) {
			return new DateFormatter(this.mvcProperties.getDateFormat());// Date formatting component
		}
Copy the code

The formatter converter we add ourselves, we just need to put it in the container

  • Support for HttpMessageConverters (see below).

    • HttpMessageConverter: used by SpringMVC to convert Http requests and responses; User – Json;

    • HttpMessageConverters is determined from the container; Get all HttpMessageConverter;

      Add your own HttpMessageConverter to the container by registering your own components in the container (@bean,@Component)

  • Automatic registration of MessageCodesResolver (see below). Define error code generation rules

  • Automatic use of a ConfigurableWebBindingInitializer bean (see below).

    We can configure a ConfigurableWebBindingInitializer to replace the default; (Add to container)

    Initialize WebDataBinder; Request data =====JavaBean;Copy the code

Org. Springframework. Boot. Autoconfigure. Web: web all automatic scene;

If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own @Configuration class of type WebMvcConfigurerAdapter, but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you can declare a WebMvcRegistrationsAdapter instance providing such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

2. Extend SpringMVC

    <mvc:view-controller path="/hello" view-name="success"/>
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/hello"/>
            <bean></bean>
        </mvc:interceptor>
    </mvc:interceptors>
Copy the code

Write a Configuration class (@Configuration) of type WebMvcConfigurerAdapter. @enableWebMVC cannot be annotated;

It retains all automatic configuration and can use our extended configuration;

// The WebMvcConfigurerAdapter can be used to extend the SpringMVC functionality
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
       // super.addViewControllers(registry);
        // The browser sends /atguigu to success
        registry.addViewController("/atguigu").setViewName("success"); }}Copy the code

Principle:

WebMvcAutoConfiguration is an automatic configuration class of SpringMVC

2) It will be imported when doing other automatic configuration; @Import(EnableWebMvcConfiguration.class)

    @Configuration
	public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
      private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

	 // Get all WebMvcConfigurer files from the container
      @Autowired(required = false)
      public void setConfigurers(List<WebMvcConfigurer> configurers) {
          if(! CollectionUtils.isEmpty(configurers)) {this.configurers.addWebMvcConfigurers(configurers);
            	// a reference implementation; Call all WebMvcConfigurer configurations together.
            	@Override
             // public void addViewControllers(ViewControllerRegistry registry) {
              // for (WebMvcConfigurer delegate : this.delegates) {
               // delegate.addViewControllers(registry);
               / /}}}}Copy the code

3) All WebMvcConfigurer elements in the container work together;

4) Our configuration class will also be called;

Effect: SpringMVC’s auto-configuration and our extension configuration both work;

3. Take over SpringMVC;

The automatic configuration of SpringBoot for SpringMVC is no longer needed, everything is configured by ourselves; All SpringMVC auto-configuration is invalid

We need to add @enableWebMVC to the configuration class;

// The WebMvcConfigurerAdapter can be used to extend the SpringMVC functionality
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
       // super.addViewControllers(registry);
        // The browser sends /atguigu to success
        registry.addViewController("/atguigu").setViewName("success"); }}Copy the code

Principle:

Why @enableWebMVC auto-configuration is invalid;

1) @enableWebMVC core

@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
Copy the code

2),

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
Copy the code

3),

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class })
// The autoconfiguration class takes effect only when the component is not in the container
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
Copy the code

4), @ EnableWebMvc imported WebMvcConfigurationSupport components;

5), import WebMvcConfigurationSupport only the most basic function of for SpringMVC;

5. How to change the default SpringBoot configuration

Mode:

1) When SpringBoot automatically configits many components, it will first see if there are any user-configured components (@bean, @Component) in the container. If there are any, it will use user-configured components; if not, it will automatically configure them. If some components can have more than one (ViewResolver), combine the user-configured and its own default;

2) There are a number of xxxConfigurer extensions available in SpringBoot

3) There are many xxxCustomizers available in SpringBoot to help us customize the configuration

6, RestfulCRUD

1) Access the home page by default


// The WebMvcConfigurerAdapter can be used to extend the SpringMVC functionality
// @enableWebMVC do not take over SpringMVC
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
       // super.addViewControllers(registry);
        // The browser sends /atguigu to success
        registry.addViewController("/atguigu").setViewName("success");
    }

    // All the WebMvcConfigurerAdapter components work together
    @Bean // Register the component in the container
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(a){
        WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/index.html").setViewName("login"); }};returnadapter; }}Copy the code

2) Internationalization

1) Write internationalization configuration files;

2), use ResourceBundleMessageSource management internationalization resource files

3) Use FMT :message to retrieve internationalized content

Steps:

1) Write internationalization configuration files and extract the internationalization messages that need to be displayed on the page

2) SpringBoot is automatically configured to manage international resource files;

@ConfigurationProperties(prefix = "spring.messages")
public class MessageSourceAutoConfiguration {
    
    /** * Comma-separated list of basenames (essentially a fully-qualified classpath * location), each following the ResourceBundle convention with relaxed support for * slash based locations. If it doesn't contain a package qualifier (such as * "org.mypackage"), it will be resolved from the classpath root. */
	private String basename = "messages";  
    // Our configuration file can be placed directly in the classpath called messages.properties;
    
    @Bean
	public MessageSource messageSource(a) {
		ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
		if (StringUtils.hasText(this.basename)) {
            // Set the base name of the internationalized resource file (without the language country code)
			messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
					StringUtils.trimAllWhitespace(this.basename)));
		}
		if (this.encoding ! =null) {
			messageSource.setDefaultEncoding(this.encoding.name());
		}
		messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
		messageSource.setCacheSeconds(this.cacheSeconds);
		messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
		return messageSource;
	}
Copy the code

3) Go to the page to obtain the value of internationalization;

<! DOCTYPEhtml>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
		<meta name="description" content="">
		<meta name="author" content="">
		<title>Signin Template for Bootstrap</title>
		<! -- Bootstrap core CSS -->
		<link href="asserts/css/bootstrap.min.css" th:href="@ {/ webjars/bootstrap / 4.0.0 / CSS/bootstrap CSS}" rel="stylesheet">
		<! -- Custom styles for this template -->
		<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
	</head>

	<body class="text-center">
		<form class="form-signin" action="dashboard.html">
			<img class="mb-4" th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72">
			<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
			<label class="sr-only" th:text="#{login.username}">Username</label>
			<input type="text" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
			<label class="sr-only" th:text="#{login.password}">Password</label>
			<input type="password" class="form-control" placeholder="Password" th:placeholder="#{login.password}" required="">
			<div class="checkbox mb-3">
				<label>
          		<input type="checkbox" value="remember-me"/> [[#{login.remember}]]
        </label>
			</div>
			<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
			<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
			<a class="btn btn-sm">Chinese</a>
			<a class="btn btn-sm">English</a>
		</form>

	</body>

</html>
Copy the code

Effect: Switch internationalization based on the browser language Settings.

Principle:

Internationalized Locale (regional information objects); LocaleResolver (get region information object);

		@Bean
		@ConditionalOnMissingBean
		@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
		public LocaleResolver localeResolver(a) {
			if (this.mvcProperties
					.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
				return new FixedLocaleResolver(this.mvcProperties.getLocale());
			}
			AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
			localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
			returnlocaleResolver; } By default, the Locale Locale is retrieved from the request headerCopy the code

4) Click the link to switch to internationalization

/** * can carry region information on the connection */
public class MyLocaleResolver implements LocaleResolver {
    
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String l = request.getParameter("l");
        Locale locale = Locale.getDefault();
        if(! StringUtils.isEmpty(l)){ String[] split = l.split("_");
            locale = new Locale(split[0],split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {}}@Bean
    public LocaleResolver localeResolver(a){
        return newMyLocaleResolver(); }}Copy the code

3) Login

Changes to the template engine page during development take effect in real time

1) Disable template engine caching

# disable caching spring.thymeleaf.cache=falseCopy the code

2) CTRL + F9: recompile after page modification is completed;

Display of login error messages

<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
Copy the code

4) The interceptor performs landing inspection

The interceptor


/** * login check, */
public class LoginHandlerInterceptor implements HandlerInterceptor {
    // Before the target method is executed
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object user = request.getSession().getAttribute("loginUser");
        if(user == null) {// No login, return to login page
            request.setAttribute("msg"."No permission, please log in first.");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else{
            // Logged-in, release request
            return true; }}@Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}}Copy the code

Register interceptors

  // All the WebMvcConfigurerAdapter components work together
    @Bean // Register the component in the container
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(a){
        WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/index.html").setViewName("login");
                registry.addViewController("/main.html").setViewName("dashboard");
            }

            // Register interceptors
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                //super.addInterceptors(registry);
                // Static resources; *.css , *.js
                //SpringBoot has done static resource mapping
                registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/ * *")
                        .excludePathPatterns("/index.html"."/"."/user/login"); }};return adapter;
    }
Copy the code

5) CRUD- Employee list

Experimental requirements:

1) RestfulCRUD: CRUD meets Rest style;

URI: / Resource name/RESOURCE ID HTTP request mode Distinguishes CRUD operations on resources

Plain CRUD (URIs to distinguish operations) RestfulCRUD
The query getEmp Emp – GET
add addEmp? xxx Emp – POST
Modify the updateEmp? id=xxx&xxx=xx Emp / {id} – PUT
delete deleteEmp? id=1 Emp / {id} – DELETE

2) Request structure of experiment;

The experimental function The request URI Request way
Query all employees emps GET
Query an employee (go to the Modify page) emp/1 GET
Go to the Add page emp GET
Add employees emp POST
Go to the modify page (check out the staff for information echo) emp/1 GET
Modify the employee emp PUT
Delete staff emp/1 DELETE

3) Staff list:

Thymeleaf public page element extraction

1. Extract common fragments<div th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</div>2. Introduce public fragments<div th:insert="~{footer :: copy}"></div>~ {templatename: : the selector} : template name: : selector ~ {templatename: : fragmentname} : template name: : fragments of 3, the default effect: Insert: [[~{}]]; [[~{}]]; [[~{}]]; [[~{}]]; [(~ {})];Copy the code

Three th attributes introduced into public fragments:

Th: INSERT: Inserts the entire public fragment into the element introduced by the declaration

Th :replace: Replaces the element introduced by the declaration with a public fragment

Th :include: Includes the content of the introduced fragment in this tag

<footer th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</footer>Introducing way<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>The effect<div>
    <footer>
    &copy; 2011 The Good Thymes Virtual Grocery
    </footer>
</div>

<footer>
&copy; 2011 The Good Thymes Virtual Grocery
</footer>

<div>
&copy; 2011 The Good Thymes Virtual Grocery
</div>
Copy the code

To import a fragment, pass in a parameter:


<nav class="col-md-2 d-none d-md-block bg-light sidebar" id="sidebar">
    <div class="sidebar-sticky">
        <ul class="nav flex-column">
            <li class="nav-item">
                <a class="nav-link active"
                   th:class="${activeUri=='main.html'? 'nav-link active':'nav-link'}"
                   href="#" th:href="@{/main.html}">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox=24 24 "0 0" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home">
                        <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
                        <polyline points="9, 22, 9, 12, 15, 12, 15, 22"></polyline>
                    </svg>
                    Dashboard <span class="sr-only">(current)</span>
                </a>
            </li>

<! -- Introduce sidebar; Pass in parameters -->
<div th:replace="commons/bar::#sidebar(activeUri='emps')"></div>
Copy the code

6) CRUD- Employee addition

Add a page

<form>
    <div class="form-group">
        <label>LastName</label>
        <input type="text" class="form-control" placeholder="zhangsan">
    </div>
    <div class="form-group">
        <label>Email</label>
        <input type="email" class="form-control" placeholder="[email protected]">
    </div>
    <div class="form-group">
        <label>Gender</label><br/>
        <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="gender"  value="1">
            <label class="form-check-label">male</label>
        </div>
        <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="gender"  value="0">
            <label class="form-check-label">female</label>
        </div>
    </div>
    <div class="form-group">
        <label>department</label>
        <select class="form-control">
            <option>1</option>
            <option>2</option>
            <option>3</option>
            <option>4</option>
            <option>5</option>
        </select>
    </div>
    <div class="form-group">
        <label>Birth</label>
        <input type="text" class="form-control" placeholder="zhangsan">
    </div>
    <button type="submit" class="btn btn-primary">add</button>
</form>
Copy the code

Submitted data in incorrect format: date of birth: date;

The 2017-12-12; 2017/12/12; 2017.12.12;

Formatting of dates; SpringMVC converts page submitted values to the specified type;

The 2017-12-12 – Date; Type conversion, formatting;

The default date is a slash;

7) CRUD- Staff modification

Modified add 2-in-1 form

<! -- Need to distinguish between employee modification and addition; -->
<form th:action="@{/emp}" method="post">
    <! -- Send a put request to modify employee data -->
    <! -- Configure HiddenHttpMethodFilter in SpringMVC; Create a post form for the page; create an input item with name="_method"; The value is the request we specify -->
    <input type="hidden" name="_method" value="put" th:if="${emp! =null}"/>
    <input type="hidden" name="id" th:if="${emp! =null}" th:value="${emp.id}">
    <div class="form-group">
        <label>LastName</label>
        <input name="lastName" type="text" class="form-control" placeholder="zhangsan" th:value="${emp! =null}? ${emp.lastName}">
    </div>
    <div class="form-group">
        <label>Email</label>
        <input name="email" type="email" class="form-control" placeholder="[email protected]" th:value="${emp! =null}? ${emp.email}">
    </div>
    <div class="form-group">
        <label>Gender</label><br/>
        <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="gender" value="1" th:checked="${emp! =null}? ${emp.gender==1}">
            <label class="form-check-label">male</label>
        </div>
        <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="gender" value="0" th:checked="${emp! =null}? ${emp.gender==0}">
            <label class="form-check-label">female</label>
        </div>
    </div>
    <div class="form-group">
        <label>department</label>
        <! -- Submit the department ID -->
        <select class="form-control" name="department.id">
            <option th:selected="${emp! =null}? ${dept.id == emp.department.id}" th:value="${dept.id}" th:each="dept:${depts}" th:text="${dept.departmentName}">1</option>
        </select>
    </div>
    <div class="form-group">
        <label>Birth</label>
        <input name="birth" type="text" class="form-control" placeholder="zhangsan" th:value="${emp! =null}? ${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}">
    </div>
    <button type="submit" class="btn btn-primary" th:text="${emp! =null}? 'Modify ':' Add '">add</button>
</form>
Copy the code

8) CRUD- Delete staff

<tr th:each="emp:${emps}">
    <td th:text="${emp.id}"></td>
    <td>[[${emp.lastName}]]</td>
    <td th:text="${emp.email}"></td>
    <td th:text="${emp.gender}==0? 'Female ':' male'></td>
    <td th:text="${emp.department.departmentName}"></td>
    <td th:text="${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}"></td>
    <td>
        <a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.id}">The editor</a>
        <button th:attr="del_uri=@{/emp/}+${emp.id}" class="btn btn-sm btn-danger deleteBtn">delete</button>
    </td>
</tr>


<script>
    $(".deleteBtn").click(function(){
        // Delete the current employee
        $("#deleteEmpForm").attr("action", $(this).attr("del_uri")).submit();
        return false;
    });
</script>
Copy the code

7. Error handling

1) Default error handling mechanism of SpringBoot

Default effect:

1), browser, return a default error page

The browser sends the request header:

2) If it is another client, the default response is a JSON data

Principle:

Can consult ErrorMvcAutoConfiguration; Automatic configuration of error handling;

The following components are added to the containerCopy the code

1, DefaultErrorAttributes:

Help us share information on the page;@Override
	public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
			boolean includeStackTrace) {
		Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();
		errorAttributes.put("timestamp".new Date());
		addStatus(errorAttributes, requestAttributes);
		addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
		addPath(errorAttributes, requestAttributes);
		return errorAttributes;
	}
Copy the code

BasicErrorController: Handles default /error requests

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
    
    @RequestMapping(produces = "text/html")// Generate htML-type data; Requests sent by the browser come to this method for processing
	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
		HttpStatus status = getStatus(request);
		Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
				request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value());
        
        // which page to go to as the error page; Contains the page address and page content
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
		return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
	}

	@RequestMapping
	@ResponseBody    // Generate JSON data, which other clients come to process;
	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
		Map<String, Object> body = getErrorAttributes(request,
				isIncludeStackTrace(request, MediaType.ALL));
		HttpStatus status = getStatus(request);
		return new ResponseEntity<Map<String, Object>>(body, status);
	}
Copy the code

3, ErrorPageCustomizer:

	@Value("${error.path:/error}")
	private String path = "/error"; After the system error came to the error request for processing; (Error page rules for web.xml registration)Copy the code

4, DefaultErrorViewResolver:

@Override
	public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map
       
         model)
       ,> {
		ModelAndView modelAndView = resolve(String.valueOf(status), model);
		if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
			modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
		}
		return modelAndView;
	}

	private ModelAndView resolve(String viewName, Map<String, Object> model) {
        // Default SpringBoot can go to find a page? error/404
		String errorViewName = "error/" + viewName;
        
        // The template engine can parse the page address using the template engine
		TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
				.getProvider(errorViewName, this.applicationContext);
		if(provider ! =null) {
            // Return to the view address specified by errorViewName if the template engine is available
			return new ModelAndView(errorViewName, model);
		}
        // The template engine is not available, so look for error/404.html in the static resources folder for errorViewName
		return resolveResource(errorViewName, model);
	}
Copy the code

Steps:

If a 4XX or 5XX error occurs in the system; ErrorPageCustomizer takes effect (custom error response rules); It will come to the /error request; It will be handled by BasicErrorController;

1) Response page; Which page to go to is resolved by TerrorViewResolver;

protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map
       
         model)
       ,> {
    // All errorViewResolvers get ModelAndViews
   for (ErrorViewResolver resolver : this.errorViewResolvers) {
      ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
      if(modelAndView ! =null) {
         returnmodelAndView; }}return null;
}
Copy the code

2) If the error response is customized:

1) How to customize the wrong page;

1) With a template engine; Error/status code; [Name the error page as error status code. HTML and put it under the error folder in the template engine folder], the error of this status code will come to the corresponding page;

We can use 4xx and 5xx as error page filenames to match all errors of this type, precision first (looking for precise status code.html is preferred);

Information available to the page;

Timestamp: indicates the timestamp

Status: indicates the status code

Error: indicates an error message

Exception: exception object

“Message” : abnormal message

Errors: JSR303 data check errors are listed here

2) There is no template engine (template engine can not find this error page), static resources folder to find;

3) There is no error page above, which is the default error page of SpringBoot;

2) How to customize the wrong JSON data;

1) Custom exception handling & return custom JSON data;

@ControllerAdvice
public class MyExceptionHandler {

    @ResponseBody
    @ExceptionHandler(UserNotExistException.class)
    public Map<String,Object> handleException(Exception e){
        Map<String,Object> map = new HashMap<>();
        map.put("code"."user.notexist");
        map.put("message",e.getMessage());
        returnmap; }}// There is no adaptive effect...
Copy the code

2) Forward to /error for adaptive response effect processing

 @ExceptionHandler(UserNotExistException.class)
    public String handleException(Exception e, HttpServletRequest request){
        Map<String,Object> map = new HashMap<>();
        // Pass in our own error status code 4xx 5xx, otherwise we will not enter the custom error page parsing process
        /** * Integer statusCode = (Integer) request .getAttribute("javax.servlet.error.status_code"); * /
        request.setAttribute("javax.servlet.error.status_code".500);
        map.put("code"."user.notexist");
        map.put("message",e.getMessage());
        // Forward to /error
        return "forward:/error";
    }
Copy the code

3) Carry out our customized data;

After an error occurs, you get a /error request, which is handled by the BasicErrorController, The data that can be retrieved in response is obtained by getErrorAttributes (a method defined by AbstractErrorController);

Write an entirely ErrorController implementation class (or subclass AbstractErrorController) and put it in a container.

2, can use the data on a page, or is the json returned with data by errorAttributes. GetErrorAttributes get;

The container DefaultErrorAttributes. GetErrorAttributes (); Performing data processing by default;

Custom ErrorAttributes

// Add our own ErrorAttributes to the container
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {

    @Override
    public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
        Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
        map.put("company"."atguigu");
        returnmap; }}Copy the code

The end result: The response is adaptive, and you can customize the ErrorAttributes to change what needs to be returned,

Configure the embedded Servlet container

SpringBoot uses Tomcat as the embedded Servlet container by default;

The problem?

1) How to customize and modify the configuration of the Servlet container;

1, modify, and server configuration (ServerProperties) is also EmbeddedServletContainerCustomizer 】 【;

server.port=8081
server.context-path=/crud

server.tomcat.uri-encoding=UTF-8

// Generic Servlet container Settings
server.xxx
/ / Tomcat Settings
server.tomcat.xxx
Copy the code

2, write a EmbeddedServletContainerCustomizer: embedded Servlet container custom; To modify the configuration of the Servlet container

@Bean  // Be sure to add the customizer to the container
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(a){
    return new EmbeddedServletContainerCustomizer() {

        // Customize embedded Servlet container-related rules
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            container.setPort(8083); }}; }Copy the code

2) Register Servlet three components [Servlet, Filter, Listener]

Because SpringBoot starts the embedded Servlet container as a JAR package by default to start SpringBoot Web applications, there is no web.xml file.

Register the three components in the following way

ServletRegistrationBean

// Register three components
@Bean
public ServletRegistrationBean myServlet(a){
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
    return registrationBean;
}
Copy the code

FilterRegistrationBean

@Bean
public FilterRegistrationBean myFilter(a){
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(new MyFilter());
    registrationBean.setUrlPatterns(Arrays.asList("/hello"."/myServlet"));
    return registrationBean;
}
Copy the code

ServletListenerRegistrationBean

@Bean
public ServletListenerRegistrationBean myListener(a){
    ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
    return registrationBean;
}
Copy the code

SpringBoot automatically registers the front-end controller of SpringMVC when we automate SpringMVC. The DIspatcherServlet;

DispatcherServletAutoConfiguration:

@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public ServletRegistrationBean dispatcherServletRegistration( DispatcherServlet dispatcherServlet) {
   ServletRegistrationBean registration = new ServletRegistrationBean(
         dispatcherServlet, this.serverProperties.getServletMapping());
    // Default interception: / all requests; Package static resources, but do not intercept JSP requests; /* Intercepts JSPS
    Server.servletpath can be used to change the request path intercepted by SpringMVC's front-end controller by default
    
   registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
   registration.setLoadOnStartup(
         this.webMvcProperties.getServlet().getLoadOnStartup());
   if (this.multipartConfig ! =null) {
      registration.setMultipartConfig(this.multipartConfig);
   }
   return registration;
}
Copy the code

2) SpringBoot can support other Servlet containers;

3) Replace with other embedded Servlet containers

Supported by default:

Tomcat (default)

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>The default for introducing web modules is to use embedded Tomcat as the Servlet container;</dependency>
Copy the code

Jetty

<! -- Introducing the web module -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
   <exclusions>
      <exclusion>
         <artifactId>spring-boot-starter-tomcat</artifactId>
         <groupId>org.springframework.boot</groupId>
      </exclusion>
   </exclusions>
</dependency>

<! -- Introducing additional Servlet containers -->
<dependency>
   <artifactId>spring-boot-starter-jetty</artifactId>
   <groupId>org.springframework.boot</groupId>
</dependency>
Copy the code

Undertow

<! -- Introducing the web module -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
   <exclusions>
      <exclusion>
         <artifactId>spring-boot-starter-tomcat</artifactId>
         <groupId>org.springframework.boot</groupId>
      </exclusion>
   </exclusions>
</dependency>

<! -- Introducing additional Servlet containers -->
<dependency>
   <artifactId>spring-boot-starter-undertow</artifactId>
   <groupId>org.springframework.boot</groupId>
</dependency>
Copy the code

4) Principle of automatic configuration of embedded Servlet container;

EmbeddedServletContainerAutoConfiguration: embedded Servlet container configuration automatically?

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
/ / import BeanPostProcessorsRegistrar: Spring annotations; Import some components into the container
/ / import EmbeddedServletContainerCustomizerBeanPostProcessor:
// Post-handler: The bean is initialized before and after the object is created
public class EmbeddedServletContainerAutoConfiguration {
    
    @Configuration
	@ConditionalOnClass({ Servlet.class, Tomcat.class })// Determine whether Tomcat dependencies are currently introduced;
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)/ / determine the current container no user self-defining EmbeddedServletContainerFactory: embedded Servlet container factory. Creates an embedded Servlet container
	public static class EmbeddedTomcat {

		@Bean
		public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory(a) {
			return newTomcatEmbeddedServletContainerFactory(); }}/** * Nested configuration if Jetty is being used. */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedJetty {

		@Bean
		public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory(a) {
			return newJettyEmbeddedServletContainerFactory(); }}/** * Nested configuration if Undertow is being used. */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedUndertow {

		@Bean
		public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory(a) {
			return newUndertowEmbeddedServletContainerFactory(); }}Copy the code

1), EmbeddedServletContainerFactory (embedded Servlet container factory)

public interface EmbeddedServletContainerFactory {

   // Get the embedded Servlet container
   EmbeddedServletContainer getEmbeddedServletContainer( ServletContextInitializer... initializers);

}
Copy the code

2) EmbeddedServletContainer :(EmbeddedServletContainer)

3), TomcatEmbeddedServletContainerFactory, for example

@Override
public EmbeddedServletContainer getEmbeddedServletContainer( ServletContextInitializer... initializers) {
    // Create a Tomcat
   Tomcat tomcat = new Tomcat();
    
    // Configure the basic steps of Tomcat
   File baseDir = (this.baseDirectory ! =null ? this.baseDirectory
         : createTempDir("tomcat"));
   tomcat.setBaseDir(baseDir.getAbsolutePath());
   Connector connector = new Connector(this.protocol);
   tomcat.getService().addConnector(connector);
   customizeConnector(connector);
   tomcat.setConnector(connector);
   tomcat.getHost().setAutoDeploy(false);
   configureEngine(tomcat.getEngine());
   for (Connector additionalConnector : this.additionalTomcatConnectors) {
      tomcat.getService().addConnector(additionalConnector);
   }
   prepareContext(tomcat.getHost(), initializers);
    
    // Pass in the configured Tomcat and return an EmbeddedServletContainer; And start the Tomcat server
   return getTomcatEmbeddedServletContainer(tomcat);
}
Copy the code

4) How do our configuration changes to embedded containers take effect?

ServerProperties, EmbeddedServletContainerCustomizerCopy the code

EmbeddedServletContainerCustomizer: customizer, help us to modify the configuration of the Servlet container?

How to modify the principle?

5), the container import EmbeddedServletContainerCustomizerBeanPostProcessor

// before initialization
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
      throws BeansException {
    / / if the current initialization is a ConfigurableEmbeddedServletContainer type of component
   if (bean instanceof ConfigurableEmbeddedServletContainer) {
       //
      postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
   }
   return bean;
}

private void postProcessBeforeInitialization( ConfigurableEmbeddedServletContainer bean) {
    // Get all the customizers and call each one's customize method to assign attributes to the Servlet container;
    for(EmbeddedServletContainerCustomizer customizer : getCustomizers()) { customizer.customize(bean); }}private Collection<EmbeddedServletContainerCustomizer> getCustomizers(a) {
    if (this.customizers == null) {
        // Look up does not include the parent context
        this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
            this.beanFactory
            / / from the container for all the ge types of components: EmbeddedServletContainerCustomizer
            / / custom Servlet containers, containers can be added to a EmbeddedServletContainerCustomizer types of components
            .getBeansOfType(EmbeddedServletContainerCustomizer.class,
                            false.false)
            .values());
        Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
        this.customizers = Collections.unmodifiableList(this.customizers);
    }
    return this.customizers; } ServerProperties is also a customizerCopy the code

Steps:

1), SpringBoot according to the dependence on import situation, add the corresponding to the container EmbeddedServletContainerFactory TomcatEmbeddedServletContainerFactory 】 【

When a component in the container wants to create an object, it will alert the post-processor; EmbeddedServletContainerCustomizerBeanPostProcessor;

The backend processor works as long as it is an embedded Servlet container factory;

3), rear processor, from the container get all EmbeddedServletContainerCustomizer, call custom custom methods

###5) Embedded Servlet container startup principle;

When do you create an embedded Servlet container factory? When to get the embedded Servlet container and start Tomcat;

Get the embedded Servlet container factory:

1) The SpringBoot application starts and runs the Run method

2), refreshContext (context); SpringBoot flushes the IOC container [create IOC container objects, initialize the container, and create every component in the container]; If it is a web application to create AnnotationConfigEmbeddedWebApplicationContext, otherwise: AnnotationConfigApplicationContext

3), refresh (context); Refresh the ioc container you just created;

public void refresh(a) throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         initMessageSource();

         // Initialize event multicaster for this context.
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         onRefresh();

         // Check for listener beans and register them.
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // Propagate exception to caller.
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...resetCommonCaches(); }}}Copy the code

4), onRefresh (); The Web’s IOC container overrides the onRefresh method

5) The Webioc container creates an embedded Servlet container; createEmbeddedServletContainer();

Get the embedded Servlet container factory:

EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();

Obtained from the ioc container EmbeddedServletContainerFactory components; TomcatEmbeddedServletContainerFactory object creation, post processor is a look at the object, to obtain all of custom custom first Servlet container of related configuration;

Use the container factory to get the embedded Servlet container: this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer());

8) The embedded Servlet container creates objects and starts the Servlet container;

Start the embedded Servlet container first, then fetch the remaining uncreated objects from the IOC container;

The IOC container initiates the creation of an embedded Servlet container

Use an external Servlet container

Embedded Servlet container: Application into executable JARS

Pros: Simple, portable;

Disadvantages: The default does not support JSP, optimization of custom complex (using custom 【 ServerProperties, custom EmbeddedServletContainerCustomizer 】, Write your own embedded Servlet container EmbeddedServletContainerFactory 】 【 create factory);

External Servlet container: Tomcat installed outside – war package packaging;

steps

1) You must create a WAR project; (Use IDEA to create a directory structure)

2) Specify embedded Tomcat as provided;

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-tomcat</artifactId>
   <scope>provided</scope>
</dependency>
Copy the code

3), you must write a SpringBootServletInitializer subclasses, and call the configure method

public class ServletInitializer extends SpringBootServletInitializer {

   @Override
   protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
       // Pass in the main program of the SpringBoot application
      returnapplication.sources(SpringBoot04WebJspApplication.class); }}Copy the code

4) Start the server and it can be used;

The principle of

Jar package: Execute main method of SpringBoot main class, start IOC container, create embedded Servlet container;

War file: start the server, application server startup SpringBoot SpringBootServletInitializer 】 【, start the ioc container;

Servlet3.0 (Spring annotations) :

8.2.4 Shared libraries/runtimes pluggability:

Rules:

1), the server to start (web application) creates the current web application inside each jar package inside ServletContainerInitializer instances:

2), the implementation of ServletContainerInitializer in jars meta-inf/services folder, there is a called javax.mail. Servlet. ServletContainerInitializer file, Content is the implementation class ServletContainerInitializer full name of the class

3) We can also use @handlestypes to load the classes we are interested in when the application starts.

Process:

1) Start Tomcat

2), org \ springframework \ spring – web \ 4.3.14 RELEASE \ spring – web – 4.3.14. The jar! \ meta-inf \ services \ javax.mail servlet. ServletContainerInitializer:

Spring’s web module contains the file: org. Springframework. Web. SpringServletContainerInitializer

3), SpringServletContainerInitializer will @ HandlesTypes (WebApplicationInitializer. Class) of all the types of classes are introduced into the onStartup method Set “class” ? > >; For these WebApplicationInitializer type of class instance is created;

4), every WebApplicationInitializer call their onStartup;

5), the equivalent of our SpringBootServletInitializer class object is created, and perform the onStartup method

6), will perform the onStartup createRootApplicationContext SpringBootServletInitializer instance; Create a container

protected WebApplicationContext createRootApplicationContext( ServletContext servletContext) {
    // create SpringApplicationBuilder
   SpringApplicationBuilder builder = createSpringApplicationBuilder();
   StandardServletEnvironment environment = new StandardServletEnvironment();
   environment.initPropertySources(servletContext, null);
   builder.environment(environment);
   builder.main(getClass());
   ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
   if(parent ! =null) {
      this.logger.info("Root context already created (using as parent).");
      servletContext.setAttribute(
            WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
      builder.initializers(new ParentContextApplicationContextInitializer(parent));
   }
   builder.initializers(
         new ServletContextApplicationContextInitializer(servletContext));
   builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
    
    // Calls the configure method, which subclasses override, passing in the SpringBoot main program class
   builder = configure(builder);
    
    // Use Builder to create a Spring application
   SpringApplication application = builder.build();
   if(application.getSources().isEmpty() && AnnotationUtils .findAnnotation(getClass(), Configuration.class) ! =null) { application.getSources().add(getClass()); } Assert.state(! application.getSources().isEmpty(),"No SpringApplication sources have been defined. Either override the "
               + "configure method or add an @Configuration annotation");
   // Ensure error pages are registered
   if (this.registerErrorPageFilter) {
      application.getSources().add(ErrorPageFilterConfiguration.class);
   }
    // Start the Spring application
   return run(application);
}
Copy the code

7) The Spring application starts and creates the IOC container

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   FailureAnalyzers analyzers = null;
   configureHeadlessProperty();
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.starting();
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
      Banner printedBanner = printBanner(environment);
      context = createApplicationContext();
      analyzers = new FailureAnalyzers(context);
      prepareContext(context, environment, listeners, applicationArguments,
            printedBanner);
       
       // Refresh the IOC container
      refreshContext(context);
      afterRefresh(context, applicationArguments);
      listeners.finished(context, null);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass)
               .logStarted(getApplicationLog(), stopWatch);
      }
      return context;
   }
   catch (Throwable ex) {
      handleRunFailure(context, listeners, analyzers, ex);
      throw newIllegalStateException(ex); }}Copy the code

Start the Servlet container, and then start the SpringBoot application