web development of microservice architecture day04 springboot

Introduction project

  • Put the html page under the templates folder of the template engine, so that you can use the functions of the template engine.

Internationalization of landing page

  • Internationalization: writing internationalization profiles 1. Write an internationalization configuration file and extract the internationalization messages to be displayed on the page 2.SpringBoot automatically configures the components for managing internationalization resource files
    @Bean
    @ConfigurationProperties(
        prefix = "spring.messages"
    )
    public MessageSourceProperties messageSourceProperties() {
        return new MessageSourceProperties();
    }

	@Bean
    public MessageSource messageSource(MessageSourceProperties properties) {
    	/*
    	 * ResourceBoundleMessageSource extends AbstractResourceBasedMessageSource implements BeanClassLoaderAware
    	 * The implementation class allows the user to specify a resource name through beanName: the fully qualified resource name including the classpath
    	 * Or specify a set of resource names through beanName
    	 */
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        if (StringUtils.hasText(properties.getBasename())) {
        /* 
         * setBasenames Set the basic name of the language country code in the internationalization resource file,
         * Internationalization resource files can be placed directly under the classpath called messages properties,
         * You can also specify the base name spring. In the configuration file messages. basename
         */
	    String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");		
	    messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
        }
        if (properties.getEncoding() != null) {
            messageSource.setDefaultEncoding(properties.getEncoding().name());
        }
		/* 
		 * If no locale specific files are found, do you want to return to the system locale
		 * 		The default is true
		 * 		If it is closed, a unique default file will be used: for example, message of "message" of baseName properties
		 */
        messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
        Duration cacheDuration = properties.getCacheDuration();
        if (cacheDuration != null) {
            messageSource.setCacheMillis(cacheDuration.toMillis());
        }
		/*
		 * Set whether the message format component is always applied to parse messages without parameters
		 * 		For example, MessageFormat wants the single quotation mark to be escaped as "",
		 * 			If the message text is written with such escape, this flag needs to be set to true even if there is no parameter placeholder defined
		 * 			Otherwise, only meaningful parameter message text will be written with the escape of MessageFormat
		 */
        messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
        /*
         * Whether to use the message code as the default message instead of throwing NoSuchMessageException,
         * Applicable to development and debugging. The default value is false
         */
        messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
        return messageSource;
    }

MessageSource resolution:

  • MessageSource schema:
  • MessageSource: Abstract message interface
  • Hierarchical MessageSource: a hierarchical message source interface, which can obtain the parent message source
  • MessageSourceSupport: abstract class of message source resolution, which formats messages by specifying "message format component MessageFormat"
  • DelegatingMessageSource: the message source resolves the delegation class When the user does not specify a message source resolution class, SpringContext uses this class by default The function is relatively simple: format the string and parameter array into a message string
  • AbstractMessageSource: an abstract class that supports the internationalization of resources in the form of "configuration file" A public message configuration file independent of regional settings is provided internally, and the message code is keyword
  • StaticMessageSource: mainly used for program testing Allows internationalization information to be provided programmatically
  • ResourceBundleMessageSource: this implementation class allows the user to specify a resource name through beanName, including the fully qualified resource name of the class Or specify a set of resource names through beanName Different regions obtain and load different resource files to achieve the purpose of internationalization
  • ReloadableResourceBundleMessageSource:
    • Differences between ReloadableResourceBundleMessageSource and ResourceBundleMessageSource:
      • Loading resource type and method:
        • ReloadResourceBundleMessageSource relies on Spring's ResourceLoader to load Resource resources, which is more powerful and supports class and properties file
        • ResourceBundleMessageSource loads resources by relying on the ResourceBundle provided by JDK. It supports absolute path and project path class and properties file
      • Cache time:
        • Reloaderesourcebundlemessagesource will record the loading time point of each resource every time it is loaded. After the cache resource expires, the modification time of the file will be compared again. If it does not change, it does not need to be loaded, and the loading time point will be refreshed at the same time
        • ResourceBundleMessageSource mainly uses resourcebundle Control realizes simple automatic loading
      • Coding method:
        • Reloaderesourcebundlemessagesource can not only specify a unified default encoding method, but also support the formulation of an individual encoding method for each file

MessageSource interface: Method description string GetMessage (string code, object [] args, string defaultmessage, locale) gets the message. If the message is not found, the default value string GetMessage (string code, object [] args, locale) throws nosuchmessageexception gets the message. If the message cannot be found, String GetMessage (MessageSourceResolvable, locale) throws nosuchmessageexception attempts to parse the message using all the properties contained in the {@ code MessageSourceResolvable} parameter passed in You must throw {@ code NoSuchMessageException} on this method, because when calling this method, you cannot determine whether the resolvable {@ code defaultMessage} attribute is empty. MessageSourceResolvable resolves the wrapper interface and class of message elements: method description: -: -- String[] getCode() returns the code used to resolve this message, in the order that these codes should try So, The last code will be the default code. Object[] getArguments() returns the parameter array to be used to parse this message. String getDefaultMessage() returns the default message hierarchalmessagesource to be used to parse this message. Message source hierarchical interface: method description: -: -- void setParentMessageSource(MessageSource parent) Sets the parent that will be used to resolve messages that cannot be resolved by secondary objects The parameter parent is the parent MessageSource that will be used to resolve messages that cannot be resolved by this object It may be {@ code null}. In this case, it is not necessary to solve the problem that MessageSource getParentMessageSource() returns the parent of the current MessageSource, Otherwise, {@ code null} messagesourcesupport is returned to support the abstract class of message source parsing: method description: -: -- void setalwaysusemessage format (Boolean alwaysusemessage format) to set whether the message format component is always applied to parse messages without parameters For example: MessageFromat wants the single quotation mark to be escaped as ""“ If the message text is all written with such escape, even if there is no parameter placeholder defined, you only need to set this flag to "true" Otherwise, only the message text with actual parameters will be written with the MessageFormat escape class. boolean isAlwaysUseMessageFormat() returns whether to apply the message format component, Parsing messages without parameters string renderdefaultmessage (string defaultmessage, object [] args, locale) renders the given default message string string string string string FormatMessage (string MSG, object [] args, locale) renders the given message string MessageFormat createmessageformat (string MSG, locale) Create a MessageFormat delegatingmessagesource message source parsing delegation class for the given message and locale: method description: -: -- string GetMessage (string code, object [] args, string defaultmessage, locale) parsing message When the parent message parsing source is not null, the parent message source is used to parse the message Otherwise, use its own message source to parse the message string GetMessage (string code, object [] args, locale) throws nosuchmessageexception to parse the message If the parent message parsing source is not null, the parent message source will be used to parse the message. Otherwise, an exception string GetMessage (messagesourceresolvable, resolvable, locale) throws nosuchmessageexception will be thrown to parse the message If the parent message parsing source is not null, the parent message source is used to parse the message, Otherwise, use its own message source to parse the messageabstractmessagesourc abstract class. The abstract class of internationalizing resources in Spring supports configuration files: method description: -: -- void setUseCodeAsDafaultMessage(boolean useCodeAsDefaultMessage) sets whether to use the message code as the default message instead of throwing NoSuchMessageException The default is false. String getmessageinternal (string code, object [] args, locale) parses the given code and parameters into messages set in the given region, If it is not found, {@ code null} string getmessagefromparent (string code, object [] args, locale) is returned. If there is a message in the parent MessageSource, an attempt is made to retrieve the given message from the parent MessageSource. String getDefaultMessage(String code) returns the default message object [] resolveargements (object [] args, locale) Search through the given parameter array, Find the MessageSourceResolve object and parse the string resolvecodewithoutarguments (string code, locale) parse the message without parameters. StaticMessageSource is an AbstractMessageSource that allows internationalization information to be provided programmatically: method description: -: -- void addmessage (string code, locale, locale, string MSG) Associating a given message with a given code void addmessage (map < string, string > messages, locale) associating a given message with a given code in batches ResourceBundleMessageSource is the implementation class of AbstractMessageSource, allowing users to specify a resource name through beanName - including the fully qualified name of the class path, Or specify a group of resource names through beanNames: method description: -: -- void setBaseName(String basename) set the resource file void setBaseNames(String... basenames) batch set the resource file void setDefaultEncoding(String defaultEncoding) set the default character set for resolving the bound resource file void setFallBackToSystemLocale(boolean fallbackToSystemLocale) whether to return to the system locale if no locale specific files are found The default is true If false, the only alternate file will be the default file void setCacheSeconds(int cacheSeconds). Set the number of seconds to cache and load the bound resource file. String resolvecodewithoutarguments (string code, locale) parses the given message code into the key in the registered resource package and returns the value in the bundle as it is, Do not use MessageFormat to parse MessageFormat resolvecode (string code, locale). Parse the given message code into the key in the registered resource package. Each message code uses the cached MessageFormat instance ResourceBundle getresourcebundle (string baseName, locale) to return a ResourceBundle for the given baseName and code, Extract the generated MessageFormat ResourceBundle dogetbundle (string baseName, locale) throws missingresourceexception from the cache. Get the resource package MessageFormat getmessageformat (ResourceBundle resourcebundle, string code, locale) set by the given baseName and locale Throws missing resourceexception returns a MessageFormat for the given package and code. Extract the generated messageformats string getstringornull (ResourceBundle resourcebundle, string key) from the cache to obtain the value corresponding to the specified key in the resource package. The ReloadableResourceBundleMessageSource implementation class allows the user to specify a resource name through beanName, Including classpath and fully qualified name Or specify a group of resource names through beanNames: method description - string resolvecodewithoutarguments (string code, locale), parse the message code into the key in the retrieved package file, and return the value found in the package as it is, Do not use MessageFormat to parse MessageFormat resolvecode (string code, locale) to parse the given message code into the key in the retrieved package file, Each message code uses the cached MessageFormat instance PropertiesHolder getMergedProperties(Locale locale) to obtain the holding properties object corresponding to the locale list < string > calculateallfilenames (string baseName, locale) to calculate all file names of the given bundle basic name and locale The file name of the given locale will be calculated. The system locale default file list < string > calculatefilenamesforlocale (string basename, locale) calculates the file name of the given bundle infrastructure package name and locale. Properties loadProperties(Resource resource, String filename) resolves the given resource resource, Return the corresponding properties object void clearCache() clear the properties file corresponding to all resource packages void clearcacheincludingprocessors() clear the cache of the current MessageSource and all parent resources

  • MessageFormat message component formatting: mainly formats message strings and parameters into strings

3. Get the internationalization value on the page

In the label body:
th:text="#{}"
th:placeholder="#{}"
Non label body, inline expression
[[#{}]]
  • Internationalization principle: locale (regional information object) in internationalization; Localeresolver (get area information object)
        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnProperty(
            prefix = "spring.mvc",
            name = {"locale"}
        )
        // The default region information parser obtains the Locale according to the region information of the request header for international parsing
        public LocaleResolver localeResolver() {
            if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) {
                return new FixedLocaleResolver(this.mvcProperties.getLocale());
            } else {
                AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
                localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
                return localeResolver;
            }
        }

 		public Locale resolveLocale(HttpServletRequest request) {
        Locale defaultLocale = this.getDefaultLocale();
        if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
            return defaultLocale;
        } else {
            Locale requestLocale = request.getLocale();
            List<Locale> supportedLocales = this.getSupportedLocales();
            if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) {
                Locale supportedLocale = this.findSupportedLocale(request, supportedLocales);
                if (supportedLocale != null) {
                    return supportedLocale;
                } else {
                    return defaultLocale != null ? defaultLocale : requestLocale;
                }
            } else {
                return requestLocale;
            }
        }
    }

Sign in

  • After the template engine is modified during development, it should take effect in real time 1. Disable the template engine cache - spring thymeleaf. cache=false 2. After the page is modified, press ctrl+F9 to recompile
  • Display of login error messages
th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"

Interceptor

  • Login check via interceptor

RESTful

  • Common CRUD: URI, / resource name / resource ID
  • RESTful CRUD: distinguish CRUD operations on resources in the form of HTTP requests

Ordinary CRUD (URI to distinguish operations)

RESTful CRUD

query

getEmp

emp--GET

add to

addEmp?xxx

emp--POST

modify

updateEmp?id=xx&xxx

emp/{id}--PUT

delete

deleteEmp?id=xx

emp/{id}--DELETE

  • give an example:

Request URI

Request mode

Query all employees

emps

GET

Query an employee (go to the modification page)

emp/{id}

GET

Enter the add page

emp

GET

Add employee

emp

POST

Enter the modification page (find out the employee information for echo)

emp/{id}

GET

Modify employee

emp/{id}

PUT

Delete employee

emp/{id}

DELETE

thymeleaf extracts public page elements

  • Extract public segments
<div th:fragment="copy">

</div>
  • Introducing public segments
<div th:insert="~{footer :: copy}"></div>

There are two ways to introduce public fragments:
~{templatename::selector}	Template name::selector
~{templatename::fragmentname}	Template name::Fragment name
 Where template name(The file name of the public clip source)Can use thymeleaf The pre suffix configuration rule of is parsed
  • Introduce the th attribute of the public fragment: 1.th:insert - inserts the entire public fragment into the element introduced by the declaration 2.th:replace - replace the element introduced by the declaration with a public fragment 3.th:include - include the content of the introduced fragment into this tag
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
  • When using the th attribute to introduce a public fragment, you do not need to write ~ {}, but only the inline writing method [[~ {}]], [(~ {})]

List CRUD

C:

  • redirect: indicates redirection to an address / Represents the current project path
  • forward: indicates forwarding to an address
  • Spring MVC automatically binds the request parameters to the properties of the input parameter object one by one The requirement is that the name of the request parameter is consistent with the property name in the object entered by the JavaBean
  • Problem: the submitted data format is incorrect: birthday date = = date format: Spring MVC needs to convert the data submitted by the page to the specified type

U:

  • Request URI and data id are concatenated by + string
  • Page send PUT request: 1. Configure HiddenHttpMethodFilter in spring MVC to modify the page request. SpringBoot has been automatically configured 2. Create a POST form on the page 3. Create an input item, name="_method"; Value is the specified request method

Error handling mechanism

  • SpringBoot's default error handling mechanism 1. When accessing the browser, a default error page will be returned: error status code, error type, error prompt information and error time Request header for browser send request: text html. 2. If it is accessed by other clients, the default json data will be returned Request header of client sending request:/* 3. Principle: refer to ErrorMvcAutoConfiguration The following components are added to the container: 1.DefaultErrorAttributes: share error information on the page
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> errorAttributes = new LinkedHashMap();
        errorAttributes.put("timestamp", new Date());
        this.addStatus(errorAttributes, webRequest);
        this.addErrorDetails(errorAttributes, webRequest, includeStackTrace);
        this.addPath(errorAttributes, webRequest);
        return errorAttributes;
    }

2.BasicErrorController: process the default / error request

@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {
    private final ErrorProperties errorProperties;

    public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
        this(errorAttributes, errorProperties, Collections.emptyList());
    }

    public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
        super(errorAttributes, errorViewResolvers);
        Assert.notNull(errorProperties, "ErrorProperties must not be null");
        this.errorProperties = errorProperties;
    }

    public String getErrorPath() {
        return this.errorProperties.getPath();
    }

    @RequestMapping(
        produces = {"text/html"}
    )	
    //Generate html data and process the request sent by the browser
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = this.getStatus(request);
        Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        // Which page to go to as the error page, including the page address and page content
        ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
        return modelAndView != null ? modelAndView : new ModelAndView("error", model);
    }

    @RequestMapping	//Generate json data and process other client requests
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = this.getStatus(request);
        return new ResponseEntity(body, status);
    }

3.ErrorPageCustomizer: if the system has errors beginning with 4 and 5, the component will take effect and customize the error response rules You will come to the / error request

	@Value("${error.path:/error}")
    private String path = "/error";	//When an error occurs in the system, it comes to the error request for processing

4.DefaultErrorViewResolver:

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

        return modelAndView;
    }

    private ModelAndView resolve(String viewName, Map<String, Object> model) {
    	// By default, SpringBoot can find the page - error/404
        String errorViewName = "error/" + viewName;
        // If the template engine can resolve the page address, use the template engine to resolve it
        TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
        // If the template engine is available, return to the view address specified by errorViewName; If the template engine is not available, find the page corresponding to errorvicename in the static resource folder If there is no corresponding page in the static resource folder, null is returned
        return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
    }

Error handling steps:

  • If the system has errors beginning with 4 and 5, the component will take effect and customize the error response rules The / error request will come and be processed by the BasicErrorController
  • Response page: which page is parsed by the DefaultErrorViewResolver
 protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
        Iterator var5 = this.errorViewResolvers.iterator();

        ModelAndView modelAndView;
        do {
            if (!var5.hasNext()) {
                return null;
            }

            ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
            modelAndView = resolver.resolveErrorView(request, status, model);
        } while(modelAndView == null);

        return modelAndView;
    }
  • How to customize error response
    • How to customize the error page
      • Template engine in some cases: 1.error / error status code. As long as the error page is named "error status code. html" and placed in the error folder in the template engine folder, the error with this status code will come to the corresponding page 2. 4xx and 5xx can be used as the file name of the error page to match all errors of this type - precision first, that is, to find the precise error status code first html 3. What information can be obtained from the page:
        • timstamp: timestamp
        • Status: status code
        • Error: error prompt
        • Exception: exception object
        • Message: exception message
        • errors: JSR303 data verification error
      • If the template engine does not: 1. The template engine cannot find the error page, so it can find it under the static resource folder
      • If there is no template engine and no static resource folder: 1. By default, you will come to the error prompt page of SpringBoot
    • How to customize wrong json data: 1. Customize exception handling and return customized json data
@ControllerAdvice
public class MyExceptionHandler {	//No adaptive effect - both browser and client return json data
    @ResponseBody
    @ExceptionHandler(RuntimeException.class)
    public Map<String,Object> handleException(Exception e){
        Map<String,Object> map=new HashMap<>();
        map.put("code","Abnormal operation");
        map.put("message",e.getMessage());
        return map;

    }
}

2. Forward to forward:/error for adaptive response effect processing

@ControllerAdvice
public class MyExceptionHandler {
    @ExceptionHandler(RuntimeException.class)
    public String handleException(Exception e, HttpServletRequest request){
        Map<String,Object> map=new HashMap<>();
        // Pass in your own error status code, otherwise you will not enter the parsing process of customized error page ---------- integer statuscode = (integer) request getAttribute("javax.servlet.error.status_code");
        request.setAttribute("javax.servlet.error.status_code","500");
        map.put("code","Abnormal operation");
        map.put("message",e.getMessage());
        //Forward to / error for adaptive effect
        return "forward:/error";

    }
}

3. Carry out customized data: after an error occurs, a / error request will be sent. This request will be processed by BasicErrorController, and the response data is obtained by geterrorattributes (the method specified by AbstractErrorController(ErrorController))

  • You can write a subclass implementation class that inherits AbstractErrorController and put it in the container
  • The data available on the page and the data returned on json are all through errorattributes Geterrorattributes, that is, defaulterrorattributes in the container Geterrorattributes() for data processing
  • The response is adaptive, and the content to be returned can be changed by customizing ErrorAtrributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
    //The return value map is all the fields that the page and json can get
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> map=super.getErrorAttributes(webRequest, includeStackTrace);
        map.put("company","oxford");
        //Data carried by exception handler
        Map<String,Object> ext=(Map<String, Object>) webRequest.getAttribute("ext",0);
        map.put("ext",ext);
        return map;
    }
}

Added by k994519 on Sat, 22 Jan 2022 05:41:33 +0200